diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2006-11-06 18:07:30 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2006-11-06 18:07:30 +0000 |
commit | 0f5cb94aa4a334366a746fcbb22f3335ca413265 (patch) | |
tree | 8f89a96628c1810d51ee9816daf78edb8c76fcd4 /firmware | |
parent | 0b22795e26ee09de14f6ac23219adeda12f2fd5b (diff) | |
download | rockbox-0f5cb94aa4a334366a746fcbb22f3335ca413265.tar.gz rockbox-0f5cb94aa4a334366a746fcbb22f3335ca413265.zip |
Big Patch adds primarily: Samplerate and format selection to recording for SWCODEC. Supprort for samplerates changing in playback (just goes with the recording part inseparably). Samplerates to all encoders. Encoders can be configured individually on a menu specific to the encoder in the recording menu. File creation is delayed until flush time to reduce spinups when splitting. Misc: statusbar icons for numbers are individual digits to display any number. Audio buffer was rearranged to maximize memory available to recording and properly reinitialized when trashed. ColdFire PCM stuff moved to target tree to avoid a complicated mess when adding samplerate switching. Some needed API changes and to neaten up growing gap between hardware and software codecs.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11452 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/SOURCES | 26 | ||||
-rw-r--r-- | firmware/drivers/tlv320.c | 45 | ||||
-rw-r--r-- | firmware/drivers/uda1380.c | 84 | ||||
-rw-r--r-- | firmware/export/audio.h | 106 | ||||
-rw-r--r-- | firmware/export/config-h100.h | 6 | ||||
-rw-r--r-- | firmware/export/config-h120.h | 6 | ||||
-rw-r--r-- | firmware/export/config-h300.h | 7 | ||||
-rw-r--r-- | firmware/export/config-iaudiox5.h | 6 | ||||
-rw-r--r-- | firmware/export/id3.h | 91 | ||||
-rw-r--r-- | firmware/export/pcm_playback.h | 16 | ||||
-rw-r--r-- | firmware/export/pcm_record.h | 46 | ||||
-rw-r--r-- | firmware/export/system.h | 81 | ||||
-rw-r--r-- | firmware/export/thread.h | 3 | ||||
-rw-r--r-- | firmware/export/tlv320.h | 10 | ||||
-rw-r--r-- | firmware/export/uda1380.h | 13 | ||||
-rw-r--r-- | firmware/id3.c | 138 | ||||
-rw-r--r-- | firmware/mpeg.c | 20 | ||||
-rw-r--r-- | firmware/pcm_playback.c | 700 | ||||
-rw-r--r-- | firmware/pcm_record.c | 2002 | ||||
-rw-r--r-- | firmware/system.c | 3 | ||||
-rw-r--r-- | firmware/target/coldfire/iaudio/x5/system-x5.c | 7 | ||||
-rw-r--r-- | firmware/target/coldfire/iriver/system-iriver.c | 7 | ||||
-rw-r--r-- | firmware/target/coldfire/system-coldfire.c | 7 | ||||
-rw-r--r-- | firmware/target/coldfire/system-target.h | 29 | ||||
-rw-r--r-- | firmware/thread.c | 8 |
25 files changed, 2053 insertions, 1414 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index 1ec3c82616..df38169be3 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -4,6 +4,7 @@ logf.c | |||
4 | #endif | 4 | #endif |
5 | backlight.c | 5 | backlight.c |
6 | buffer.c | 6 | buffer.c |
7 | general.c | ||
7 | common/atoi.c | 8 | common/atoi.c |
8 | common/crc32.c | 9 | common/crc32.c |
9 | common/ctype.c | 10 | common/ctype.c |
@@ -45,7 +46,12 @@ target/coldfire/memcpy-coldfire.S | |||
45 | target/coldfire/memmove-coldfire.S | 46 | target/coldfire/memmove-coldfire.S |
46 | target/coldfire/memset-coldfire.S | 47 | target/coldfire/memset-coldfire.S |
47 | target/coldfire/memset16-coldfire.S | 48 | target/coldfire/memset16-coldfire.S |
49 | #ifndef SIMULATOR | ||
50 | #ifndef BOOTLOADER | ||
51 | target/coldfire/pcm-coldfire.c | ||
52 | #endif | ||
48 | target/coldfire/system-coldfire.c | 53 | target/coldfire/system-coldfire.c |
54 | #endif | ||
49 | #elif (CONFIG_CPU == SH7034) | 55 | #elif (CONFIG_CPU == SH7034) |
50 | target/sh/memcpy-sh.S | 56 | target/sh/memcpy-sh.S |
51 | target/sh/memmove-sh.S | 57 | target/sh/memmove-sh.S |
@@ -207,15 +213,21 @@ drivers/wm8731l.c | |||
207 | #elif defined(HAVE_TLV320) && !defined(SIMULATOR) | 213 | #elif defined(HAVE_TLV320) && !defined(SIMULATOR) |
208 | drivers/tlv320.c | 214 | drivers/tlv320.c |
209 | #endif | 215 | #endif |
210 | #if (CONFIG_CODEC == SWCODEC) && !defined(SIMULATOR) | 216 | #if (CONFIG_CODEC == SWCODEC) && !defined(BOOTLOADER) |
211 | pcm_playback.c | 217 | pcm_sampr.c |
212 | #endif | ||
213 | #if CONFIG_CODEC == SWCODEC | ||
214 | replaygain.c | 218 | replaygain.c |
215 | #endif | 219 | #ifndef SIMULATOR |
216 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) | 220 | pcm_playback.c |
221 | #endif /* SIMULATOR */ | ||
222 | #ifdef HAVE_RECORDING | ||
223 | enc_base.c | ||
224 | #if defined(CPU_COLDFIRE) | ||
225 | #ifndef SIMULATOR | ||
217 | pcm_record.c | 226 | pcm_record.c |
218 | #endif | 227 | #endif /* SIMULATOR */ |
228 | #endif /* CPU_COLDFIRE */ | ||
229 | #endif /* HAVE_RECORDING */ | ||
230 | #endif /* SWCODEC && !BOOTLOADER */ | ||
219 | sound.c | 231 | sound.c |
220 | #if defined(IRIVER_IFP7XX_SERIES) && defined(STUB) | 232 | #if defined(IRIVER_IFP7XX_SERIES) && defined(STUB) |
221 | common/sscanf.c | 233 | common/sscanf.c |
diff --git a/firmware/drivers/tlv320.c b/firmware/drivers/tlv320.c index abce31ef81..7c4bbbd1ee 100644 --- a/firmware/drivers/tlv320.c +++ b/firmware/drivers/tlv320.c | |||
@@ -82,7 +82,7 @@ void tlv320_init(void) | |||
82 | tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ | 82 | tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ |
83 | tlv320_write_reg(REG_DAIF, DAIF_IWL_16 | DAIF_FOR_I2S); | 83 | tlv320_write_reg(REG_DAIF, DAIF_IWL_16 | DAIF_FOR_I2S); |
84 | tlv320_write_reg(REG_DIA, DIA_ACT); | 84 | tlv320_write_reg(REG_DIA, DIA_ACT); |
85 | tlv320_write_reg(REG_SRC, (1 << 5)); /* 44.1kHz */ | 85 | tlv320_set_frequency(-1); /* default */ |
86 | /* All ON except ADC, MIC and LINE */ | 86 | /* All ON except ADC, MIC and LINE */ |
87 | tlv320_write_reg(REG_PC, PC_ADC | PC_MIC | PC_LINE); | 87 | tlv320_write_reg(REG_PC, PC_ADC | PC_MIC | PC_LINE); |
88 | } | 88 | } |
@@ -96,6 +96,32 @@ void tlv320_reset(void) | |||
96 | } | 96 | } |
97 | 97 | ||
98 | /** | 98 | /** |
99 | * Sets internal sample rate for DAC and ADC relative to MCLK | ||
100 | * Selection for frequency: | ||
101 | * Fs: tlv: with: | ||
102 | * 11025: 0 = MCLK/2 MCLK/2 SCLK, LRCK: Audio Clk / 16 | ||
103 | * 22050: 0 = MCLK/2 MCLK SCLK, LRCK: Audio Clk / 8 | ||
104 | * 44100: 1 = MCLK MCLK SCLK, LRCK: Audio Clk / 4 (default) | ||
105 | * 88200: 2 = MCLK*2 MCLK SCLK, LRCK: Audio Clk / 2 | ||
106 | */ | ||
107 | void tlv320_set_frequency(unsigned fsel) | ||
108 | { | ||
109 | /* All rates available for 11.2896MHz besides 8.021 */ | ||
110 | unsigned char values_src[3] = | ||
111 | { | ||
112 | /* Fs: */ | ||
113 | (0x8 << 2) | SRC_CLKIN, /* 11025, 22050 */ | ||
114 | (0x8 << 2), /* 44100 */ | ||
115 | (0xf << 2), /* 88200 */ | ||
116 | }; | ||
117 | |||
118 | if (fsel >= ARRAYLEN(values_src)) | ||
119 | fsel = 1; | ||
120 | |||
121 | tlv320_write_reg(REG_SRC, values_src[fsel]); | ||
122 | } | ||
123 | |||
124 | /** | ||
99 | * Sets left and right headphone volume | 125 | * Sets left and right headphone volume |
100 | * | 126 | * |
101 | * Left & Right: 48 .. 121 .. 127 => Volume -73dB (mute) .. +0 dB .. +6 dB | 127 | * Left & Right: 48 .. 121 .. 127 => Volume -73dB (mute) .. +0 dB .. +6 dB |
@@ -142,7 +168,6 @@ void tlv320_set_recvol(int left, int right, int type) | |||
142 | value_aap &= ~AAP_MICB; | 168 | value_aap &= ~AAP_MICB; |
143 | 169 | ||
144 | tlv320_write_reg(REG_AAP, value_aap); | 170 | tlv320_write_reg(REG_AAP, value_aap); |
145 | |||
146 | } | 171 | } |
147 | else if (type == AUDIO_GAIN_LINEIN) | 172 | else if (type == AUDIO_GAIN_LINEIN) |
148 | { | 173 | { |
@@ -180,15 +205,17 @@ void tlv320_mute(bool mute) | |||
180 | } | 205 | } |
181 | 206 | ||
182 | /* Nice shutdown of TLV320 codec */ | 207 | /* Nice shutdown of TLV320 codec */ |
183 | void tlv320_close() | 208 | void tlv320_close(void) |
184 | { | 209 | { |
210 | tlv320_mute(true); | ||
211 | sleep(HZ/8); | ||
212 | |||
185 | tlv320_write_reg(REG_PC, PC_OFF | PC_CLK | PC_OSC | PC_OUT | | 213 | tlv320_write_reg(REG_PC, PC_OFF | PC_CLK | PC_OSC | PC_OUT | |
186 | PC_DAC | PC_ADC | PC_MIC | PC_LINE); /* All OFF */ | 214 | PC_DAC | PC_ADC | PC_MIC | PC_LINE); /* All OFF */ |
187 | } | 215 | } |
188 | 216 | ||
189 | void tlv320_enable_recording(bool source_mic) | 217 | void tlv320_enable_recording(bool source_mic) |
190 | { | 218 | { |
191 | unsigned value_daif = tlv320_regs[REG_DAIF]; | ||
192 | unsigned value_aap, value_pc; | 219 | unsigned value_aap, value_pc; |
193 | 220 | ||
194 | if (source_mic) | 221 | if (source_mic) |
@@ -205,20 +232,12 @@ void tlv320_enable_recording(bool source_mic) | |||
205 | 232 | ||
206 | tlv320_write_reg(REG_PC, value_pc); | 233 | tlv320_write_reg(REG_PC, value_pc); |
207 | tlv320_write_reg(REG_AAP, value_aap); | 234 | tlv320_write_reg(REG_AAP, value_aap); |
208 | |||
209 | /* Enable MASTER mode (start sending I2S data to the CPU) */ | ||
210 | value_daif |= DAIF_MS; | ||
211 | tlv320_write_reg(REG_DAIF, value_daif); | ||
212 | } | 235 | } |
213 | 236 | ||
214 | void tlv320_disable_recording() | 237 | void tlv320_disable_recording(void) |
215 | { | 238 | { |
216 | unsigned value_pc = tlv320_regs[REG_PC]; | 239 | unsigned value_pc = tlv320_regs[REG_PC]; |
217 | unsigned value_aap = tlv320_regs[REG_AAP]; | 240 | unsigned value_aap = tlv320_regs[REG_AAP]; |
218 | unsigned value_daif = tlv320_regs[REG_DAIF]; | ||
219 | |||
220 | value_daif &= ~DAIF_MS; /* disable MASTER mode */ | ||
221 | tlv320_write_reg(REG_DAIF, value_daif); | ||
222 | 241 | ||
223 | value_aap |= AAP_MICM; /* mute MIC */ | 242 | value_aap |= AAP_MICM; /* mute MIC */ |
224 | tlv320_write_reg(REG_PC, value_aap); | 243 | tlv320_write_reg(REG_PC, value_aap); |
diff --git a/firmware/drivers/uda1380.c b/firmware/drivers/uda1380.c index 241a117385..d6dfe6623b 100644 --- a/firmware/drivers/uda1380.c +++ b/firmware/drivers/uda1380.c | |||
@@ -49,9 +49,10 @@ short recgain_line; | |||
49 | #define NUM_DEFAULT_REGS 13 | 49 | #define NUM_DEFAULT_REGS 13 |
50 | unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = | 50 | unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = |
51 | { | 51 | { |
52 | REG_0, EN_DAC | EN_INT | EN_DEC | SYSCLK_256FS | WSPLL_25_50, | 52 | REG_0, EN_DAC | EN_INT | EN_DEC | ADC_CLK | DAC_CLK | |
53 | SYSCLK_256FS | WSPLL_25_50, | ||
53 | REG_I2S, I2S_IFMT_IIS, | 54 | REG_I2S, I2S_IFMT_IIS, |
54 | REG_PWR, PON_BIAS, | 55 | REG_PWR, PON_PLL | PON_BIAS, |
55 | /* PON_HP & PON_DAC is enabled later */ | 56 | /* PON_HP & PON_DAC is enabled later */ |
56 | REG_AMIX, AMIX_RIGHT(0x3f) | AMIX_LEFT(0x3f), | 57 | REG_AMIX, AMIX_RIGHT(0x3f) | AMIX_LEFT(0x3f), |
57 | /* 00=max, 3f=mute */ | 58 | /* 00=max, 3f=mute */ |
@@ -60,7 +61,7 @@ unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = | |||
60 | REG_MIX_VOL, MIX_VOL_CH_1(0) | MIX_VOL_CH_2(0xff), | 61 | REG_MIX_VOL, MIX_VOL_CH_1(0) | MIX_VOL_CH_2(0xff), |
61 | /* 00=max, ff=mute */ | 62 | /* 00=max, ff=mute */ |
62 | REG_EQ, EQ_MODE_MAX, | 63 | REG_EQ, EQ_MODE_MAX, |
63 | /* Bass and tremble = 0 dB */ | 64 | /* Bass and treble = 0 dB */ |
64 | REG_MUTE, MUTE_MASTER | MUTE_CH2, | 65 | REG_MUTE, MUTE_MASTER | MUTE_CH2, |
65 | /* Mute everything to start with */ | 66 | /* Mute everything to start with */ |
66 | REG_MIX_CTL, MIX_CTL_MIX, | 67 | REG_MIX_CTL, MIX_CTL_MIX, |
@@ -192,6 +193,43 @@ void uda1380_reset(void) | |||
192 | #endif | 193 | #endif |
193 | } | 194 | } |
194 | 195 | ||
196 | /** | ||
197 | * Sets frequency settings for DAC and ADC relative to MCLK | ||
198 | * | ||
199 | * Selection for frequency ranges: | ||
200 | * Fs: range: with: | ||
201 | * 11025: 0 = 6.25 to 12.5 MCLK/2 SCLK, LRCK: Audio Clk / 16 | ||
202 | * 22050: 1 = 12.5 to 25 MCLK/2 SCLK, LRCK: Audio Clk / 8 | ||
203 | * 44100: 2 = 25 to 50 MCLK SCLK, LRCK: Audio Clk / 4 (default) | ||
204 | * 88200: 3 = 50 to 100 MCLK SCLK, LRCK: Audio Clk / 2 <= TODO: Needs WSPLL | ||
205 | */ | ||
206 | void uda1380_set_frequency(unsigned fsel) | ||
207 | { | ||
208 | static const unsigned short values_reg[4][2] = | ||
209 | { | ||
210 | /* Fs: */ | ||
211 | { 0, WSPLL_625_125 | SYSCLK_512FS }, /* 11025 */ | ||
212 | { 0, WSPLL_125_25 | SYSCLK_256FS }, /* 22050 */ | ||
213 | { MIX_CTL_SEL_NS, WSPLL_25_50 | SYSCLK_256FS }, /* 44100 */ | ||
214 | { MIX_CTL_SEL_NS, WSPLL_50_100 | SYSCLK_256FS }, /* 88200 */ | ||
215 | }; | ||
216 | |||
217 | const unsigned short *ent; | ||
218 | |||
219 | if (fsel >= ARRAYLEN(values_reg)) | ||
220 | fsel = 2; | ||
221 | |||
222 | ent = values_reg[fsel]; | ||
223 | |||
224 | /* Set WSPLL input frequency range or SYSCLK divider */ | ||
225 | uda1380_regs[REG_0] &= ~0xf; | ||
226 | uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ent[1]); | ||
227 | |||
228 | /* Choose 3rd order or 5th order noise shaper */ | ||
229 | uda1380_regs[REG_MIX_CTL] &= ~MIX_CTL_SEL_NS; | ||
230 | uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] | ent[0]); | ||
231 | } | ||
232 | |||
195 | /* Initialize UDA1380 codec with default register values (uda1380_defaults) */ | 233 | /* Initialize UDA1380 codec with default register values (uda1380_defaults) */ |
196 | int uda1380_init(void) | 234 | int uda1380_init(void) |
197 | { | 235 | { |
@@ -227,30 +265,34 @@ void uda1380_close(void) | |||
227 | */ | 265 | */ |
228 | void uda1380_enable_recording(bool source_mic) | 266 | void uda1380_enable_recording(bool source_mic) |
229 | { | 267 | { |
268 | uda1380_regs[REG_0] &= ~(ADC_CLK | DAC_CLK); | ||
230 | uda1380_write_reg(REG_0, uda1380_regs[REG_0] | EN_ADC); | 269 | uda1380_write_reg(REG_0, uda1380_regs[REG_0] | EN_ADC); |
231 | 270 | ||
232 | if (source_mic) | 271 | if (source_mic) |
233 | { | 272 | { |
234 | /* VGA_GAIN: 0=0 dB, F=30dB */ | 273 | /* VGA_GAIN: 0=0 dB, F=30dB */ |
274 | /* Output of left ADC is fed into right bitstream */ | ||
275 | uda1380_regs[REG_PWR] &= ~(PON_PLL | PON_PGAR | PON_ADCR); | ||
235 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_LNA | PON_ADCL); | 276 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_LNA | PON_ADCL); |
277 | uda1380_regs[REG_ADC] &= ~SKIP_DCFIL; | ||
236 | uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & VGA_GAIN_MASK) | 278 | uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & VGA_GAIN_MASK) |
237 | | SEL_LNA | SEL_MIC | EN_DCFIL); | 279 | | SEL_LNA | SEL_MIC | EN_DCFIL); |
238 | uda1380_write_reg(REG_PGA, 0); | 280 | uda1380_write_reg(REG_PGA, 0); |
239 | } else | 281 | } |
282 | else | ||
240 | { | 283 | { |
241 | /* PGA_GAIN: 0=0 dB, F=24dB */ | 284 | /* PGA_GAIN: 0=0 dB, F=24dB */ |
285 | uda1380_regs[REG_PWR] &= ~(PON_PLL | PON_LNA); | ||
242 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PGAL | PON_ADCL | 286 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PGAL | PON_ADCL |
243 | | PON_PGAR | PON_ADCR); | 287 | | PON_PGAR | PON_ADCR); |
244 | uda1380_write_reg(REG_ADC, EN_DCFIL); | 288 | uda1380_write_reg(REG_ADC, EN_DCFIL); |
245 | uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & PGA_GAIN_MASK) | 289 | uda1380_write_reg(REG_PGA, uda1380_regs[REG_PGA] & PGA_GAIN_MASK); |
246 | | PGA_GAINL(0) | PGA_GAINR(0)); | ||
247 | } | 290 | } |
248 | 291 | ||
249 | sleep(HZ/8); | 292 | sleep(HZ/8); |
250 | 293 | ||
251 | uda1380_write_reg(REG_I2S, uda1380_regs[REG_I2S] | I2S_MODE_MASTER); | 294 | uda1380_write_reg(REG_I2S, uda1380_regs[REG_I2S] | I2S_MODE_MASTER); |
252 | uda1380_write_reg(REG_MIX_CTL, MIX_MODE(1)); | 295 | uda1380_write_reg(REG_MIX_CTL, MIX_MODE(1)); |
253 | |||
254 | } | 296 | } |
255 | 297 | ||
256 | /** | 298 | /** |
@@ -262,10 +304,13 @@ void uda1380_disable_recording(void) | |||
262 | sleep(HZ/8); | 304 | sleep(HZ/8); |
263 | 305 | ||
264 | uda1380_write_reg(REG_I2S, I2S_IFMT_IIS); | 306 | uda1380_write_reg(REG_I2S, I2S_IFMT_IIS); |
265 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] & ~(PON_LNA | PON_ADCL | 307 | |
266 | | PON_ADCR | PON_PGAL | 308 | uda1380_regs[REG_PWR] &= ~(PON_LNA | PON_ADCL | PON_ADCR | PON_PGAL | PON_PGAR); |
267 | | PON_PGAR)); | 309 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PLL); |
268 | uda1380_write_reg(REG_0, uda1380_regs[REG_0] & ~EN_ADC); | 310 | |
311 | uda1380_regs[REG_0] &= ~EN_ADC; | ||
312 | uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ADC_CLK | DAC_CLK); | ||
313 | |||
269 | uda1380_write_reg(REG_ADC, SKIP_DCFIL); | 314 | uda1380_write_reg(REG_ADC, SKIP_DCFIL); |
270 | } | 315 | } |
271 | 316 | ||
@@ -373,20 +418,3 @@ void uda1380_set_monitor(int enable) | |||
373 | else /* mute channel 2 */ | 418 | else /* mute channel 2 */ |
374 | uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] | MUTE_CH2); | 419 | uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] | MUTE_CH2); |
375 | } | 420 | } |
376 | |||
377 | /* Change the order of the noise chaper, | ||
378 | 5th order is recommended above 32kHz */ | ||
379 | void uda1380_set_nsorder(int order) | ||
380 | { | ||
381 | switch(order) | ||
382 | { | ||
383 | case 5: | ||
384 | uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] | ||
385 | | MIX_CTL_SEL_NS); | ||
386 | break; | ||
387 | case 3: | ||
388 | default: | ||
389 | uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] | ||
390 | & ~MIX_CTL_SEL_NS); | ||
391 | } | ||
392 | } | ||
diff --git a/firmware/export/audio.h b/firmware/export/audio.h index 9099cb3765..d3f544de94 100644 --- a/firmware/export/audio.h +++ b/firmware/export/audio.h | |||
@@ -20,6 +20,20 @@ | |||
20 | #define AUDIO_H | 20 | #define AUDIO_H |
21 | 21 | ||
22 | #include <stdbool.h> | 22 | #include <stdbool.h> |
23 | #include <sys/types.h> | ||
24 | /* These must always be included with audio.h for this to compile under | ||
25 | cetain conditions. Do it here or else spread the complication around to | ||
26 | many files. */ | ||
27 | #if CONFIG_CODEC == SWCODEC | ||
28 | #include "pcm_sampr.h" | ||
29 | #include "pcm_playback.h" | ||
30 | #ifdef HAVE_RECORDING | ||
31 | #include "pcm_record.h" | ||
32 | #include "id3.h" | ||
33 | #include "enc_base.h" | ||
34 | #endif /* HAVE_RECORDING */ | ||
35 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
36 | |||
23 | 37 | ||
24 | #ifdef SIMULATOR | 38 | #ifdef SIMULATOR |
25 | #define audio_play(x) sim_audio_play(x) | 39 | #define audio_play(x) sim_audio_play(x) |
@@ -31,9 +45,6 @@ | |||
31 | #define AUDIO_STATUS_PRERECORD 8 | 45 | #define AUDIO_STATUS_PRERECORD 8 |
32 | #define AUDIO_STATUS_ERROR 16 | 46 | #define AUDIO_STATUS_ERROR 16 |
33 | 47 | ||
34 | #define AUDIO_STATUS_STAYON_FLAGS \ | ||
35 | (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE | AUDIO_STATUS_RECORD | AUDIO_) | ||
36 | |||
37 | #define AUDIOERR_DISK_FULL 1 | 48 | #define AUDIOERR_DISK_FULL 1 |
38 | 49 | ||
39 | #define AUDIO_GAIN_LINEIN 0 | 50 | #define AUDIO_GAIN_LINEIN 0 |
@@ -72,10 +83,11 @@ void audio_resume(void); | |||
72 | void audio_next(void); | 83 | void audio_next(void); |
73 | void audio_prev(void); | 84 | void audio_prev(void); |
74 | int audio_status(void); | 85 | int audio_status(void); |
75 | bool audio_query_poweroff(void); | 86 | #if CONFIG_CODEC == SWCODEC |
76 | int audio_track_count(void); /* SWCODEC only */ | 87 | int audio_track_count(void); /* SWCODEC only */ |
77 | long audio_filebufused(void); /* SWCODEC only */ | 88 | long audio_filebufused(void); /* SWCODEC only */ |
78 | void audio_pre_ff_rewind(void); /* SWCODEC only */ | 89 | void audio_pre_ff_rewind(void); /* SWCODEC only */ |
90 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
79 | void audio_ff_rewind(long newtime); | 91 | void audio_ff_rewind(long newtime); |
80 | void audio_flush_and_reload_tracks(void); | 92 | void audio_flush_and_reload_tracks(void); |
81 | struct mp3entry* audio_current_track(void); | 93 | struct mp3entry* audio_current_track(void); |
@@ -89,18 +101,28 @@ void audio_error_clear(void); | |||
89 | int audio_get_file_pos(void); | 101 | int audio_get_file_pos(void); |
90 | void audio_beep(int duration); | 102 | void audio_beep(int duration); |
91 | void audio_init_playback(void); | 103 | void audio_init_playback(void); |
104 | unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size); | ||
92 | 105 | ||
93 | /* audio recording functions */ | 106 | /* channel modes */ |
94 | void audio_init_recording(unsigned int buffer_offset); | 107 | enum rec_channel_modes |
95 | void audio_close_recording(void); | 108 | { |
96 | void audio_record(const char *filename); | 109 | __CHN_MODE_START_INDEX = -1, |
97 | void audio_stop_recording(void); | 110 | |
98 | void audio_pause_recording(void); | 111 | CHN_MODE_STEREO, |
99 | void audio_resume_recording(void); | 112 | CHN_MODE_MONO, |
100 | void audio_new_file(const char *filename); | 113 | |
114 | CHN_NUM_MODES | ||
115 | }; | ||
116 | |||
117 | #if CONFIG_CODEC == SWCODEC | ||
118 | /* channel mode capability bits */ | ||
119 | #define CHN_CAP_STEREO (1 << CHN_MODE_STEREO) | ||
120 | #define CHN_CAP_MONO (1 << CHN_MODE_MONO) | ||
121 | #define CHN_CAP_ALL (CHN_CAP_STEREO | CHN_CAP_MONO) | ||
122 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
101 | 123 | ||
102 | /* audio sources */ | 124 | /* audio sources */ |
103 | enum | 125 | enum audio_sources |
104 | { | 126 | { |
105 | AUDIO_SRC_PLAYBACK = -1, /* for audio playback (default) */ | 127 | AUDIO_SRC_PLAYBACK = -1, /* for audio playback (default) */ |
106 | AUDIO_SRC_MIC, /* monitor mic */ | 128 | AUDIO_SRC_MIC, /* monitor mic */ |
@@ -123,33 +145,57 @@ enum | |||
123 | AUDIO_SRC_MAX = AUDIO_NUM_SOURCES-1 | 145 | AUDIO_SRC_MAX = AUDIO_NUM_SOURCES-1 |
124 | }; | 146 | }; |
125 | 147 | ||
126 | /* channel modes */ | 148 | #ifdef HAVE_RECORDING |
127 | enum | 149 | /* parameters for audio_set_recording_options */ |
150 | struct audio_recording_options | ||
128 | { | 151 | { |
129 | CHN_MODE_MONO = 1, | 152 | int rec_source; |
130 | CHN_MODE_STEREO, | 153 | int rec_frequency; |
154 | int rec_channels; | ||
155 | int rec_prerecord_time; | ||
156 | #if CONFIG_CODEC == SWCODEC | ||
157 | int rec_source_flags; /* for rec_set_source */ | ||
158 | struct encoder_config enc_config; | ||
159 | #else | ||
160 | int rec_quality; | ||
161 | bool rec_editable; | ||
162 | #endif | ||
131 | }; | 163 | }; |
132 | void audio_set_recording_options(int frequency, int quality, | 164 | |
133 | int source, int channel_mode, | 165 | /* audio recording functions */ |
134 | bool editable, int prerecord_time); | 166 | void audio_init_recording(unsigned int buffer_offset); |
167 | void audio_close_recording(void); | ||
168 | void audio_record(const char *filename); | ||
169 | void audio_stop_recording(void); | ||
170 | void audio_pause_recording(void); | ||
171 | void audio_resume_recording(void); | ||
172 | void audio_new_file(const char *filename); | ||
173 | void audio_set_recording_options(struct audio_recording_options *options); | ||
135 | void audio_set_recording_gain(int left, int right, int type); | 174 | void audio_set_recording_gain(int left, int right, int type); |
136 | unsigned long audio_recorded_time(void); | 175 | unsigned long audio_recorded_time(void); |
137 | unsigned long audio_num_recorded_bytes(void); | 176 | unsigned long audio_num_recorded_bytes(void); |
138 | #if 0 | 177 | |
139 | #ifdef HAVE_SPDIF_POWER | ||
140 | void audio_set_spdif_power_setting(bool on); | ||
141 | #endif | ||
142 | #endif | ||
143 | unsigned long audio_get_spdif_sample_rate(void); | ||
144 | unsigned long audio_prev_elapsed(void); | ||
145 | #if CONFIG_CODEC == SWCODEC | 178 | #if CONFIG_CODEC == SWCODEC |
146 | /* audio encoder functions (defined in playback.c) */ | 179 | /* SWCODEC recoring functions */ |
147 | int audio_get_encoder_id(void); | 180 | /* playback.c */ |
148 | void audio_load_encoder(int enc_id); | 181 | bool audio_load_encoder(int afmt); |
149 | void audio_remove_encoder(void); | 182 | void audio_remove_encoder(void); |
183 | unsigned char *audio_get_recording_buffer(size_t *buffer_size); | ||
150 | #endif /* CONFIG_CODEC == SWCODEC */ | 184 | #endif /* CONFIG_CODEC == SWCODEC */ |
185 | #endif /* HAVE_RECORDING */ | ||
151 | 186 | ||
187 | #ifdef HAVE_SPDIF_IN | ||
188 | #ifdef HAVE_SPDIF_POWER | ||
189 | void audio_set_spdif_power_setting(bool on); | ||
190 | bool audio_get_spdif_power_setting(void); | ||
191 | #endif | ||
192 | /* returns index into rec_master_sampr_list */ | ||
193 | int audio_get_spdif_sample_rate(void); | ||
194 | /* > 0: monitor EBUin, 0: Monitor IISrecv, <0: reset only */ | ||
195 | void audio_spdif_set_monitor(int monitor_spdif); | ||
196 | #endif /* HAVE_SPDIF_IN */ | ||
152 | 197 | ||
198 | unsigned long audio_prev_elapsed(void); | ||
153 | 199 | ||
154 | 200 | ||
155 | /***********************************************************************/ | 201 | /***********************************************************************/ |
diff --git a/firmware/export/config-h100.h b/firmware/export/config-h100.h index 6f74078e1e..285ab88930 100644 --- a/firmware/export/config-h100.h +++ b/firmware/export/config-h100.h | |||
@@ -84,6 +84,12 @@ | |||
84 | /* define this if you have recording possibility */ | 84 | /* define this if you have recording possibility */ |
85 | #define HAVE_RECORDING 1 | 85 | #define HAVE_RECORDING 1 |
86 | 86 | ||
87 | /* define hardware samples rate caps mask */ | ||
88 | #define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
89 | |||
90 | /* define the bitmask of recording sample rates */ | ||
91 | #define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
92 | |||
87 | #define HAVE_AGC | 93 | #define HAVE_AGC |
88 | 94 | ||
89 | #ifndef SIMULATOR | 95 | #ifndef SIMULATOR |
diff --git a/firmware/export/config-h120.h b/firmware/export/config-h120.h index 1476102100..b22ff0eb22 100644 --- a/firmware/export/config-h120.h +++ b/firmware/export/config-h120.h | |||
@@ -77,6 +77,12 @@ | |||
77 | /* define this if you have recording possibility */ | 77 | /* define this if you have recording possibility */ |
78 | #define HAVE_RECORDING 1 | 78 | #define HAVE_RECORDING 1 |
79 | 79 | ||
80 | /* define hardware samples rate caps mask */ | ||
81 | #define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
82 | |||
83 | /* define the bitmask of recording sample rates */ | ||
84 | #define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
85 | |||
80 | #define HAVE_AGC | 86 | #define HAVE_AGC |
81 | 87 | ||
82 | #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ | 88 | #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ |
diff --git a/firmware/export/config-h300.h b/firmware/export/config-h300.h index 31f0f6729f..748635dcb4 100644 --- a/firmware/export/config-h300.h +++ b/firmware/export/config-h300.h | |||
@@ -72,6 +72,12 @@ | |||
72 | /* define this if you have recording possibility */ | 72 | /* define this if you have recording possibility */ |
73 | #define HAVE_RECORDING 1 | 73 | #define HAVE_RECORDING 1 |
74 | 74 | ||
75 | /* define hardware samples rate caps mask */ | ||
76 | #define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
77 | |||
78 | /* define the bitmask of recording sample rates */ | ||
79 | #define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
80 | |||
75 | #define HAVE_AGC | 81 | #define HAVE_AGC |
76 | 82 | ||
77 | #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ | 83 | #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ |
@@ -157,4 +163,3 @@ | |||
157 | 163 | ||
158 | /* Define this for FM radio input available */ | 164 | /* Define this for FM radio input available */ |
159 | #define HAVE_FMRADIO_IN | 165 | #define HAVE_FMRADIO_IN |
160 | |||
diff --git a/firmware/export/config-iaudiox5.h b/firmware/export/config-iaudiox5.h index 80b010a6b0..d4c904ed23 100644 --- a/firmware/export/config-iaudiox5.h +++ b/firmware/export/config-iaudiox5.h | |||
@@ -9,6 +9,12 @@ | |||
9 | /* define this if you have recording possibility */ | 9 | /* define this if you have recording possibility */ |
10 | #define HAVE_RECORDING 1 | 10 | #define HAVE_RECORDING 1 |
11 | 11 | ||
12 | /* define the bitmask of hardware sample rates */ | ||
13 | #define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
14 | |||
15 | /* define the bitmask of recording sample rates */ | ||
16 | #define REC_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
17 | |||
12 | /* define this if you have a bitmap LCD display */ | 18 | /* define this if you have a bitmap LCD display */ |
13 | #define HAVE_LCD_BITMAP 1 | 19 | #define HAVE_LCD_BITMAP 1 |
14 | 20 | ||
diff --git a/firmware/export/id3.h b/firmware/export/id3.h index 1d07affbfa..dd099e0204 100644 --- a/firmware/export/id3.h +++ b/firmware/export/id3.h | |||
@@ -24,13 +24,19 @@ | |||
24 | #include "file.h" | 24 | #include "file.h" |
25 | 25 | ||
26 | /* Audio file types. */ | 26 | /* Audio file types. */ |
27 | enum { | 27 | enum |
28 | { | ||
28 | AFMT_UNKNOWN = 0, /* Unknown file format */ | 29 | AFMT_UNKNOWN = 0, /* Unknown file format */ |
29 | 30 | ||
31 | /* start formats */ | ||
32 | |||
30 | AFMT_MPA_L1, /* MPEG Audio layer 1 */ | 33 | AFMT_MPA_L1, /* MPEG Audio layer 1 */ |
31 | AFMT_MPA_L2, /* MPEG Audio layer 2 */ | 34 | AFMT_MPA_L2, /* MPEG Audio layer 2 */ |
32 | AFMT_MPA_L3, /* MPEG Audio layer 3 */ | 35 | AFMT_MPA_L3, /* MPEG Audio layer 3 */ |
33 | 36 | ||
37 | AFMT_AIFF, /* Audio Interchange File Format */ | ||
38 | |||
39 | #if CONFIG_CODEC == SWCODEC | ||
34 | AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */ | 40 | AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */ |
35 | AFMT_OGG_VORBIS, /* Ogg Vorbis */ | 41 | AFMT_OGG_VORBIS, /* Ogg Vorbis */ |
36 | AFMT_FLAC, /* FLAC */ | 42 | AFMT_FLAC, /* FLAC */ |
@@ -40,54 +46,91 @@ enum { | |||
40 | AFMT_ALAC, /* Apple Lossless Audio Codec */ | 46 | AFMT_ALAC, /* Apple Lossless Audio Codec */ |
41 | AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */ | 47 | AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */ |
42 | AFMT_SHN, /* Shorten */ | 48 | AFMT_SHN, /* Shorten */ |
43 | AFMT_AIFF, /* Audio Interchange File Format */ | ||
44 | AFMT_SID, /* SID File Format */ | 49 | AFMT_SID, /* SID File Format */ |
45 | AFMT_ADX, /* ADX */ | 50 | AFMT_ADX, /* ADX File Format */ |
51 | #endif | ||
46 | 52 | ||
47 | /* New formats must be added to the end of this list */ | 53 | /* add new formats at any index above this line to have a sensible order - |
54 | specified array index inits are used */ | ||
55 | /* format arrays defined in id3.c */ | ||
48 | 56 | ||
49 | AFMT_NUM_CODECS, | 57 | AFMT_NUM_CODECS, |
50 | 58 | ||
51 | #if CONFIG_CODEC == SWCODEC | 59 | #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) |
52 | /* masks to decompose parts */ | 60 | /* masks to decompose parts */ |
53 | CODEC_AFMT_MASK = 0x0fff, | 61 | CODEC_AFMT_MASK = 0x0fff, |
54 | CODEC_TYPE_MASK = 0x7000, | 62 | CODEC_TYPE_MASK = 0x7000, |
55 | 63 | ||
56 | /* switch for specifying codec type when requesting a filename */ | 64 | /* switch for specifying codec type when requesting a filename */ |
57 | CODEC_TYPE_DECODER = (0 << 12), /* default */ | 65 | CODEC_TYPE_DECODER = (0 << 12), /* default */ |
58 | CODEC_TYPE_ENCODER = (1 << 12) | 66 | CODEC_TYPE_ENCODER = (1 << 12), |
59 | #endif | 67 | #endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ |
60 | }; | 68 | }; |
61 | 69 | ||
62 | #if CONFIG_CODEC == SWCODEC | 70 | #if CONFIG_CODEC == SWCODEC |
63 | #define AFMT_ENTRY(label, codec_fname, codec_enc_fname, enc_ext) \ | 71 | #define CODEC_EXTENSION "codec" |
64 | { label, codec_fname, codec_enc_fname, enc_ext } | 72 | |
65 | #else | 73 | #ifdef HAVE_RECORDING |
66 | #define AFMT_ENTRY(label, codec_fname, codec_enc_fname, enc_ext) \ | 74 | #define ENCODER_SUFFIX "_enc" |
67 | { label } | 75 | enum rec_format_indexes |
68 | #endif | 76 | { |
77 | __REC_FORMAT_START_INDEX = -1, | ||
78 | |||
79 | /* start formats */ | ||
80 | |||
81 | REC_FORMAT_PCM_WAV, | ||
82 | REC_FORMAT_WAVPACK, | ||
83 | REC_FORMAT_MPA_L3, | ||
84 | |||
85 | /* add new formats at any index above this line to have a sensible order - | ||
86 | specified array index inits are used | ||
87 | REC_FORMAT_CFG_NUM_BITS should allocate enough bits to hold the range | ||
88 | REC_FORMAT_CFG_VALUE_LIST should be in same order as indexes | ||
89 | */ | ||
90 | |||
91 | REC_NUM_FORMATS, | ||
92 | |||
93 | REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV, | ||
94 | REC_FORMAT_CFG_NUM_BITS = 2 | ||
95 | }; | ||
96 | |||
97 | #define REC_FORMAT_CFG_VAL_LIST "wave,wvpk,mpa3" | ||
98 | |||
99 | /* get REC_FORMAT_* corresponding AFMT_* */ | ||
100 | extern const int rec_format_afmt[REC_NUM_FORMATS]; | ||
101 | /* get AFMT_* corresponding REC_FORMAT_* */ | ||
102 | extern const int afmt_rec_format[AFMT_NUM_CODECS]; | ||
103 | |||
104 | #define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ | ||
105 | { label, root_fname, enc_root_fname, ext_list } | ||
106 | #else /* !HAVE_RECORDING */ | ||
107 | #define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ | ||
108 | { label, root_fname, ext_list } | ||
109 | #endif /* HAVE_RECORDING */ | ||
110 | #else /* !SWCODEC */ | ||
111 | |||
112 | #define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ | ||
113 | { label, ext_list } | ||
114 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
69 | 115 | ||
70 | /* record describing the audio format */ | 116 | /* record describing the audio format */ |
71 | struct afmt_entry | 117 | struct afmt_entry |
72 | { | 118 | { |
73 | #if CONFIG_CODEC == SWCODEC | ||
74 | char label[8]; /* format label */ | 119 | char label[8]; /* format label */ |
75 | char *codec_fn; /* filename of decoder codec */ | 120 | #if CONFIG_CODEC == SWCODEC |
76 | char *codec_enc_fn; /* filename of encoder codec */ | 121 | char *codec_root_fn; /* root codec filename (sans _enc and .codec) */ |
77 | char *ext; /* default extension for file (enc only for now) */ | 122 | #ifdef HAVE_RECORDING |
78 | #else | 123 | char *codec_enc_root_fn; /* filename of encoder codec */ |
79 | char label[4]; | 124 | #endif |
80 | #endif | 125 | #endif |
126 | char *ext_list; /* double NULL terminated extension | ||
127 | list for type with the first as | ||
128 | the default for recording */ | ||
81 | }; | 129 | }; |
82 | 130 | ||
83 | /* database of labels and codecs. add formats per above enum */ | 131 | /* database of labels and codecs. add formats per above enum */ |
84 | extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS]; | 132 | extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS]; |
85 | 133 | ||
86 | #if CONFIG_CODEC == SWCODEC | ||
87 | /* recording quality to AFMT_* */ | ||
88 | extern const int rec_quality_info_afmt[9]; | ||
89 | #endif | ||
90 | |||
91 | struct mp3entry { | 134 | struct mp3entry { |
92 | char path[MAX_PATH]; | 135 | char path[MAX_PATH]; |
93 | char* title; | 136 | char* title; |
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h index a4cd93969b..9c3e96ba63 100644 --- a/firmware/export/pcm_playback.h +++ b/firmware/export/pcm_playback.h | |||
@@ -19,11 +19,23 @@ | |||
19 | #ifndef PCM_PLAYBACK_H | 19 | #ifndef PCM_PLAYBACK_H |
20 | #define PCM_PLAYBACK_H | 20 | #define PCM_PLAYBACK_H |
21 | 21 | ||
22 | #include <sys/types.h> | ||
23 | |||
24 | /* Typedef for registered callback (play and record) */ | ||
25 | typedef void (*pcm_more_callback_type)(unsigned char **start, | ||
26 | size_t *size); | ||
27 | |||
22 | void pcm_init(void); | 28 | void pcm_init(void); |
29 | |||
30 | /* set the pcm frequency - use values in hw_sampr_list | ||
31 | * use -1 for the default frequency | ||
32 | */ | ||
23 | void pcm_set_frequency(unsigned int frequency); | 33 | void pcm_set_frequency(unsigned int frequency); |
34 | /* apply settings to hardware immediately */ | ||
35 | void pcm_apply_settings(bool reset); | ||
24 | 36 | ||
25 | /* This is for playing "raw" PCM data */ | 37 | /* This is for playing "raw" PCM data */ |
26 | void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), | 38 | void pcm_play_data(pcm_more_callback_type get_more, |
27 | unsigned char* start, size_t size); | 39 | unsigned char* start, size_t size); |
28 | 40 | ||
29 | void pcm_calculate_peaks(int *left, int *right); | 41 | void pcm_calculate_peaks(int *left, int *right); |
@@ -35,4 +47,4 @@ void pcm_play_pause(bool play); | |||
35 | bool pcm_is_paused(void); | 47 | bool pcm_is_paused(void); |
36 | bool pcm_is_playing(void); | 48 | bool pcm_is_playing(void); |
37 | 49 | ||
38 | #endif | 50 | #endif /* PCM_PLAYBACK_H */ |
diff --git a/firmware/export/pcm_record.h b/firmware/export/pcm_record.h index b217335340..c1187a4c6c 100644 --- a/firmware/export/pcm_record.h +++ b/firmware/export/pcm_record.h | |||
@@ -20,24 +20,44 @@ | |||
20 | #ifndef PCM_RECORD_H | 20 | #ifndef PCM_RECORD_H |
21 | #define PCM_RECORD_H | 21 | #define PCM_RECORD_H |
22 | 22 | ||
23 | void enc_set_parameters(int chunk_size, int num_chunks, | 23 | #define DMA_REC_ERROR_DMA ((size_t)-1) |
24 | int samp_per_chunk, char *head_ptr, int head_size, | 24 | #ifdef HAVE_SPDIF_IN |
25 | int enc_id); | 25 | #define DMA_REC_ERROR_SPDIF ((size_t)-2) |
26 | void enc_get_inputs(int *buffer_size, int *channels, int *quality); | 26 | #endif |
27 | unsigned int* enc_alloc_chunk(void); | 27 | /* Use AUDIO_SRC_* enumeration values */ |
28 | void enc_free_chunk(void); | 28 | void pcm_set_monitor(int monitor); |
29 | int enc_wavbuf_near_empty(void); | 29 | void pcm_set_rec_source(int source); |
30 | char* enc_get_wav_data(int size); | 30 | |
31 | extern void (*enc_set_header_callback)(void *head_buffer, int head_size, | 31 | /** |
32 | int num_pcm_samples, bool is_file_header); | 32 | * RAW pcm data recording |
33 | * These calls are nescessary only when using the raw pcm apis directly. | ||
34 | */ | ||
35 | |||
36 | /* Initialize pcm recording interface */ | ||
37 | void pcm_init_recording(void); | ||
38 | /* Uninitialze pcm recording interface */ | ||
39 | void pcm_close_recording(void); | ||
40 | |||
41 | /* Start recording "raw" PCM data */ | ||
42 | void pcm_record_data(pcm_more_callback_type more_ready, | ||
43 | unsigned char *start, size_t size); | ||
33 | 44 | ||
45 | /* Stop tranferring data into supplied buffer */ | ||
46 | void pcm_stop_recording(void); | ||
47 | |||
48 | void pcm_calculate_rec_peaks(int *left, int *right); | ||
49 | |||
50 | /** General functions for high level codec recording **/ | ||
51 | void pcm_rec_error_clear(void); | ||
34 | unsigned long pcm_rec_status(void); | 52 | unsigned long pcm_rec_status(void); |
35 | void pcm_rec_init(void); | 53 | void pcm_rec_init(void); |
36 | void pcm_rec_mux(int source); | 54 | void pcm_rec_mux(int source); |
37 | int pcm_rec_current_bitrate(void); | 55 | int pcm_rec_current_bitrate(void); |
56 | int pcm_rec_encoder_afmt(void); /* AFMT_* value, AFMT_UNKNOWN if none */ | ||
57 | int pcm_rec_rec_format(void); /* Format index or -1 otherwise */ | ||
58 | unsigned long pcm_rec_sample_rate(void); | ||
38 | int pcm_get_num_unprocessed(void); | 59 | int pcm_get_num_unprocessed(void); |
39 | void pcm_rec_get_peaks(int *left, int *right); | ||
40 | 60 | ||
41 | /* audio.h contains audio recording functions */ | 61 | /* audio.h contains audio_* recording functions */ |
42 | 62 | ||
43 | #endif | 63 | #endif /* PCM_RECORD_H */ |
diff --git a/firmware/export/system.h b/firmware/export/system.h index 4a33d80466..9b90a6e80c 100644 --- a/firmware/export/system.h +++ b/firmware/export/system.h | |||
@@ -21,7 +21,6 @@ | |||
21 | #define __SYSTEM_H__ | 21 | #define __SYSTEM_H__ |
22 | 22 | ||
23 | #include "cpu.h" | 23 | #include "cpu.h" |
24 | #include "config.h" | ||
25 | #include "stdbool.h" | 24 | #include "stdbool.h" |
26 | 25 | ||
27 | extern void system_reboot (void); | 26 | extern void system_reboot (void); |
@@ -111,6 +110,23 @@ const char *get_cpu_boost_tracker(void); | |||
111 | #define MAX(a, b) (((a)>(b))?(a):(b)) | 110 | #define MAX(a, b) (((a)>(b))?(a):(b)) |
112 | #endif | 111 | #endif |
113 | 112 | ||
113 | /* return number of elements in array a */ | ||
114 | #define ARRAYLEN(a) (sizeof(a)/sizeof((a)[0])) | ||
115 | |||
116 | /* return p incremented by specified number of bytes */ | ||
117 | #define SKIPBYTES(p, count) ((typeof (p))((char *)(p) + (count))) | ||
118 | |||
119 | #define P2_M1(p2) ((1 << (p2))-1) | ||
120 | |||
121 | /* align up or down to nearest 2^p2 */ | ||
122 | #define ALIGN_DOWN_P2(n, p2) ((n) & ~P2_M1(p2)) | ||
123 | #define ALIGN_UP_P2(n, p2) ALIGN_DOWN_P2((n) + P2_M1(p2),p2) | ||
124 | |||
125 | /* align up or down to nearest integer multiple of a */ | ||
126 | #define ALIGN_DOWN(n, a) ((n)/(a)*(a)) | ||
127 | #define ALIGN_UP(n, a) ALIGN_DOWN((n)+((a)-1),a) | ||
128 | |||
129 | /* live endianness conversion */ | ||
114 | #ifdef ROCKBOX_LITTLE_ENDIAN | 130 | #ifdef ROCKBOX_LITTLE_ENDIAN |
115 | #define letoh16(x) (x) | 131 | #define letoh16(x) (x) |
116 | #define letoh32(x) (x) | 132 | #define letoh32(x) (x) |
@@ -120,6 +136,8 @@ const char *get_cpu_boost_tracker(void); | |||
120 | #define betoh32(x) swap32(x) | 136 | #define betoh32(x) swap32(x) |
121 | #define htobe16(x) swap16(x) | 137 | #define htobe16(x) swap16(x) |
122 | #define htobe32(x) swap32(x) | 138 | #define htobe32(x) swap32(x) |
139 | #define swap_odd_even_be32(x) (x) | ||
140 | #define swap_odd_even_le32(x) swap_odd_even32(x) | ||
123 | #else | 141 | #else |
124 | #define letoh16(x) swap16(x) | 142 | #define letoh16(x) swap16(x) |
125 | #define letoh32(x) swap32(x) | 143 | #define letoh32(x) swap32(x) |
@@ -129,6 +147,37 @@ const char *get_cpu_boost_tracker(void); | |||
129 | #define betoh32(x) (x) | 147 | #define betoh32(x) (x) |
130 | #define htobe16(x) (x) | 148 | #define htobe16(x) (x) |
131 | #define htobe32(x) (x) | 149 | #define htobe32(x) (x) |
150 | #define swap_odd_even_be32(x) swap_odd_even32(x) | ||
151 | #define swap_odd_even_le32(x) (x) | ||
152 | #endif | ||
153 | |||
154 | /* static endianness conversion */ | ||
155 | #define SWAP_16(x) ((typeof(x))(unsigned short)(((unsigned short)(x) >> 8) | \ | ||
156 | ((unsigned short)(x) << 8))) | ||
157 | |||
158 | #define SWAP_32(x) ((typeof(x))(unsigned long)( ((unsigned long)(x) >> 24) | \ | ||
159 | (((unsigned long)(x) & 0xff0000ul) >> 8) | \ | ||
160 | (((unsigned long)(x) & 0xff00ul) << 8) | \ | ||
161 | ((unsigned long)(x) << 24))) | ||
162 | |||
163 | #ifdef ROCKBOX_LITTLE_ENDIAN | ||
164 | #define LE_TO_H16(x) (x) | ||
165 | #define LE_TO_H32(x) (x) | ||
166 | #define H_TO_LE16(x) (x) | ||
167 | #define H_TO_LE32(x) (x) | ||
168 | #define BE_TO_H16(x) SWAP_16(x) | ||
169 | #define BE_TO_H32(x) SWAP_32(x) | ||
170 | #define H_TO_BE16(x) SWAP_16(x) | ||
171 | #define H_TO_BE32(x) SWAP_32(x) | ||
172 | #else | ||
173 | #define LE_TO_H16(x) SWAP_16(x) | ||
174 | #define LE_TO_H32(x) SWAP_32(x) | ||
175 | #define H_TO_LE16(x) SWAP_16(x) | ||
176 | #define H_TO_LE32(x) SWAP_32(x) | ||
177 | #define BE_TO_H16(x) (x) | ||
178 | #define BE_TO_H32(x) (x) | ||
179 | #define H_TO_BE16(x) (x) | ||
180 | #define H_TO_BE32(x) (x) | ||
132 | #endif | 181 | #endif |
133 | 182 | ||
134 | 183 | ||
@@ -181,6 +230,7 @@ enum { | |||
181 | : /* %0 */ I_CONSTRAINT((char)(mask)), \ | 230 | : /* %0 */ I_CONSTRAINT((char)(mask)), \ |
182 | /* %1 */ "z"(address-GBR)) | 231 | /* %1 */ "z"(address-GBR)) |
183 | 232 | ||
233 | |||
184 | #endif /* CONFIG_CPU == SH7034 */ | 234 | #endif /* CONFIG_CPU == SH7034 */ |
185 | 235 | ||
186 | #ifndef SIMULATOR | 236 | #ifndef SIMULATOR |
@@ -388,7 +438,20 @@ static inline unsigned long swap32(unsigned long value) | |||
388 | #define invalidate_icache() | 438 | #define invalidate_icache() |
389 | 439 | ||
390 | #endif | 440 | #endif |
391 | #else | 441 | |
442 | #ifndef CPU_COLDFIRE | ||
443 | static inline unsigned long swap_odd_even32(unsigned long value) | ||
444 | { | ||
445 | /* | ||
446 | result[31..24],[15.. 8] = value[23..16],[ 7.. 0] | ||
447 | result[23..16],[ 7.. 0] = value[31..24],[15.. 8] | ||
448 | */ | ||
449 | unsigned long t = value & 0xff00ff00; | ||
450 | return (t >> 8) | ((t ^ value) << 8); | ||
451 | } | ||
452 | #endif | ||
453 | |||
454 | #else /* SIMULATOR */ | ||
392 | 455 | ||
393 | static inline unsigned short swap16(unsigned short value) | 456 | static inline unsigned short swap16(unsigned short value) |
394 | /* | 457 | /* |
@@ -412,8 +475,18 @@ static inline unsigned long swap32(unsigned long value) | |||
412 | return (lo << 16) | hi; | 475 | return (lo << 16) | hi; |
413 | } | 476 | } |
414 | 477 | ||
478 | static inline unsigned long swap_odd_even32(unsigned long value) | ||
479 | { | ||
480 | /* | ||
481 | result[31..24],[15.. 8] = value[23..16],[ 7.. 0] | ||
482 | result[23..16],[ 7.. 0] = value[31..24],[15.. 8] | ||
483 | */ | ||
484 | unsigned long t = value & 0xff00ff00; | ||
485 | return (t >> 8) | ((t ^ value) << 8); | ||
486 | } | ||
487 | |||
415 | #define invalidate_icache() | 488 | #define invalidate_icache() |
416 | 489 | ||
417 | #endif | 490 | #endif /* !SIMULATOR */ |
418 | 491 | ||
419 | #endif | 492 | #endif /* __SYSTEM_H__ */ |
diff --git a/firmware/export/thread.h b/firmware/export/thread.h index 17e6e3aa88..72c692ec3b 100644 --- a/firmware/export/thread.h +++ b/firmware/export/thread.h | |||
@@ -142,7 +142,10 @@ void switch_thread(bool save_context, struct thread_entry **blocked_list); | |||
142 | void sleep_thread(int ticks); | 142 | void sleep_thread(int ticks); |
143 | void block_thread(struct thread_entry **thread, int timeout); | 143 | void block_thread(struct thread_entry **thread, int timeout); |
144 | void wakeup_thread(struct thread_entry **thread); | 144 | void wakeup_thread(struct thread_entry **thread); |
145 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
145 | int thread_set_priority(struct thread_entry *thread, int priority); | 146 | int thread_set_priority(struct thread_entry *thread, int priority); |
147 | int thread_get_priority(struct thread_entry *thread); | ||
148 | #endif | ||
146 | void init_threads(void); | 149 | void init_threads(void); |
147 | int thread_stack_usage(const struct thread_entry *thread); | 150 | int thread_stack_usage(const struct thread_entry *thread); |
148 | int thread_get_status(const struct thread_entry *thread); | 151 | int thread_get_status(const struct thread_entry *thread); |
diff --git a/firmware/export/tlv320.h b/firmware/export/tlv320.h index dfcbec4373..023ec9d874 100644 --- a/firmware/export/tlv320.h +++ b/firmware/export/tlv320.h | |||
@@ -24,6 +24,16 @@ | |||
24 | 24 | ||
25 | extern void tlv320_init(void); | 25 | extern void tlv320_init(void); |
26 | extern void tlv320_reset(void); | 26 | extern void tlv320_reset(void); |
27 | /** | ||
28 | * Sets internal sample rate for DAC and ADC relative to MCLK | ||
29 | * Selection for frequency: | ||
30 | * Fs: tlv: with: | ||
31 | * 11025: 0 = MCLK/2 MCLK/2 SCLK, LRCK: Audio Clk / 16 | ||
32 | * 22050: 0 = MCLK/2 MCLK SCLK, LRCK: Audio Clk / 8 | ||
33 | * 44100: 1 = MCLK MCLK SCLK, LRCK: Audio Clk / 4 (default) | ||
34 | * 88200: 2 = MCLK*2 MCLK SCLK, LRCK: Audio Clk / 2 | ||
35 | */ | ||
36 | extern void tlv320_set_frequency(unsigned fsel); | ||
27 | extern void tlv320_enable_output(bool enable); | 37 | extern void tlv320_enable_output(bool enable); |
28 | extern void tlv320_set_headphone_vol(int vol_l, int vol_r); | 38 | extern void tlv320_set_headphone_vol(int vol_l, int vol_r); |
29 | extern void tlv320_set_recvol(int left, int right, int type); | 39 | extern void tlv320_set_recvol(int left, int right, int type); |
diff --git a/firmware/export/uda1380.h b/firmware/export/uda1380.h index 9c761c6a7d..639ca8aa5c 100644 --- a/firmware/export/uda1380.h +++ b/firmware/export/uda1380.h | |||
@@ -28,8 +28,17 @@ extern void uda1380_set_bass(int value); | |||
28 | extern void uda1380_set_treble(int value); | 28 | extern void uda1380_set_treble(int value); |
29 | extern int uda1380_mute(int mute); | 29 | extern int uda1380_mute(int mute); |
30 | extern void uda1380_close(void); | 30 | extern void uda1380_close(void); |
31 | extern void uda1380_set_nsorder(int order); | 31 | /** |
32 | 32 | * Sets frequency settings for DAC and ADC relative to MCLK | |
33 | * | ||
34 | * Selection for frequency ranges: | ||
35 | * Fs: range: with: | ||
36 | * 11025: 0 = 6.25 to 12.5 SCLK, LRCK: Audio Clk / 16 | ||
37 | * 22050: 1 = 12.5 to 25 SCLK, LRCK: Audio Clk / 8 | ||
38 | * 44100: 2 = 25 to 50 SCLK, LRCK: Audio Clk / 4 (default) | ||
39 | * 88200: 3 = 50 to 100 SCLK, LRCK: Audio Clk / 2 | ||
40 | */ | ||
41 | extern void uda1380_set_frequency(unsigned fsel); | ||
33 | extern void uda1380_enable_recording(bool source_mic); | 42 | extern void uda1380_enable_recording(bool source_mic); |
34 | extern void uda1380_disable_recording(void); | 43 | extern void uda1380_disable_recording(void); |
35 | extern void uda1380_set_recvol(int left, int right, int type); | 44 | extern void uda1380_set_recvol(int left, int right, int type); |
diff --git a/firmware/id3.c b/firmware/id3.c index 92f60a2095..7d03c75331 100644 --- a/firmware/id3.c +++ b/firmware/id3.c | |||
@@ -44,6 +44,89 @@ | |||
44 | #include "replaygain.h" | 44 | #include "replaygain.h" |
45 | #include "rbunicode.h" | 45 | #include "rbunicode.h" |
46 | 46 | ||
47 | /** Database of audio formats **/ | ||
48 | const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | ||
49 | { | ||
50 | /* Unknown file format */ | ||
51 | [AFMT_UNKNOWN] = | ||
52 | AFMT_ENTRY("???", NULL, NULL, NULL ), | ||
53 | |||
54 | /* MPEG Audio layer 1 */ | ||
55 | [AFMT_MPA_L1] = | ||
56 | AFMT_ENTRY("MP1", "mpa", NULL, "mp1\0" ), | ||
57 | /* MPEG Audio layer 2 */ | ||
58 | [AFMT_MPA_L2] = | ||
59 | AFMT_ENTRY("MP2", "mpa", NULL, "mpa\0mp2\0" ), | ||
60 | /* MPEG Audio layer 3 */ | ||
61 | [AFMT_MPA_L3] = | ||
62 | AFMT_ENTRY("MP3", "mpa", "mp3_enc", "mp3\0" ), | ||
63 | |||
64 | /* Audio Interchange File Format */ | ||
65 | [AFMT_AIFF] = | ||
66 | AFMT_ENTRY("AIFF", "aiff", NULL, "aiff\0aif\0"), | ||
67 | |||
68 | #if CONFIG_CODEC == SWCODEC | ||
69 | /* Uncompressed PCM in a WAV file */ | ||
70 | [AFMT_PCM_WAV] = | ||
71 | AFMT_ENTRY("WAV", "wav", "wav_enc", "wav\0" ), | ||
72 | /* Ogg Vorbis */ | ||
73 | [AFMT_OGG_VORBIS] = | ||
74 | AFMT_ENTRY("Ogg", "vorbis", NULL, "ogg\0" ), | ||
75 | /* FLAC */ | ||
76 | [AFMT_FLAC] = | ||
77 | AFMT_ENTRY("FLAC", "flac", NULL, "flac\0" ), | ||
78 | /* Musepack */ | ||
79 | [AFMT_MPC] = | ||
80 | AFMT_ENTRY("MPC", "mpc", NULL, "mpc\0" ), | ||
81 | /* A/52 (aka AC3) audio */ | ||
82 | [AFMT_A52] = | ||
83 | AFMT_ENTRY("AC3", "a52", NULL, "a52\0ac3\0" ), | ||
84 | /* WavPack */ | ||
85 | [AFMT_WAVPACK] = | ||
86 | AFMT_ENTRY("WV", "wavpack", "wavpack_enc", "wv\0" ), | ||
87 | /* Apple Lossless Audio Codec */ | ||
88 | [AFMT_ALAC] = | ||
89 | AFMT_ENTRY("ALAC", "alac", NULL, "m4a\0" ), | ||
90 | /* Advanced Audio Coding in M4A container */ | ||
91 | [AFMT_AAC] = | ||
92 | AFMT_ENTRY("AAC", "aac", NULL, "mp4\0" ), | ||
93 | /* Shorten */ | ||
94 | [AFMT_SHN] = | ||
95 | AFMT_ENTRY("SHN", "shorten", NULL, "shn\0" ), | ||
96 | /* SID File Format */ | ||
97 | [AFMT_SID] = | ||
98 | AFMT_ENTRY("SID", "sid", NULL, "sid\0" ), | ||
99 | /* ADX File Format */ | ||
100 | [AFMT_ADX] = | ||
101 | AFMT_ENTRY("ADX", "adx", NULL, "adx\0" ), | ||
102 | #endif | ||
103 | }; | ||
104 | |||
105 | #if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) | ||
106 | /* get REC_FORMAT_* corresponding AFMT_* */ | ||
107 | const int rec_format_afmt[REC_NUM_FORMATS] = | ||
108 | { | ||
109 | /* give AFMT_UNKNOWN by default */ | ||
110 | [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN, | ||
111 | /* add new entries below this line */ | ||
112 | [REC_FORMAT_MPA_L3] = AFMT_MPA_L3, | ||
113 | [REC_FORMAT_WAVPACK] = AFMT_WAVPACK, | ||
114 | [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV, | ||
115 | }; | ||
116 | |||
117 | /* get AFMT_* corresponding REC_FORMAT_* */ | ||
118 | const int afmt_rec_format[AFMT_NUM_CODECS] = | ||
119 | { | ||
120 | /* give -1 by default */ | ||
121 | [0 ... AFMT_NUM_CODECS-1] = -1, | ||
122 | /* add new entries below this line */ | ||
123 | [AFMT_MPA_L3] = REC_FORMAT_MPA_L3, | ||
124 | [AFMT_WAVPACK] = REC_FORMAT_WAVPACK, | ||
125 | [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV, | ||
126 | }; | ||
127 | #endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ | ||
128 | /****/ | ||
129 | |||
47 | #define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \ | 130 | #define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \ |
48 | ((long)(b1 & 0x7F) << (2*7)) | \ | 131 | ((long)(b1 & 0x7F) << (2*7)) | \ |
49 | ((long)(b2 & 0x7F) << (1*7)) | \ | 132 | ((long)(b2 & 0x7F) << (1*7)) | \ |
@@ -85,61 +168,6 @@ static const char* const genres[] = { | |||
85 | "Synthpop" | 168 | "Synthpop" |
86 | }; | 169 | }; |
87 | 170 | ||
88 | /* database of audio formats */ | ||
89 | const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | ||
90 | { | ||
91 | /* Unknown file format */ | ||
92 | AFMT_ENTRY("???", NULL, NULL, NULL ), | ||
93 | /* MPEG Audio layer 1 */ | ||
94 | AFMT_ENTRY("MP1", "mpa.codec", NULL, NULL ), | ||
95 | /* MPEG Audio layer 2 */ | ||
96 | AFMT_ENTRY("MP2", "mpa.codec", NULL, NULL ), | ||
97 | /* MPEG Audio layer 3 */ | ||
98 | AFMT_ENTRY("MP3", "mpa.codec", "mp3_enc.codec", ".mp3"), | ||
99 | #if CONFIG_CODEC == SWCODEC | ||
100 | /* Uncompressed PCM in a WAV file */ | ||
101 | AFMT_ENTRY("WAV", "wav.codec", "wav_enc.codec", ".wav"), | ||
102 | /* Ogg Vorbis */ | ||
103 | AFMT_ENTRY("Ogg", "vorbis.codec", NULL, NULL ), | ||
104 | /* FLAC */ | ||
105 | AFMT_ENTRY("FLAC", "flac.codec", NULL, NULL ), | ||
106 | /* Musepack */ | ||
107 | AFMT_ENTRY("MPC", "mpc.codec", NULL, NULL ), | ||
108 | /* A/52 (aka AC3) audio */ | ||
109 | AFMT_ENTRY("AC3", "a52.codec", NULL, NULL ), | ||
110 | /* WavPack */ | ||
111 | AFMT_ENTRY("WV", "wavpack.codec", "wavpack_enc.codec", ".wv" ), | ||
112 | /* Apple Lossless Audio Codec */ | ||
113 | AFMT_ENTRY("ALAC", "alac.codec", NULL, NULL ), | ||
114 | /* Advanced Audio Coding in M4A container */ | ||
115 | AFMT_ENTRY("AAC", "aac.codec", NULL, NULL ), | ||
116 | /* Shorten */ | ||
117 | AFMT_ENTRY("SHN", "shorten.codec", NULL, NULL ), | ||
118 | /* Audio Interchange File Format */ | ||
119 | AFMT_ENTRY("AIFF", "aiff.codec", NULL, NULL ), | ||
120 | /* SID File Format */ | ||
121 | AFMT_ENTRY("SID", "sid.codec", NULL, NULL ), | ||
122 | /* ADX File Format */ | ||
123 | AFMT_ENTRY("ADX", "adx.codec", NULL, NULL ), | ||
124 | #endif | ||
125 | }; | ||
126 | |||
127 | #if CONFIG_CODEC == SWCODEC | ||
128 | /* recording quality to AFMT_* */ | ||
129 | const int rec_quality_info_afmt[9] = | ||
130 | { | ||
131 | AFMT_MPA_L3, /* MPEG L3 64 kBit/s */ | ||
132 | AFMT_MPA_L3, /* MPEG L3 96 kBit/s */ | ||
133 | AFMT_MPA_L3, /* MPEG L3 128 kBit/s */ | ||
134 | AFMT_MPA_L3, /* MPEG L3 160 kBit/s */ | ||
135 | AFMT_MPA_L3, /* MPEG L3 192 kBit/s */ | ||
136 | AFMT_MPA_L3, /* MPEG L3 224 kBit/s */ | ||
137 | AFMT_MPA_L3, /* MPEG L3 320 kBit/s */ | ||
138 | AFMT_WAVPACK, /* WavPack 909 kBit/s */ | ||
139 | AFMT_PCM_WAV, /* PCM Wav 1411 kBit/s */ | ||
140 | }; | ||
141 | #endif /* SWCODEC */ | ||
142 | |||
143 | char* id3_get_genre(const struct mp3entry* id3) | 171 | char* id3_get_genre(const struct mp3entry* id3) |
144 | { | 172 | { |
145 | if( id3->genre_string ) | 173 | if( id3->genre_string ) |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index ce1d995461..bb438a3ab4 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -2453,34 +2453,32 @@ static void stop_recording(void) | |||
2453 | resume_recording(); | 2453 | resume_recording(); |
2454 | } | 2454 | } |
2455 | 2455 | ||
2456 | void audio_set_recording_options(int frequency, int quality, | 2456 | void audio_set_recording_options(struct audio_recording_options *options) |
2457 | int source, int channel_mode, | ||
2458 | bool editable, int prerecord_time) | ||
2459 | { | 2457 | { |
2460 | bool is_mpeg1; | 2458 | bool is_mpeg1; |
2461 | 2459 | ||
2462 | is_mpeg1 = (frequency < 3)?true:false; | 2460 | is_mpeg1 = (options->rec_frequency < 3)?true:false; |
2463 | 2461 | ||
2464 | rec_version_index = is_mpeg1?3:2; | 2462 | rec_version_index = is_mpeg1?3:2; |
2465 | rec_frequency_index = frequency % 3; | 2463 | rec_frequency_index = options->rec_frequency % 3; |
2466 | 2464 | ||
2467 | shadow_encoder_control = (quality << 17) | | 2465 | shadow_encoder_control = (options->rec_quality << 17) | |
2468 | (rec_frequency_index << 10) | | 2466 | (rec_frequency_index << 10) | |
2469 | ((is_mpeg1?1:0) << 9) | | 2467 | ((is_mpeg1?1:0) << 9) | |
2470 | (((channel_mode * 2 + 1) & 3) << 6) | | 2468 | (((options->rec_channels * 2 + 1) & 3) << 6) | |
2471 | (1 << 5) /* MS-stereo */ | | 2469 | (1 << 5) /* MS-stereo */ | |
2472 | (1 << 2) /* Is an original */; | 2470 | (1 << 2) /* Is an original */; |
2473 | mas_writemem(MAS_BANK_D0, MAS_D0_ENCODER_CONTROL, &shadow_encoder_control,1); | 2471 | mas_writemem(MAS_BANK_D0, MAS_D0_ENCODER_CONTROL, &shadow_encoder_control,1); |
2474 | 2472 | ||
2475 | DEBUGF("mas_writemem(MAS_BANK_D0, ENCODER_CONTROL, %x)\n", shadow_encoder_control); | 2473 | DEBUGF("mas_writemem(MAS_BANK_D0, ENCODER_CONTROL, %x)\n", shadow_encoder_control); |
2476 | 2474 | ||
2477 | shadow_soft_mute = editable?4:0; | 2475 | shadow_soft_mute = options->rec_editable?4:0; |
2478 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute,1); | 2476 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute,1); |
2479 | 2477 | ||
2480 | DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute); | 2478 | DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute); |
2481 | 2479 | ||
2482 | shadow_io_control_main = ((1 << 10) | /* Monitoring ON */ | 2480 | shadow_io_control_main = ((1 << 10) | /* Monitoring ON */ |
2483 | ((source < 2)?1:2) << 8) | /* Input select */ | 2481 | ((options->rec_source < 2)?1:2) << 8) | /* Input select */ |
2484 | (1 << 5) | /* SDO strobe invert */ | 2482 | (1 << 5) | /* SDO strobe invert */ |
2485 | ((is_mpeg1?0:1) << 3) | | 2483 | ((is_mpeg1?0:1) << 3) | |
2486 | (1 << 2) | /* Inverted SIBC clock signal */ | 2484 | (1 << 2) | /* Inverted SIBC clock signal */ |
@@ -2489,7 +2487,7 @@ void audio_set_recording_options(int frequency, int quality, | |||
2489 | 2487 | ||
2490 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); | 2488 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); |
2491 | 2489 | ||
2492 | if(source == AUDIO_SRC_MIC) | 2490 | if(options->rec_source == AUDIO_SRC_MIC) |
2493 | { | 2491 | { |
2494 | /* Copy left channel to right (mono mode) */ | 2492 | /* Copy left channel to right (mono mode) */ |
2495 | mas_codec_writereg(8, 0x8000); | 2493 | mas_codec_writereg(8, 0x8000); |
@@ -2500,7 +2498,7 @@ void audio_set_recording_options(int frequency, int quality, | |||
2500 | mas_codec_writereg(8, 0); | 2498 | mas_codec_writereg(8, 0); |
2501 | } | 2499 | } |
2502 | 2500 | ||
2503 | prerecording_max_seconds = prerecord_time; | 2501 | prerecording_max_seconds = options->rec_prerecord_time; |
2504 | if(prerecording_max_seconds) | 2502 | if(prerecording_max_seconds) |
2505 | { | 2503 | { |
2506 | prerecording = true; | 2504 | prerecording = true; |
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index cd14f123d1..b7ea96f3d3 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c | |||
@@ -16,259 +16,86 @@ | |||
16 | * KIND, either express or implied. | 16 | * KIND, either express or implied. |
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #include <stdbool.h> | 19 | #include "system.h" |
20 | #include "config.h" | 20 | #include "kernel.h" |
21 | #include "debug.h" | 21 | #include "logf.h" |
22 | #include "panic.h" | 22 | #include "audio.h" |
23 | #include <kernel.h> | 23 | #if defined(HAVE_WM8975) |
24 | #include "cpu.h" | ||
25 | #include "i2c.h" | ||
26 | #if defined(HAVE_UDA1380) | ||
27 | #include "uda1380.h" | ||
28 | #elif defined(HAVE_WM8975) | ||
29 | #include "wm8975.h" | 24 | #include "wm8975.h" |
30 | #elif defined(HAVE_WM8758) | 25 | #elif defined(HAVE_WM8758) |
31 | #include "wm8758.h" | 26 | #include "wm8758.h" |
32 | #elif defined(HAVE_TLV320) | ||
33 | #include "tlv320.h" | ||
34 | #elif defined(HAVE_WM8731) || defined(HAVE_WM8721) | 27 | #elif defined(HAVE_WM8731) || defined(HAVE_WM8721) |
35 | #include "wm8731l.h" | 28 | #include "wm8731l.h" |
36 | #elif CONFIG_CPU == PNX0101 | 29 | #elif CONFIG_CPU == PNX0101 |
30 | #include "string.h" | ||
37 | #include "pnx0101.h" | 31 | #include "pnx0101.h" |
38 | #endif | 32 | #endif |
39 | #include "system.h" | ||
40 | #include "logf.h" | ||
41 | 33 | ||
42 | #include <stdio.h> | 34 | /** |
43 | #include <string.h> | 35 | * APIs implemented in the target-specific portion: |
44 | #include <stdarg.h> | 36 | * Public - |
45 | #include "pcm_playback.h" | 37 | * pcm_init |
46 | #include "lcd.h" | 38 | * pcm_get_bytes_waiting |
47 | #include "button.h" | 39 | * pcm_calculate_peaks |
48 | #include "file.h" | 40 | * Semi-private - |
49 | #include "buffer.h" | 41 | * pcm_play_dma_start |
50 | #include "sprintf.h" | 42 | * pcm_play_dma_stop |
51 | #include "button.h" | 43 | * pcm_play_pause_pause |
52 | #include <string.h> | 44 | * pcm_play_pause_unpause |
53 | 45 | */ | |
54 | static bool pcm_playing; | 46 | |
55 | static bool pcm_paused; | 47 | /** These items may be implemented target specifically or need to |
48 | be shared semi-privately **/ | ||
56 | 49 | ||
57 | /* the registered callback function to ask for more mp3 data */ | 50 | /* the registered callback function to ask for more mp3 data */ |
58 | static void (*callback_for_more)(unsigned char**, size_t*) IDATA_ATTR = NULL; | 51 | pcm_more_callback_type pcm_callback_for_more = NULL; |
52 | bool pcm_playing = false; | ||
53 | bool pcm_paused = false; | ||
54 | |||
55 | void pcm_play_dma_start(const void *addr, size_t size); | ||
56 | void pcm_play_dma_stop(void); | ||
57 | void pcm_play_pause_pause(void); | ||
58 | void pcm_play_pause_unpause(void); | ||
59 | |||
60 | /** Functions that require targeted implementation **/ | ||
61 | |||
62 | #ifndef CPU_COLDFIRE | ||
59 | 63 | ||
60 | #if (CONFIG_CPU == S3C2440) | 64 | #if (CONFIG_CPU == S3C2440) |
61 | 65 | ||
62 | /* TODO: Implement for Gigabeat | 66 | /* TODO: Implement for Gigabeat |
63 | For now, just implement some dummy functions. | 67 | For now, just implement some dummy functions. |
64 | */ | 68 | */ |
65 | |||
66 | void pcm_init(void) | 69 | void pcm_init(void) |
67 | { | 70 | { |
68 | |||
69 | } | 71 | } |
70 | 72 | ||
71 | static void dma_start(const void *addr, size_t size) | 73 | void pcm_play_dma_start(const void *addr, size_t size) |
72 | { | 74 | { |
73 | (void)addr; | 75 | (void)addr; |
74 | (void)size; | 76 | (void)size; |
75 | } | 77 | } |
76 | 78 | ||
77 | void pcm_set_frequency(unsigned int frequency) | 79 | void pcm_play_dma_stop(void) |
78 | { | ||
79 | (void)frequency; | ||
80 | } | ||
81 | |||
82 | void pcm_play_stop(void) | ||
83 | { | 80 | { |
84 | } | 81 | } |
85 | 82 | ||
86 | size_t pcm_get_bytes_waiting(void) | 83 | void pcm_play_pause_pause(void) |
87 | { | 84 | { |
88 | return 0; | ||
89 | } | 85 | } |
90 | #else | ||
91 | #ifdef CPU_COLDFIRE | ||
92 | 86 | ||
93 | #ifdef HAVE_SPDIF_OUT | 87 | void pcm_play_pause_unpause(void) |
94 | #define EBU_DEFPARM ((7 << 12) | (3 << 8) | (1 << 5) | (5 << 2)) | ||
95 | #endif | ||
96 | #define IIS_DEFPARM(freq) ((freq << 12) | 0x300 | 4 << 2) | ||
97 | #define IIS_RESET 0x800 | ||
98 | |||
99 | #ifdef IAUDIO_X5 | ||
100 | #define SET_IIS_CONFIG(x) IIS1CONFIG = (x); | ||
101 | #else | ||
102 | #define SET_IIS_CONFIG(x) IIS2CONFIG = (x); | ||
103 | #endif | ||
104 | |||
105 | static int pcm_freq = 0x6; /* 44.1 is default */ | ||
106 | |||
107 | int peak_left = 0, peak_right = 0; | ||
108 | |||
109 | /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ | ||
110 | static void dma_start(const void *addr, size_t size) | ||
111 | { | 88 | { |
112 | pcm_playing = true; | ||
113 | |||
114 | addr = (void *)((unsigned long)addr & ~3); /* Align data */ | ||
115 | size &= ~3; /* Size must be multiple of 4 */ | ||
116 | |||
117 | /* Reset the audio FIFO */ | ||
118 | #ifdef HAVE_SPDIF_OUT | ||
119 | EBU1CONFIG = IIS_RESET | EBU_DEFPARM; | ||
120 | #endif | ||
121 | |||
122 | /* Set up DMA transfer */ | ||
123 | SAR0 = (unsigned long)addr; /* Source address */ | ||
124 | DAR0 = (unsigned long)&PDOR3; /* Destination address */ | ||
125 | BCR0 = size; /* Bytes to transfer */ | ||
126 | |||
127 | /* Enable the FIFO and force one write to it */ | ||
128 | SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq)); | ||
129 | /* Also send the audio to S/PDIF */ | ||
130 | #ifdef HAVE_SPDIF_OUT | ||
131 | EBU1CONFIG = EBU_DEFPARM; | ||
132 | #endif | ||
133 | DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_SINC | (3 << 20) | DMA_START; | ||
134 | } | 89 | } |
135 | 90 | ||
136 | /* Stops the DMA transfer and interrupt */ | ||
137 | static void dma_stop(void) | ||
138 | { | ||
139 | pcm_playing = false; | ||
140 | |||
141 | DCR0 = 0; | ||
142 | DSR0 = 1; | ||
143 | /* Reset the FIFO */ | ||
144 | SET_IIS_CONFIG(IIS_RESET | IIS_DEFPARM(pcm_freq)); | ||
145 | #ifdef HAVE_SPDIF_OUT | ||
146 | EBU1CONFIG = IIS_RESET | EBU_DEFPARM; | ||
147 | #endif | ||
148 | } | ||
149 | |||
150 | /* sets frequency of input to DAC */ | ||
151 | void pcm_set_frequency(unsigned int frequency) | 91 | void pcm_set_frequency(unsigned int frequency) |
152 | { | 92 | { |
153 | switch(frequency) | 93 | (void)frequency; |
154 | { | ||
155 | case 11025: | ||
156 | pcm_freq = 0x2; | ||
157 | #ifdef HAVE_UDA1380 | ||
158 | uda1380_set_nsorder(3); | ||
159 | #endif | ||
160 | break; | ||
161 | case 22050: | ||
162 | pcm_freq = 0x4; | ||
163 | #ifdef HAVE_UDA1380 | ||
164 | uda1380_set_nsorder(3); | ||
165 | #endif | ||
166 | break; | ||
167 | case 44100: | ||
168 | default: | ||
169 | pcm_freq = 0x6; | ||
170 | #ifdef HAVE_UDA1380 | ||
171 | uda1380_set_nsorder(5); | ||
172 | #endif | ||
173 | break; | ||
174 | } | ||
175 | } | 94 | } |
176 | 95 | ||
177 | size_t pcm_get_bytes_waiting(void) | 96 | size_t pcm_get_bytes_waiting(void) |
178 | { | 97 | { |
179 | return (BCR0 & 0xffffff); | 98 | return 0; |
180 | } | ||
181 | |||
182 | /* DMA0 Interrupt is called when the DMA has finished transfering a chunk */ | ||
183 | void DMA0(void) __attribute__ ((interrupt_handler, section(".icode"))); | ||
184 | void DMA0(void) | ||
185 | { | ||
186 | int res = DSR0; | ||
187 | |||
188 | DSR0 = 1; /* Clear interrupt */ | ||
189 | DCR0 &= ~DMA_EEXT; | ||
190 | |||
191 | /* Stop on error */ | ||
192 | if(res & 0x70) | ||
193 | { | ||
194 | dma_stop(); | ||
195 | logf("DMA Error:0x%04x", res); | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | size_t next_size; | ||
200 | unsigned char *next_start; | ||
201 | { | ||
202 | void (*get_more)(unsigned char**, size_t*) = callback_for_more; | ||
203 | if (get_more) | ||
204 | get_more(&next_start, &next_size); | ||
205 | else | ||
206 | { | ||
207 | next_size = 0; | ||
208 | next_start = NULL; | ||
209 | } | ||
210 | } | ||
211 | if(next_size) | ||
212 | { | ||
213 | SAR0 = (unsigned long)next_start; /* Source address */ | ||
214 | BCR0 = next_size; /* Bytes to transfer */ | ||
215 | DCR0 |= DMA_EEXT; | ||
216 | } | ||
217 | else | ||
218 | { | ||
219 | /* Finished playing */ | ||
220 | dma_stop(); | ||
221 | logf("DMA No Data:0x%04x", res); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | IPR |= (1<<14); /* Clear pending interrupt request */ | ||
226 | } | ||
227 | |||
228 | void pcm_init(void) | ||
229 | { | ||
230 | pcm_playing = false; | ||
231 | pcm_paused = false; | ||
232 | |||
233 | MPARK = 0x81; /* PARK[1,0]=10 + BCR24BIT */ | ||
234 | DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */ | ||
235 | DMAROUTE = (DMAROUTE & 0xffffff00) | DMA0_REQ_AUDIO_1; | ||
236 | DMACONFIG = 1; /* DMA0Req = PDOR3 */ | ||
237 | |||
238 | /* Reset the audio FIFO */ | ||
239 | SET_IIS_CONFIG(IIS_RESET); | ||
240 | |||
241 | /* Enable interrupt at level 7, priority 0 */ | ||
242 | ICR6 = 0x1c; | ||
243 | IMR &= ~(1<<14); /* bit 14 is DMA0 */ | ||
244 | |||
245 | pcm_set_frequency(44100); | ||
246 | |||
247 | /* Prevent pops (resets DAC to zero point) */ | ||
248 | SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq) | IIS_RESET); | ||
249 | |||
250 | #if defined(HAVE_UDA1380) | ||
251 | /* Initialize default register values. */ | ||
252 | uda1380_init(); | ||
253 | |||
254 | /* Sleep a while so the power can stabilize (especially a long | ||
255 | delay is needed for the line out connector). */ | ||
256 | sleep(HZ); | ||
257 | |||
258 | /* Power on FSDAC and HP amp. */ | ||
259 | uda1380_enable_output(true); | ||
260 | |||
261 | /* Unmute the master channel (DAC should be at zero point now). */ | ||
262 | uda1380_mute(false); | ||
263 | |||
264 | #elif defined(HAVE_TLV320) | ||
265 | tlv320_init(); | ||
266 | sleep(HZ/4); | ||
267 | tlv320_mute(false); | ||
268 | #endif | ||
269 | |||
270 | /* Call dma_stop to initialize everything. */ | ||
271 | dma_stop(); | ||
272 | } | 99 | } |
273 | 100 | ||
274 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | 101 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ |
@@ -286,14 +113,14 @@ void pcm_init(void) | |||
286 | #define FIFO_FREE_COUNT 4 /* TODO: make this sensible */ | 113 | #define FIFO_FREE_COUNT 4 /* TODO: make this sensible */ |
287 | #endif | 114 | #endif |
288 | 115 | ||
289 | static int pcm_freq = 44100; /* 44.1 is default */ | 116 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ |
290 | 117 | ||
291 | /* NOTE: The order of these two variables is important if you use the iPod | 118 | /* NOTE: The order of these two variables is important if you use the iPod |
292 | assembler optimised fiq handler, so don't change it. */ | 119 | assembler optimised fiq handler, so don't change it. */ |
293 | unsigned short* p IBSS_ATTR; | 120 | unsigned short* p IBSS_ATTR; |
294 | size_t p_size IBSS_ATTR; | 121 | size_t p_size IBSS_ATTR; |
295 | 122 | ||
296 | static void dma_start(const void *addr, size_t size) | 123 | void pcm_play_dma_start(const void *addr, size_t size) |
297 | { | 124 | { |
298 | p=(unsigned short*)addr; | 125 | p=(unsigned short*)addr; |
299 | p_size=size; | 126 | p_size=size; |
@@ -341,7 +168,7 @@ static void dma_start(const void *addr, size_t size) | |||
341 | } | 168 | } |
342 | 169 | ||
343 | /* Stops the DMA transfer and interrupt */ | 170 | /* Stops the DMA transfer and interrupt */ |
344 | static void dma_stop(void) | 171 | void pcm_play_dma_stop(void) |
345 | { | 172 | { |
346 | pcm_playing = false; | 173 | pcm_playing = false; |
347 | 174 | ||
@@ -365,9 +192,58 @@ static void dma_stop(void) | |||
365 | disable_fiq(); | 192 | disable_fiq(); |
366 | } | 193 | } |
367 | 194 | ||
195 | void pcm_play_pause_pause(void) | ||
196 | { | ||
197 | #if CONFIG_CPU == PP5020 | ||
198 | /* Disable the interrupt */ | ||
199 | IISCONFIG &= ~0x2; | ||
200 | /* Disable playback FIFO */ | ||
201 | IISCONFIG &= ~0x20000000; | ||
202 | #elif CONFIG_CPU == PP5002 | ||
203 | /* Disable the interrupt */ | ||
204 | IISFIFO_CFG &= ~(1<<9); | ||
205 | /* Disable playback FIFO */ | ||
206 | IISCONFIG &= ~0x4; | ||
207 | #endif | ||
208 | disable_fiq(); | ||
209 | } | ||
210 | |||
211 | void pcm_play_pause_unpause(void) | ||
212 | { | ||
213 | /* Enable the FIFO and fill it */ | ||
214 | |||
215 | enable_fiq(); | ||
216 | |||
217 | /* Enable playback FIFO */ | ||
218 | #if CONFIG_CPU == PP5020 | ||
219 | IISCONFIG |= 0x20000000; | ||
220 | #elif CONFIG_CPU == PP5002 | ||
221 | IISCONFIG |= 0x4; | ||
222 | #endif | ||
223 | |||
224 | /* Fill the FIFO - we assume there are enough bytes in the | ||
225 | pcm buffer to fill the 32-byte FIFO. */ | ||
226 | while (p_size > 0) { | ||
227 | if (FIFO_FREE_COUNT < 2) { | ||
228 | /* Enable interrupt */ | ||
229 | #if CONFIG_CPU == PP5020 | ||
230 | IISCONFIG |= 0x2; | ||
231 | #elif CONFIG_CPU == PP5002 | ||
232 | IISFIFO_CFG |= (1<<9); | ||
233 | #endif | ||
234 | return; | ||
235 | } | ||
236 | |||
237 | IISFIFO_WR = (*(p++))<<16; | ||
238 | IISFIFO_WR = (*(p++))<<16; | ||
239 | p_size-=4; | ||
240 | } | ||
241 | } | ||
242 | |||
368 | void pcm_set_frequency(unsigned int frequency) | 243 | void pcm_set_frequency(unsigned int frequency) |
369 | { | 244 | { |
370 | pcm_freq=frequency; | 245 | (void)frequency; |
246 | pcm_freq = HW_SAMPR_DEFAULT; | ||
371 | } | 247 | } |
372 | 248 | ||
373 | size_t pcm_get_bytes_waiting(void) | 249 | size_t pcm_get_bytes_waiting(void) |
@@ -378,8 +254,8 @@ size_t pcm_get_bytes_waiting(void) | |||
378 | /* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode | 254 | /* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode |
379 | has registers r8-r14 banked, and so does not need to be saved. This routine | 255 | has registers r8-r14 banked, and so does not need to be saved. This routine |
380 | uses only these registers, and so will never touch the stack unless it | 256 | uses only these registers, and so will never touch the stack unless it |
381 | actually needs to do so when calling callback_for_more. C version is still | 257 | actually needs to do so when calling pcm_callback_for_more. C version is |
382 | included below for reference. | 258 | still included below for reference. |
383 | */ | 259 | */ |
384 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 | 260 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 |
385 | void fiq(void) ICODE_ATTR __attribute__((naked)); | 261 | void fiq(void) ICODE_ATTR __attribute__((naked)); |
@@ -433,10 +309,10 @@ void fiq(void) | |||
433 | "add r1, r11, #4 \n\t" /* r1 = &p_size */ | 309 | "add r1, r11, #4 \n\t" /* r1 = &p_size */ |
434 | "str r9, [r0] \n\t" /* save internal copies of variables back */ | 310 | "str r9, [r0] \n\t" /* save internal copies of variables back */ |
435 | "str r8, [r1] \n\t" | 311 | "str r8, [r1] \n\t" |
436 | "ldr r2, =callback_for_more\n\t" | 312 | "ldr r2, =pcm_callback_for_more\n\t" |
437 | "ldr r2, [r2] \n\t" /* get callback address */ | 313 | "ldr r2, [r2] \n\t" /* get callback address */ |
438 | "cmp r2, #0 \n\t" /* check for null pointer */ | 314 | "cmp r2, #0 \n\t" /* check for null pointer */ |
439 | "movne lr, pc \n\t" /* call callback_for_more */ | 315 | "movne lr, pc \n\t" /* call pcm_callback_for_more */ |
440 | "bxne r2 \n\t" | 316 | "bxne r2 \n\t" |
441 | "ldmia sp!, { r0-r3, r12, lr}\n\t" | 317 | "ldmia sp!, { r0-r3, r12, lr}\n\t" |
442 | "ldr r8, [r11, #4] \n\t" /* reload p_size and p */ | 318 | "ldr r8, [r11, #4] \n\t" /* reload p_size and p */ |
@@ -477,7 +353,7 @@ void fiq(void) | |||
477 | "b .exit \n\t" | 353 | "b .exit \n\t" |
478 | ); | 354 | ); |
479 | } | 355 | } |
480 | #else | 356 | #else /* !(CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002) */ |
481 | void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); | 357 | void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); |
482 | void fiq(void) | 358 | void fiq(void) |
483 | { | 359 | { |
@@ -507,20 +383,21 @@ void fiq(void) | |||
507 | } | 383 | } |
508 | 384 | ||
509 | /* p is empty, get some more data */ | 385 | /* p is empty, get some more data */ |
510 | if (callback_for_more) { | 386 | if (pcm_callback_for_more) { |
511 | callback_for_more((unsigned char**)&p,&p_size); | 387 | pcm_callback_for_more((unsigned char**)&p,&p_size); |
512 | } | 388 | } |
513 | } while (p_size); | 389 | } while (p_size); |
514 | 390 | ||
515 | /* No more data, so disable the FIFO/FIQ */ | 391 | /* No more data, so disable the FIFO/FIQ */ |
516 | dma_stop(); | 392 | pcm_play_dma_stop(); |
517 | } | 393 | } |
518 | #endif | 394 | #endif /* CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 */ |
519 | 395 | ||
520 | void pcm_init(void) | 396 | void pcm_init(void) |
521 | { | 397 | { |
522 | pcm_playing = false; | 398 | pcm_playing = false; |
523 | pcm_paused = false; | 399 | pcm_paused = false; |
400 | pcm_callback_for_more = NULL; | ||
524 | 401 | ||
525 | /* Initialize default register values. */ | 402 | /* Initialize default register values. */ |
526 | wmcodec_init(); | 403 | wmcodec_init(); |
@@ -531,8 +408,8 @@ void pcm_init(void) | |||
531 | /* Unmute the master channel (DAC should be at zero point now). */ | 408 | /* Unmute the master channel (DAC should be at zero point now). */ |
532 | wmcodec_mute(false); | 409 | wmcodec_mute(false); |
533 | 410 | ||
534 | /* Call dma_stop to initialize everything. */ | 411 | /* Call pcm_play_dma_stop to initialize everything. */ |
535 | dma_stop(); | 412 | pcm_play_dma_stop(); |
536 | } | 413 | } |
537 | 414 | ||
538 | #elif (CONFIG_CPU == PNX0101) | 415 | #elif (CONFIG_CPU == PNX0101) |
@@ -542,12 +419,16 @@ void pcm_init(void) | |||
542 | short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; | 419 | short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; |
543 | short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; | 420 | short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; |
544 | 421 | ||
545 | static int pcm_freq = 44100; /* 44.1 is default */ | 422 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ |
546 | 423 | ||
547 | unsigned short* p IBSS_ATTR; | 424 | unsigned short* p IBSS_ATTR; |
548 | size_t p_size IBSS_ATTR; | 425 | size_t p_size IBSS_ATTR; |
549 | 426 | ||
550 | static void dma_start(const void *addr, size_t size) | 427 | void pcm_init(void) |
428 | { | ||
429 | } | ||
430 | |||
431 | void pcm_play_dma_start(const void *addr, size_t size) | ||
551 | { | 432 | { |
552 | p = (unsigned short*)addr; | 433 | p = (unsigned short*)addr; |
553 | p_size = size; | 434 | p_size = size; |
@@ -555,11 +436,19 @@ static void dma_start(const void *addr, size_t size) | |||
555 | pcm_playing = true; | 436 | pcm_playing = true; |
556 | } | 437 | } |
557 | 438 | ||
558 | static void dma_stop(void) | 439 | void pcm_play_dma_stop(void) |
559 | { | 440 | { |
560 | pcm_playing = false; | 441 | pcm_playing = false; |
561 | } | 442 | } |
562 | 443 | ||
444 | void pcm_play_pause_pause(void) | ||
445 | { | ||
446 | } | ||
447 | |||
448 | void pcm_play_pause_unpause(void) | ||
449 | { | ||
450 | } | ||
451 | |||
563 | static inline void fill_dma_buf(int offset) | 452 | static inline void fill_dma_buf(int offset) |
564 | { | 453 | { |
565 | short *l, *r, *lend; | 454 | short *l, *r, *lend; |
@@ -611,8 +500,8 @@ static inline void fill_dma_buf(int offset) | |||
611 | p = tmp_p; | 500 | p = tmp_p; |
612 | if (l >= lend) | 501 | if (l >= lend) |
613 | return; | 502 | return; |
614 | else if (callback_for_more) | 503 | else if (pcm_callback_for_more) |
615 | callback_for_more((unsigned char**)&p, | 504 | pcm_callback_for_more((unsigned char**)&p, |
616 | &p_size); | 505 | &p_size); |
617 | } | 506 | } |
618 | while (p_size); | 507 | while (p_size); |
@@ -647,9 +536,10 @@ unsigned long physical_address(void *p) | |||
647 | void pcm_init(void) | 536 | void pcm_init(void) |
648 | { | 537 | { |
649 | int i; | 538 | int i; |
650 | callback_for_more = NULL; | 539 | |
651 | pcm_playing = false; | 540 | pcm_playing = false; |
652 | pcm_paused = false; | 541 | pcm_paused = false; |
542 | pcm_callback_for_more = NULL; | ||
653 | 543 | ||
654 | memset(dma_buf_left, 0, sizeof(dma_buf_left)); | 544 | memset(dma_buf_left, 0, sizeof(dma_buf_left)); |
655 | memset(dma_buf_right, 0, sizeof(dma_buf_right)); | 545 | memset(dma_buf_right, 0, sizeof(dma_buf_right)); |
@@ -691,271 +581,37 @@ void pcm_init(void) | |||
691 | 581 | ||
692 | void pcm_set_frequency(unsigned int frequency) | 582 | void pcm_set_frequency(unsigned int frequency) |
693 | { | 583 | { |
694 | pcm_freq=frequency; | 584 | (void)frequency; |
585 | pcm_freq = HW_SAMPR_DEFAULT; | ||
695 | } | 586 | } |
696 | size_t pcm_get_bytes_waiting(void) | 587 | size_t pcm_get_bytes_waiting(void) |
697 | { | 588 | { |
698 | return p_size; | 589 | return p_size; |
699 | } | 590 | } |
700 | #endif | 591 | #endif /* CONFIG_CPU == */ |
701 | 592 | ||
702 | void pcm_play_stop(void) | 593 | /* dummy functions for those not actually supporting all this yet */ |
594 | void pcm_apply_settings(bool reset) | ||
703 | { | 595 | { |
704 | if (pcm_playing) { | 596 | (void)reset; |
705 | dma_stop(); | ||
706 | } | ||
707 | } | 597 | } |
708 | 598 | ||
709 | #endif | 599 | void pcm_set_monitor(int monitor) |
710 | |||
711 | void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), | ||
712 | unsigned char* start, size_t size) | ||
713 | { | 600 | { |
714 | callback_for_more = get_more; | 601 | (void)monitor; |
715 | |||
716 | if (!(start && size)) | ||
717 | { | ||
718 | if (get_more) | ||
719 | get_more(&start, &size); | ||
720 | else | ||
721 | return; | ||
722 | } | ||
723 | if (start && size) | ||
724 | { | ||
725 | dma_start(start, size); | ||
726 | if (pcm_paused) { | ||
727 | pcm_paused = false; | ||
728 | pcm_play_pause(false); | ||
729 | } | ||
730 | } | ||
731 | } | 602 | } |
603 | /** **/ | ||
732 | 604 | ||
733 | void pcm_mute(bool mute) | 605 | void pcm_mute(bool mute) |
734 | { | 606 | { |
735 | #ifdef HAVE_UDA1380 | 607 | #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \ |
736 | uda1380_mute(mute); | ||
737 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
738 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) | 608 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) |
739 | wmcodec_mute(mute); | 609 | wmcodec_mute(mute); |
740 | #elif defined(HAVE_TLV320) | ||
741 | tlv320_mute(mute); | ||
742 | #endif | 610 | #endif |
743 | if (mute) | 611 | if (mute) |
744 | sleep(HZ/16); | 612 | sleep(HZ/16); |
745 | } | 613 | } |
746 | 614 | ||
747 | void pcm_play_pause(bool play) | ||
748 | { | ||
749 | bool needs_change = pcm_paused == play; | ||
750 | |||
751 | /* This needs to be done ahead of the rest to prevent infinite | ||
752 | * recursion from dma_start */ | ||
753 | pcm_paused = !play; | ||
754 | if (pcm_playing && needs_change) { | ||
755 | if(play) { | ||
756 | if (pcm_get_bytes_waiting()) { | ||
757 | logf("unpause"); | ||
758 | |||
759 | #ifdef CPU_COLDFIRE | ||
760 | /* Enable the FIFO and force one write to it */ | ||
761 | SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq)); | ||
762 | #ifdef HAVE_SPDIF_OUT | ||
763 | EBU1CONFIG = EBU_DEFPARM; | ||
764 | #endif | ||
765 | DCR0 |= DMA_EEXT | DMA_START; | ||
766 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
767 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) | ||
768 | /* Enable the FIFO and fill it */ | ||
769 | |||
770 | enable_fiq(); | ||
771 | |||
772 | /* Enable playback FIFO */ | ||
773 | #if CONFIG_CPU == PP5020 | ||
774 | IISCONFIG |= 0x20000000; | ||
775 | #elif CONFIG_CPU == PP5002 | ||
776 | IISCONFIG |= 0x4; | ||
777 | #endif | ||
778 | |||
779 | /* Fill the FIFO - we assume there are enough bytes in the | ||
780 | pcm buffer to fill the 32-byte FIFO. */ | ||
781 | while (p_size > 0) { | ||
782 | if (FIFO_FREE_COUNT < 2) { | ||
783 | /* Enable interrupt */ | ||
784 | #if CONFIG_CPU == PP5020 | ||
785 | IISCONFIG |= 0x2; | ||
786 | #elif CONFIG_CPU == PP5002 | ||
787 | IISFIFO_CFG |= (1<<9); | ||
788 | #endif | ||
789 | return; | ||
790 | } | ||
791 | |||
792 | IISFIFO_WR = (*(p++))<<16; | ||
793 | IISFIFO_WR = (*(p++))<<16; | ||
794 | p_size-=4; | ||
795 | } | ||
796 | #elif (CONFIG_CPU == PNX0101 || CONFIG_CPU == S3C2440) /* End wmcodecs */ | ||
797 | /* nothing yet */ | ||
798 | #endif | ||
799 | } else { | ||
800 | #if (CONFIG_CPU != PNX0101 && CONFIG_CPU != S3C2440) | ||
801 | size_t next_size; | ||
802 | unsigned char *next_start; | ||
803 | void (*get_more)(unsigned char**, size_t*) = callback_for_more; | ||
804 | logf("unpause, no data waiting"); | ||
805 | if (get_more) | ||
806 | get_more(&next_start, &next_size); | ||
807 | if (next_start && next_size) | ||
808 | dma_start(next_start, next_size); | ||
809 | else | ||
810 | { | ||
811 | dma_stop(); | ||
812 | logf("unpause attempted, no data"); | ||
813 | } | ||
814 | #endif | ||
815 | } | ||
816 | } else { | ||
817 | logf("pause"); | ||
818 | |||
819 | #ifdef CPU_COLDFIRE | ||
820 | /* Disable DMA peripheral request. */ | ||
821 | DCR0 &= ~DMA_EEXT; | ||
822 | SET_IIS_CONFIG(IIS_RESET | IIS_DEFPARM(pcm_freq)); | ||
823 | #ifdef HAVE_SPDIF_OUT | ||
824 | EBU1CONFIG = IIS_RESET | EBU_DEFPARM; | ||
825 | #endif | ||
826 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
827 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) | ||
828 | #if CONFIG_CPU == PP5020 | ||
829 | /* Disable the interrupt */ | ||
830 | IISCONFIG &= ~0x2; | ||
831 | /* Disable playback FIFO */ | ||
832 | IISCONFIG &= ~0x20000000; | ||
833 | #elif CONFIG_CPU == PP5002 | ||
834 | /* Disable the interrupt */ | ||
835 | IISFIFO_CFG &= ~(1<<9); | ||
836 | /* Disable playback FIFO */ | ||
837 | IISCONFIG &= ~0x4; | ||
838 | #endif | ||
839 | |||
840 | disable_fiq(); | ||
841 | #elif (CONFIG_CPU == PNX0101 || CONFIG_CPU == S3C2440) /* End wmcodecs */ | ||
842 | /* nothing yet */ | ||
843 | #endif | ||
844 | } | ||
845 | } /* pcm_playing && needs_change */ | ||
846 | } | ||
847 | |||
848 | bool pcm_is_playing(void) { | ||
849 | return pcm_playing; | ||
850 | } | ||
851 | |||
852 | bool pcm_is_paused(void) { | ||
853 | return pcm_paused; | ||
854 | } | ||
855 | |||
856 | |||
857 | #if defined(CPU_COLDFIRE) | ||
858 | /* Peaks ahead in the DMA buffer based upon the calling period to | ||
859 | attempt to compensate for the delay. Keeps a moving average of | ||
860 | length four. */ | ||
861 | void pcm_calculate_peaks(int *left, int *right) | ||
862 | { | ||
863 | unsigned long samples; | ||
864 | unsigned long *addr, *end; | ||
865 | long peak_p, peak_n; | ||
866 | |||
867 | static unsigned long last_peak_tick = 0; | ||
868 | static unsigned long frame_period = 0; | ||
869 | |||
870 | /* Throttled peak ahead based on calling period */ | ||
871 | unsigned long period = current_tick - last_peak_tick; | ||
872 | |||
873 | /* Keep reasonable limits on period */ | ||
874 | if (period < 1) | ||
875 | period = 1; | ||
876 | else if (period > HZ/5) | ||
877 | period = HZ/5; | ||
878 | |||
879 | frame_period = (3*frame_period + period) >> 2; | ||
880 | |||
881 | last_peak_tick = current_tick; | ||
882 | |||
883 | if (!pcm_playing || pcm_paused) | ||
884 | { | ||
885 | peak_left = peak_right = 0; | ||
886 | goto peak_done; | ||
887 | } | ||
888 | |||
889 | samples = (BCR0 & 0xffffff) >> 2; | ||
890 | addr = (long *)(SAR0 & ~3); | ||
891 | samples = MIN(frame_period*44100/HZ, samples); | ||
892 | end = addr + samples; | ||
893 | peak_p = peak_n = 0; | ||
894 | |||
895 | if (left && right) | ||
896 | { | ||
897 | if (samples > 0) | ||
898 | { | ||
899 | long peak_rp = 0, peak_rn = 0; | ||
900 | |||
901 | do | ||
902 | { | ||
903 | long value = *addr; | ||
904 | long ch; | ||
905 | |||
906 | ch = value >> 16; | ||
907 | if (ch > peak_p) peak_p = ch; | ||
908 | else if (ch < peak_n) peak_n = ch; | ||
909 | |||
910 | ch = (short)value; | ||
911 | if (ch > peak_rp) peak_rp = ch; | ||
912 | else if (ch < peak_rn) peak_rn = ch; | ||
913 | |||
914 | addr += 4; | ||
915 | } | ||
916 | while (addr < end); | ||
917 | |||
918 | peak_left = MAX(peak_p, -peak_n); | ||
919 | peak_right = MAX(peak_rp, -peak_rn); | ||
920 | } | ||
921 | } | ||
922 | else if (left || right) | ||
923 | { | ||
924 | if (samples > 0) | ||
925 | { | ||
926 | if (left) | ||
927 | { | ||
928 | /* Put left channel in low word */ | ||
929 | addr = (long *)((short *)addr - 1); | ||
930 | end = (long *)((short *)end - 1); | ||
931 | } | ||
932 | |||
933 | do | ||
934 | { | ||
935 | long value = *(short *)addr; | ||
936 | |||
937 | if (value > peak_p) peak_p = value; | ||
938 | else if (value < peak_n) peak_n = value; | ||
939 | |||
940 | addr += 4; | ||
941 | } | ||
942 | while (addr < end); | ||
943 | |||
944 | if (left) | ||
945 | peak_left = MAX(peak_p, -peak_n); | ||
946 | else | ||
947 | peak_right = MAX(peak_p, -peak_n); | ||
948 | } | ||
949 | } | ||
950 | |||
951 | peak_done: | ||
952 | if (left) | ||
953 | *left = peak_left; | ||
954 | |||
955 | if (right) | ||
956 | *right = peak_right; | ||
957 | } | ||
958 | #else | ||
959 | /* | 615 | /* |
960 | * This function goes directly into the DMA buffer to calculate the left and | 616 | * This function goes directly into the DMA buffer to calculate the left and |
961 | * right peak values. To avoid missing peaks it tries to look forward two full | 617 | * right peak values. To avoid missing peaks it tries to look forward two full |
@@ -1037,4 +693,94 @@ void pcm_calculate_peaks(int *left, int *right) | |||
1037 | } | 693 | } |
1038 | #endif | 694 | #endif |
1039 | } | 695 | } |
696 | |||
1040 | #endif /* CPU_COLDFIRE */ | 697 | #endif /* CPU_COLDFIRE */ |
698 | |||
699 | /**************************************************************************** | ||
700 | * Functions that do not require targeted implementation but only a targeted | ||
701 | * interface | ||
702 | */ | ||
703 | |||
704 | /* Common code to pcm_play_data and pcm_play_pause | ||
705 | Returns true if DMA playback was started, else false. */ | ||
706 | bool pcm_play_data_start(pcm_more_callback_type get_more, | ||
707 | unsigned char *start, size_t size) | ||
708 | { | ||
709 | if (!(start && size)) | ||
710 | { | ||
711 | size = 0; | ||
712 | if (get_more) | ||
713 | get_more(&start, &size); | ||
714 | } | ||
715 | |||
716 | if (start && size) | ||
717 | { | ||
718 | pcm_play_dma_start(start, size); | ||
719 | return true; | ||
720 | } | ||
721 | |||
722 | return false; | ||
723 | } | ||
724 | |||
725 | void pcm_play_data(pcm_more_callback_type get_more, | ||
726 | unsigned char *start, size_t size) | ||
727 | { | ||
728 | pcm_callback_for_more = get_more; | ||
729 | |||
730 | if (pcm_play_data_start(get_more, start, size) && pcm_paused) | ||
731 | { | ||
732 | pcm_paused = false; | ||
733 | pcm_play_pause(false); | ||
734 | } | ||
735 | } | ||
736 | |||
737 | void pcm_play_pause(bool play) | ||
738 | { | ||
739 | bool needs_change = pcm_paused == play; | ||
740 | |||
741 | /* This needs to be done ahead of the rest to prevent infinite | ||
742 | recursion from pcm_play_data */ | ||
743 | pcm_paused = !play; | ||
744 | |||
745 | if (pcm_playing && needs_change) | ||
746 | { | ||
747 | if (play) | ||
748 | { | ||
749 | if (pcm_get_bytes_waiting()) | ||
750 | { | ||
751 | logf("unpause"); | ||
752 | pcm_play_pause_unpause(); | ||
753 | } | ||
754 | else | ||
755 | { | ||
756 | logf("unpause, no data waiting"); | ||
757 | if (!pcm_play_data_start(pcm_callback_for_more, NULL, 0)) | ||
758 | { | ||
759 | pcm_play_dma_stop(); | ||
760 | logf("unpause attempted, no data"); | ||
761 | } | ||
762 | } | ||
763 | } | ||
764 | else | ||
765 | { | ||
766 | logf("pause"); | ||
767 | pcm_play_pause_pause(); | ||
768 | } | ||
769 | } /* pcm_playing && needs_change */ | ||
770 | } | ||
771 | |||
772 | void pcm_play_stop(void) | ||
773 | { | ||
774 | if (pcm_playing) | ||
775 | pcm_play_dma_stop(); | ||
776 | } | ||
777 | |||
778 | bool pcm_is_playing(void) | ||
779 | { | ||
780 | return pcm_playing; | ||
781 | } | ||
782 | |||
783 | bool pcm_is_paused(void) | ||
784 | { | ||
785 | return pcm_paused; | ||
786 | } | ||
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index 2785d4b1b1..25f1f1ef64 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c | |||
@@ -16,199 +16,238 @@ | |||
16 | * KIND, either express or implied. | 16 | * KIND, either express or implied. |
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | 19 | #include "system.h" | |
20 | #include "config.h" | 20 | #include "kernel.h" |
21 | #include "debug.h" | 21 | #include "logf.h" |
22 | #include "panic.h" | 22 | #include "panic.h" |
23 | #include "thread.h" | 23 | #include "thread.h" |
24 | |||
25 | #include <kernel.h> | ||
26 | #include <stdio.h> | ||
27 | #include <string.h> | ||
28 | #include <stdarg.h> | ||
29 | #include <string.h> | 24 | #include <string.h> |
30 | 25 | #include "ata.h" | |
31 | #include "cpu.h" | 26 | #include "usb.h" |
32 | #include "i2c.h" | 27 | #if defined(HAVE_UDA1380) |
33 | #include "power.h" | ||
34 | #ifdef HAVE_UDA1380 | ||
35 | #include "uda1380.h" | 28 | #include "uda1380.h" |
36 | #endif | 29 | #include "general.h" |
37 | #ifdef HAVE_TLV320 | 30 | #elif defined(HAVE_TLV320) |
38 | #include "tlv320.h" | 31 | #include "tlv320.h" |
39 | #endif | 32 | #endif |
40 | #include "system.h" | ||
41 | #include "usb.h" | ||
42 | |||
43 | #include "buffer.h" | 33 | #include "buffer.h" |
44 | #include "audio.h" | 34 | #include "audio.h" |
45 | #include "button.h" | ||
46 | #include "file.h" | ||
47 | #include "sprintf.h" | ||
48 | #include "logf.h" | ||
49 | #include "button.h" | ||
50 | #include "lcd.h" | ||
51 | #include "lcd-remote.h" | ||
52 | #include "pcm_playback.h" | ||
53 | #include "sound.h" | 35 | #include "sound.h" |
54 | #include "id3.h" | 36 | #include "id3.h" |
55 | #include "pcm_record.h" | ||
56 | |||
57 | extern int boost_counter; /* used for boost check */ | ||
58 | 37 | ||
59 | /***************************************************************************/ | 38 | /***************************************************************************/ |
60 | 39 | ||
40 | /** | ||
41 | * APIs implemented in the target tree portion: | ||
42 | * Public - | ||
43 | * pcm_init_recording | ||
44 | * pcm_close_recording | ||
45 | * pcm_rec_mux | ||
46 | * Semi-private - | ||
47 | * pcm_rec_dma_start | ||
48 | * pcm_rec_dma_stop | ||
49 | */ | ||
50 | |||
51 | /** These items may be implemented target specifically or need to | ||
52 | be shared semi-privately **/ | ||
53 | |||
54 | /* the registered callback function for when more data is available */ | ||
55 | pcm_more_callback_type pcm_callback_more_ready = NULL; | ||
56 | /* DMA transfer in is currently active */ | ||
57 | bool pcm_recording = false; | ||
58 | |||
59 | /* APIs implemented in the target-specific portion */ | ||
60 | void pcm_rec_dma_start(const void *addr, size_t size); | ||
61 | void pcm_rec_dma_stop(void); | ||
62 | |||
63 | /** General recording state **/ | ||
61 | static bool is_recording; /* We are recording */ | 64 | static bool is_recording; /* We are recording */ |
62 | static bool is_paused; /* We have paused */ | 65 | static bool is_paused; /* We have paused */ |
66 | static bool is_stopping; /* We are currently stopping */ | ||
63 | static bool is_error; /* An error has occured */ | 67 | static bool is_error; /* An error has occured */ |
64 | 68 | ||
65 | static unsigned long num_rec_bytes; /* Num bytes recorded */ | 69 | /** Stats on encoded data for current file **/ |
66 | static unsigned long num_file_bytes; /* Num bytes written to current file */ | 70 | static size_t num_rec_bytes; /* Num bytes recorded */ |
67 | static int error_count; /* Number of DMA errors */ | 71 | static unsigned long num_rec_samples; /* Number of PCM samples recorded */ |
68 | static unsigned long num_pcm_samples; /* Num pcm samples written to current file */ | ||
69 | |||
70 | static long record_start_time; /* current_tick when recording was started */ | ||
71 | static long pause_start_time; /* current_tick when pause was started */ | ||
72 | static unsigned int sample_rate; /* Sample rate at time of recording start */ | ||
73 | static int rec_source; /* Current recording source */ | ||
74 | 72 | ||
75 | static int wav_file; | 73 | /** Stats on encoded data for all files from start to stop **/ |
76 | static char recording_filename[MAX_PATH]; | 74 | static unsigned long long accum_rec_bytes; /* total size written to chunks */ |
75 | static unsigned long long accum_pcm_samples; /* total pcm count processed */ | ||
77 | 76 | ||
78 | static volatile bool init_done, close_done, record_done; | 77 | /* Keeps data about current file and is sent as event data for codec */ |
79 | static volatile bool stop_done, pause_done, resume_done, new_file_done; | 78 | static struct enc_file_event_data rec_fdata IDATA_ATTR = |
80 | 79 | { | |
81 | static int peak_left, peak_right; | 80 | .chunk = NULL, |
81 | .new_enc_size = 0, | ||
82 | .new_num_pcm = 0, | ||
83 | .rec_file = -1, | ||
84 | .num_pcm_samples = 0 | ||
85 | }; | ||
82 | 86 | ||
83 | #ifdef IAUDIO_X5 | 87 | /** These apply to current settings **/ |
84 | #define SET_IIS_PLAY(x) IIS1CONFIG = (x); | 88 | static int rec_source; /* current rec_source setting */ |
85 | #define SET_IIS_REC(x) IIS1CONFIG = (x); | 89 | static int rec_frequency; /* current frequency setting */ |
86 | #else | 90 | static unsigned long sample_rate; /* Sample rate in HZ */ |
87 | #define SET_IIS_PLAY(x) IIS2CONFIG = (x); | 91 | static int num_channels; /* Current number of channels */ |
88 | #define SET_IIS_REC(x) IIS1CONFIG = (x); | 92 | static struct encoder_config enc_config; /* Current encoder configuration */ |
89 | #endif | ||
90 | 93 | ||
91 | /**************************************************************************** | 94 | /**************************************************************************** |
92 | use 2 circular buffers of same size: | 95 | use 2 circular buffers: |
93 | rec_buffer=DMA output buffer: chunks (8192 Bytes) of raw pcm audio data | 96 | pcm_buffer=DMA output buffer: chunks (8192 Bytes) of raw pcm audio data |
94 | enc_buffer=encoded audio buffer: storage for encoder output data | 97 | enc_buffer=encoded audio buffer: storage for encoder output data |
95 | 98 | ||
96 | Flow: | 99 | Flow: |
97 | 1. when entering recording_screen DMA feeds the ringbuffer rec_buffer | 100 | 1. when entering recording_screen DMA feeds the ringbuffer pcm_buffer |
98 | 2. if enough pcm data are available the encoder codec does encoding of pcm | 101 | 2. if enough pcm data are available the encoder codec does encoding of pcm |
99 | chunks (4-8192 Bytes) into ringbuffer enc_buffer in codec_thread | 102 | chunks (4-8192 Bytes) into ringbuffer enc_buffer in codec_thread |
100 | 3. pcmrec_callback detects enc_buffer 'near full' and writes data to disk | 103 | 3. pcmrec_callback detects enc_buffer 'near full' and writes data to disk |
101 | 104 | ||
102 | Functions calls: | 105 | Functions calls (basic encoder steps): |
103 | 1.main: codec_load_encoder(); start the encoder | 106 | 1.main: audio_load_encoder(); start the encoder |
104 | 2.encoder: enc_get_inputs(); get encoder buffsize, mono/stereo, quality | 107 | 2.encoder: enc_get_inputs(); get encoder recording settings |
105 | 3.encoder: enc_set_parameters(); set the encoder parameters (max.chunksize) | 108 | 3.encoder: enc_set_parameters(); set the encoder parameters |
106 | 4.encoder: enc_get_wav_data(); get n bytes of unprocessed pcm data | 109 | 4.encoder: enc_get_pcm_data(); get n bytes of unprocessed pcm data |
107 | 5.encoder: enc_wavbuf_near_empty();if true: reduce cpu_boost | 110 | 5.encoder: enc_pcm_buf_near_empty(); if 1: reduce cpu_boost |
108 | 6.encoder: enc_alloc_chunk(); get a ptr to next enc chunk | 111 | 6.encoder: enc_alloc_chunk(); get a ptr to next enc chunk |
109 | 7.encoder: <process enc chunk> compress and store data to enc chunk | 112 | 7.encoder: <process enc chunk> compress and store data to enc chunk |
110 | 8.encoder: enc_free_chunk(); inform main about chunk process finished | 113 | 8.encoder: enc_free_chunk(); inform main about chunk process finished |
111 | 9.encoder: repeat 4. to 8. | 114 | 9.encoder: repeat 4. to 8. |
112 | A.main: enc_set_header_callback(); create the current format header (file) | 115 | A.pcmrec: enc_events_callback(); called for certain events |
113 | ****************************************************************************/ | 116 | ****************************************************************************/ |
114 | #define NUM_CHUNKS 256 /* Power of 2 */ | 117 | |
115 | #define CHUNK_SIZE 8192 /* Power of 2 */ | 118 | /** buffer parameters where incoming PCM data is placed **/ |
116 | #define MAX_FEED_SIZE 20000 /* max pcm size passed to encoder */ | 119 | #define PCM_NUM_CHUNKS 256 /* Power of 2 */ |
117 | #define CHUNK_MASK (NUM_CHUNKS * CHUNK_SIZE - 1) | 120 | #define PCM_CHUNK_SIZE 8192 /* Power of 2 */ |
118 | #define WRITE_THRESHOLD (44100 * 5 / enc_samp_per_chunk) /* 5sec */ | 121 | #define PCM_CHUNK_MASK (PCM_NUM_CHUNKS*PCM_CHUNK_SIZE - 1) |
119 | #define GET_CHUNK(x) (long*)(&rec_buffer[x]) | 122 | |
120 | #define GET_ENC_CHUNK(x) (long*)(&enc_buffer[enc_chunk_size*(x)]) | 123 | #define GET_PCM_CHUNK(offset) ((long *)(pcm_buffer + (offset))) |
121 | 124 | #define GET_ENC_CHUNK(index) ENC_CHUNK_HDR(enc_buffer + enc_chunk_size*(index)) | |
122 | static int audio_enc_id; /* current encoder id */ | 125 | |
123 | static unsigned char *rec_buffer; /* Circular recording buffer */ | 126 | #define INC_ENC_INDEX(index) \ |
124 | static unsigned char *enc_buffer; /* Circular encoding buffer */ | 127 | { if (++index >= enc_num_chunks) index = 0; } |
125 | static unsigned char *enc_head_buffer; /* encoder header buffer */ | 128 | #define DEC_ENC_INDEX(index) \ |
126 | static int enc_head_size; /* used size in header buffer */ | 129 | { if (--index < 0) index = enc_num_chunks - 1; } |
127 | static int write_pos; /* Current chunk pos for DMA writing */ | 130 | |
128 | static int read_pos; /* Current chunk pos for encoding */ | 131 | static size_t rec_buffer_size; /* size of available buffer */ |
129 | static long pre_record_ticks;/* pre-record time expressed in ticks */ | 132 | static unsigned char *pcm_buffer; /* circular recording buffer */ |
130 | static int enc_wr_index; /* Current encoding chunk write index */ | 133 | static unsigned char *enc_buffer; /* circular encoding buffer */ |
131 | static int enc_rd_index; /* Current encoding chunk read index */ | 134 | static volatile int dma_wr_pos; /* current DMA write pos */ |
132 | static int enc_chunk_size; /* maximum encoder chunk size */ | 135 | static int pcm_rd_pos; /* current PCM read pos */ |
136 | static volatile bool dma_lock; /* lock DMA write position */ | ||
137 | static unsigned long pre_record_ticks;/* pre-record time in ticks */ | ||
138 | static int enc_wr_index; /* encoder chunk write index */ | ||
139 | static int enc_rd_index; /* encoder chunk read index */ | ||
133 | static int enc_num_chunks; /* number of chunks in ringbuffer */ | 140 | static int enc_num_chunks; /* number of chunks in ringbuffer */ |
134 | static int enc_buffer_size; /* encode buffer size */ | 141 | static size_t enc_chunk_size; /* maximum encoder chunk size */ |
135 | static int enc_channels; /* 1=mono 2=stereo */ | 142 | static size_t enc_data_size; /* maximum data size for encoder */ |
136 | static int enc_quality; /* mp3: 64,96,128,160,192,320 kBit */ | 143 | static unsigned long enc_sample_rate; /* sample rate used by encoder */ |
137 | static int enc_samp_per_chunk;/* pcm samples per encoder chunk */ | ||
138 | static bool wav_queue_empty; /* all wav chunks processed? */ | 144 | static bool wav_queue_empty; /* all wav chunks processed? */ |
139 | static unsigned long avrg_bit_rate; /* average bit rates from chunks */ | ||
140 | static unsigned long curr_bit_rate; /* cumulated bit rates from chunks */ | ||
141 | static unsigned long curr_chunk_cnt; /* number of processed chunks */ | ||
142 | 145 | ||
143 | void (*enc_set_header_callback)(void *head_buffer, int head_size, | 146 | /** file flushing **/ |
144 | int num_pcm_samples, bool is_file_header); | 147 | static int write_threshold; /* max chunk limit for data flush */ |
148 | static int panic_threshold; /* boost thread prio when here */ | ||
149 | static int spinup_time = -1;/* last ata_spinup_time */ | ||
150 | |||
151 | /** encoder events **/ | ||
152 | static void (*enc_events_callback)(enum enc_events event, void *data); | ||
153 | |||
154 | /** Path queue for files to write **/ | ||
155 | #define FNQ_MIN_NUM_PATHS 16 /* minimum number of paths to hold */ | ||
156 | static unsigned char *fn_queue; /* pointer to first filename */ | ||
157 | static ssize_t fnq_size; /* capacity of queue in bytes */ | ||
158 | static int fnq_rd_pos; /* current read position */ | ||
159 | static int fnq_wr_pos; /* current write position */ | ||
145 | 160 | ||
146 | /***************************************************************************/ | 161 | /***************************************************************************/ |
147 | 162 | ||
148 | static struct event_queue pcmrec_queue; | 163 | static struct event_queue pcmrec_queue; |
149 | static long pcmrec_stack[2*DEFAULT_STACK_SIZE/sizeof(long)]; | 164 | static long pcmrec_stack[3*DEFAULT_STACK_SIZE/sizeof(long)]; |
150 | static const char pcmrec_thread_name[] = "pcmrec"; | 165 | static const char pcmrec_thread_name[] = "pcmrec"; |
151 | 166 | ||
152 | static void pcmrec_thread(void); | 167 | static void pcmrec_thread(void); |
153 | static void pcmrec_dma_start(void); | ||
154 | static void pcmrec_dma_stop(void); | ||
155 | static void close_wave(void); | ||
156 | 168 | ||
157 | /* Event IDs */ | 169 | /* Event values which are also single-bit flags */ |
158 | #define PCMREC_INIT 1 /* Enable recording */ | 170 | #define PCMREC_INIT 0x00000001 /* enable recording */ |
159 | #define PCMREC_CLOSE 2 | 171 | #define PCMREC_CLOSE 0x00000002 |
160 | 172 | ||
161 | #define PCMREC_START 3 /* Start a new recording */ | 173 | #define PCMREC_START 0x00000004 /* start recording (when stopped) */ |
162 | #define PCMREC_STOP 4 /* Stop the current recording */ | 174 | #define PCMREC_STOP 0x00000008 /* stop the current recording */ |
163 | #define PCMREC_PAUSE 10 | 175 | #define PCMREC_PAUSE 0x00000010 /* pause the current recording */ |
164 | #define PCMREC_RESUME 11 | 176 | #define PCMREC_RESUME 0x00000020 /* resume the current recording */ |
165 | #define PCMREC_NEW_FILE 12 | 177 | #define PCMREC_NEW_FILE 0x00000040 /* start new file (when recording) */ |
166 | #define PCMREC_SET_GAIN 13 | 178 | #define PCMREC_SET_GAIN 0x00000080 |
179 | #define PCMREC_FLUSH_NUM 0x00000100 /* flush a number of files out */ | ||
180 | #define PCMREC_FINISH_STOP 0x00000200 /* finish the stopping recording */ | ||
167 | 181 | ||
168 | /*******************************************************************/ | 182 | /* mask for signaling events */ |
169 | /* Functions that are not executing in the pcmrec_thread first */ | 183 | static volatile long pcm_thread_event_mask; |
170 | /*******************************************************************/ | ||
171 | 184 | ||
172 | /* Creates pcmrec_thread */ | 185 | static void pcm_thread_sync_post(long event, void *data) |
173 | void pcm_rec_init(void) | ||
174 | { | 186 | { |
175 | queue_init(&pcmrec_queue, true); | 187 | pcm_thread_event_mask &= ~event; |
176 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), | 188 | queue_post(&pcmrec_queue, event, data); |
177 | pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING)); | 189 | while(!(event & pcm_thread_event_mask)) |
178 | } | 190 | yield(); |
191 | } /* pcm_thread_sync_post */ | ||
179 | 192 | ||
193 | static inline void pcm_thread_signal_event(long event) | ||
194 | { | ||
195 | pcm_thread_event_mask |= event; | ||
196 | } /* pcm_thread_signal_event */ | ||
180 | 197 | ||
181 | int audio_get_encoder_id(void) | 198 | static inline void pcm_thread_unsignal_event(long event) |
182 | { | 199 | { |
183 | return audio_enc_id; | 200 | pcm_thread_event_mask &= ~event; |
184 | } | 201 | } /* pcm_thread_unsignal_event */ |
185 | 202 | ||
186 | /* Initializes recording: | 203 | static inline bool pcm_thread_event_state(long signaled, long unsignaled) |
187 | * - Set up the UDA1380/TLV320 for recording | 204 | { |
188 | * - Prepare for DMA transfers | 205 | return ((signaled | unsignaled) & pcm_thread_event_mask) == signaled; |
189 | */ | 206 | } /* pcm_thread_event_state */ |
190 | 207 | ||
191 | void audio_init_recording(unsigned int buffer_offset) | 208 | static void pcm_thread_wait_for_stop(void) |
192 | { | 209 | { |
193 | (void)buffer_offset; | 210 | if (is_stopping) |
211 | { | ||
212 | logf("waiting for stop to finish"); | ||
213 | while (is_stopping) | ||
214 | yield(); | ||
215 | } | ||
216 | } /* pcm_thread_wait_for_stop */ | ||
194 | 217 | ||
195 | init_done = false; | 218 | /*******************************************************************/ |
196 | queue_post(&pcmrec_queue, PCMREC_INIT, 0); | 219 | /* Functions that are not executing in the pcmrec_thread first */ |
220 | /*******************************************************************/ | ||
197 | 221 | ||
198 | while(!init_done) | 222 | /* Callback for when more data is ready */ |
199 | sleep_thread(1); | 223 | static void pcm_rec_have_more(unsigned char **data, size_t *size) |
200 | } | ||
201 | |||
202 | void audio_close_recording(void) | ||
203 | { | 224 | { |
204 | close_done = false; | 225 | if (*size != 0) |
205 | queue_post(&pcmrec_queue, PCMREC_CLOSE, 0); | 226 | { |
227 | /* some error condition */ | ||
228 | if (*size == DMA_REC_ERROR_DMA) | ||
229 | { | ||
230 | /* Flush recorded data to disk and stop recording */ | ||
231 | queue_post(&pcmrec_queue, PCMREC_STOP, NULL); | ||
232 | return; | ||
233 | } | ||
234 | /* else try again next transmission */ | ||
235 | } | ||
236 | else if (!dma_lock) | ||
237 | { | ||
238 | /* advance write position */ | ||
239 | dma_wr_pos = (dma_wr_pos + PCM_CHUNK_SIZE) & PCM_CHUNK_MASK; | ||
240 | } | ||
206 | 241 | ||
207 | while(!close_done) | 242 | *data = (unsigned char *)GET_PCM_CHUNK(dma_wr_pos); |
208 | sleep_thread(1); | 243 | *size = PCM_CHUNK_SIZE; |
244 | } /* pcm_rec_have_more */ | ||
209 | 245 | ||
210 | audio_remove_encoder(); | 246 | /** pcm_rec_* group **/ |
211 | } | 247 | void pcm_rec_error_clear(void) |
248 | { | ||
249 | is_error = false; | ||
250 | } /* pcm_rec_error_clear */ | ||
212 | 251 | ||
213 | unsigned long pcm_rec_status(void) | 252 | unsigned long pcm_rec_status(void) |
214 | { | 253 | { |
@@ -216,165 +255,223 @@ unsigned long pcm_rec_status(void) | |||
216 | 255 | ||
217 | if (is_recording) | 256 | if (is_recording) |
218 | ret |= AUDIO_STATUS_RECORD; | 257 | ret |= AUDIO_STATUS_RECORD; |
258 | |||
219 | if (is_paused) | 259 | if (is_paused) |
220 | ret |= AUDIO_STATUS_PAUSE; | 260 | ret |= AUDIO_STATUS_PAUSE; |
261 | |||
221 | if (is_error) | 262 | if (is_error) |
222 | ret |= AUDIO_STATUS_ERROR; | 263 | ret |= AUDIO_STATUS_ERROR; |
223 | if (!is_recording && pre_record_ticks && init_done && !close_done) | 264 | |
265 | if (!is_recording && pre_record_ticks && | ||
266 | pcm_thread_event_state(PCMREC_INIT, PCMREC_CLOSE)) | ||
224 | ret |= AUDIO_STATUS_PRERECORD; | 267 | ret |= AUDIO_STATUS_PRERECORD; |
225 | 268 | ||
226 | return ret; | 269 | return ret; |
227 | } | 270 | } /* pcm_rec_status */ |
228 | 271 | ||
229 | int pcm_rec_current_bitrate(void) | 272 | int pcm_rec_current_bitrate(void) |
230 | { | 273 | { |
231 | return avrg_bit_rate; | 274 | if (accum_pcm_samples == 0) |
232 | } | 275 | return 0; |
233 | 276 | ||
234 | unsigned long audio_recorded_time(void) | 277 | return (int)(8*accum_rec_bytes*enc_sample_rate / (1000*accum_pcm_samples)); |
278 | } /* pcm_rec_current_bitrate */ | ||
279 | |||
280 | int pcm_rec_encoder_afmt(void) | ||
235 | { | 281 | { |
236 | if (is_recording) | 282 | return enc_config.afmt; |
283 | } /* pcm_rec_encoder_afmt */ | ||
284 | |||
285 | int pcm_rec_rec_format(void) | ||
237 | { | 286 | { |
238 | if (is_paused) | 287 | return afmt_rec_format[enc_config.afmt]; |
239 | return pause_start_time - record_start_time; | 288 | } /* pcm_rec_rec_format */ |
240 | else | ||
241 | return current_tick - record_start_time; | ||
242 | } | ||
243 | 289 | ||
244 | return 0; | 290 | unsigned long pcm_rec_sample_rate(void) |
245 | } | 291 | { |
292 | /* Which is better ?? */ | ||
293 | #if 0 | ||
294 | return enc_sample_rate; | ||
295 | #endif | ||
296 | return sample_rate; | ||
297 | } /* audio_get_sample_rate */ | ||
246 | 298 | ||
247 | unsigned long audio_num_recorded_bytes(void) | 299 | /** |
300 | * Creates pcmrec_thread | ||
301 | */ | ||
302 | void pcm_rec_init(void) | ||
248 | { | 303 | { |
249 | if (is_recording) | 304 | queue_init(&pcmrec_queue, true); |
250 | return num_rec_bytes; | 305 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), |
306 | pcmrec_thread_name, PRIORITY_RECORDING); | ||
307 | } /* pcm_rec_init */ | ||
251 | 308 | ||
309 | /** audio_* group **/ | ||
310 | |||
311 | void audio_init_recording(unsigned int buffer_offset) | ||
312 | { | ||
313 | (void)buffer_offset; | ||
314 | pcm_thread_wait_for_stop(); | ||
315 | pcm_thread_sync_post(PCMREC_INIT, NULL); | ||
316 | } /* audio_init_recording */ | ||
317 | |||
318 | void audio_close_recording(void) | ||
319 | { | ||
320 | pcm_thread_wait_for_stop(); | ||
321 | pcm_thread_sync_post(PCMREC_CLOSE, NULL); | ||
322 | /* reset pcm to defaults (playback only) */ | ||
323 | pcm_set_frequency(-1); | ||
324 | pcm_set_monitor(-1); | ||
325 | pcm_set_rec_source(-1); | ||
326 | #ifdef HAVE_TLV320 | ||
327 | /* tlv320 screeches if left at 88.2 with no inputs */ | ||
328 | pcm_apply_settings(true); | ||
329 | #endif | ||
330 | audio_remove_encoder(); | ||
331 | } /* audio_close_recording */ | ||
332 | |||
333 | unsigned long audio_recorded_time(void) | ||
334 | { | ||
335 | if (!is_recording || enc_sample_rate == 0) | ||
252 | return 0; | 336 | return 0; |
253 | } | ||
254 | 337 | ||
255 | #ifdef HAVE_SPDIF_IN | 338 | /* return actual recorded time a la encoded data even if encoder rate |
256 | /* Only the last six of these are standard rates, but all sample rates are | 339 | doesn't match the pcm rate */ |
257 | * possible, so we support some other common ones as well. | 340 | return (long)(HZ*(unsigned long long)num_rec_samples / enc_sample_rate); |
258 | */ | 341 | } /* audio_recorded_time */ |
259 | static unsigned long spdif_sample_rates[] = { | ||
260 | 8000, 11025, 12000, 16000, 22050, 24000, | ||
261 | 32000, 44100, 48000, 64000, 88200, 96000 | ||
262 | }; | ||
263 | 342 | ||
264 | /* Return SPDIF sample rate. Since we base our reading on the actual SPDIF | 343 | unsigned long audio_num_recorded_bytes(void) |
265 | * sample rate (which might be a bit inaccurate), we round off to the closest | ||
266 | * sample rate that is supported by SPDIF. | ||
267 | */ | ||
268 | unsigned long audio_get_spdif_sample_rate(void) | ||
269 | { | 344 | { |
270 | int i = 0; | 345 | if (!is_recording) |
271 | unsigned long measured_rate; | 346 | return 0; |
272 | const int upper_bound = sizeof(spdif_sample_rates)/sizeof(long) - 1; | 347 | |
348 | return num_rec_bytes; | ||
349 | } /* audio_num_recorded_bytes */ | ||
273 | 350 | ||
351 | #ifdef HAVE_SPDIF_IN | ||
352 | /* Return current SPDIF sample rate */ | ||
353 | static unsigned long measure_spdif_sample_rate(void) | ||
354 | { | ||
274 | /* The following formula is specified in MCF5249 user's manual section | 355 | /* The following formula is specified in MCF5249 user's manual section |
275 | * 17.6.1. The 3*(1 << 13) part will need changing if the setup of the | 356 | * 17.6.1. The 128 divide is because of the fact that the SPDIF clock is |
276 | * PHASECONFIG register is ever changed. The 128 divide is because of the | 357 | * the sample rate times 128. Keep "3*(1 << 13)" part in sync with |
277 | * fact that the SPDIF clock is the sample rate times 128. | 358 | * PHASECONFIG setup in pcm_init_recording in pcm-coldfire.c. |
278 | */ | 359 | */ |
279 | measured_rate = (unsigned long)((unsigned long long)FREQMEAS*CPU_FREQ/ | 360 | return (unsigned long)((unsigned long long)FREQMEAS*CPU_FREQ / |
280 | ((1 << 15)*3*(1 << 13))/128); | 361 | ((1 << 15)*3*(1 << 13))/128); |
281 | /* Find which SPDIF sample rate we're closest to. */ | 362 | } /* measure_spdif_sample_rate */ |
282 | while (spdif_sample_rates[i] < measured_rate && i < upper_bound) ++i; | ||
283 | if (i > 0 && i < upper_bound) | ||
284 | { | ||
285 | long diff1 = measured_rate - spdif_sample_rates[i - 1]; | ||
286 | long diff2 = spdif_sample_rates[i] - measured_rate; | ||
287 | 363 | ||
288 | if (diff2 > diff1) --i; | 364 | /** |
289 | } | 365 | * Return SPDIF sample rate index in audio_master_sampr_list. Since we base |
290 | return i; | 366 | * our reading on the actual SPDIF sample rate (which might be a bit |
291 | } | 367 | * inaccurate), we round off to the closest sample rate that is supported by |
292 | #endif | 368 | * SPDIF. |
369 | */ | ||
370 | int audio_get_spdif_sample_rate(void) | ||
371 | { | ||
372 | unsigned long measured_rate = measure_spdif_sample_rate(); | ||
373 | /* Find which SPDIF sample rate we're closest to. */ | ||
374 | return round_value_to_list32(measured_rate, audio_master_sampr_list, | ||
375 | SAMPR_NUM_FREQ, false); | ||
376 | } /* audio_get_spdif_sample_rate */ | ||
293 | 377 | ||
294 | #if 0 | ||
295 | /* not needed atm */ | ||
296 | #ifdef HAVE_SPDIF_POWER | 378 | #ifdef HAVE_SPDIF_POWER |
297 | static bool spdif_power_setting; | 379 | static bool spdif_power_setting; |
298 | 380 | ||
299 | void audio_set_spdif_power_setting(bool on) | 381 | void audio_set_spdif_power_setting(bool on) |
300 | { | 382 | { |
301 | spdif_power_setting = on; | 383 | spdif_power_setting = on; |
302 | } | 384 | } /* audio_set_spdif_power_setting */ |
385 | |||
386 | bool audio_get_spdif_power_setting(void) | ||
387 | { | ||
388 | return spdif_power_setting; | ||
389 | } /* audio_get_spdif_power_setting */ | ||
303 | #endif | 390 | #endif |
391 | |||
392 | void audio_spdif_set_monitor(int monitor_spdif) | ||
393 | { | ||
394 | EBU1CONFIG = 0x800; /* Reset before reprogram */ | ||
395 | |||
396 | if (monitor_spdif > 0) | ||
397 | { | ||
398 | #ifdef HAVE_SPDIF_POWER | ||
399 | EBU1CONFIG = spdif_power_setting ? (1 << 2) : 0; | ||
400 | /* Input source is EBUin1, Feed-through monitoring if desired */ | ||
401 | #else | ||
402 | EBU1CONFIG = (1 << 2); | ||
403 | /* Input source is EBUin1, Feed-through monitoring */ | ||
304 | #endif | 404 | #endif |
405 | } | ||
406 | else if (monitor_spdif == 0) | ||
407 | { | ||
408 | /* SCLK2, TXSRC = IIS1recv, validity, normal operation */ | ||
409 | EBU1CONFIG = (7 << 12) | (4 << 8) | (1 << 5) | (5 << 2); | ||
410 | } | ||
411 | } /* audio_spdif_set_monitor */ | ||
412 | |||
413 | #endif /* HAVE_SPDIF_IN */ | ||
305 | 414 | ||
306 | /** | 415 | /** |
307 | * Sets recording parameters | 416 | * Sets recording parameters |
308 | * | ||
309 | * This functions starts feeding the CPU with audio data over the I2S bus | ||
310 | */ | 417 | */ |
311 | void audio_set_recording_options(int frequency, int quality, | 418 | void audio_set_recording_options(struct audio_recording_options *options) |
312 | int source, int channel_mode, | ||
313 | bool editable, int prerecord_time) | ||
314 | { | 419 | { |
315 | /* TODO: */ | 420 | pcm_thread_wait_for_stop(); |
316 | (void)editable; | ||
317 | 421 | ||
318 | /* NOTE: Coldfire UDA based recording does not yet support anything other | 422 | /* stop DMA transfer */ |
319 | * than 44.1kHz sampling rate, so we limit it to that case here now. SPDIF | 423 | dma_lock = true; |
320 | * based recording will overwrite this value with the proper sample rate in | 424 | pcm_stop_recording(); |
321 | * audio_record(), and will not be affected by this. | ||
322 | */ | ||
323 | frequency = 44100; | ||
324 | enc_quality = quality; | ||
325 | rec_source = source; | ||
326 | enc_channels = channel_mode == CHN_MODE_MONO ? 1 : 2; | ||
327 | pre_record_ticks = prerecord_time * HZ; | ||
328 | 425 | ||
329 | switch (source) | 426 | rec_frequency = options->rec_frequency; |
330 | { | 427 | rec_source = options->rec_source; |
331 | case AUDIO_SRC_MIC: | 428 | num_channels = options->rec_channels == 1 ? 1 : 2; |
332 | case AUDIO_SRC_LINEIN: | 429 | pre_record_ticks = options->rec_prerecord_time * HZ; |
333 | #ifdef HAVE_FMRADIO_IN | 430 | enc_config = options->enc_config; |
334 | case AUDIO_SRC_FMRADIO: | 431 | enc_config.afmt = rec_format_afmt[enc_config.rec_format]; |
335 | #endif | ||
336 | /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ | ||
337 | DATAINCONTROL = 0xc020; | ||
338 | break; | ||
339 | 432 | ||
340 | #ifdef HAVE_SPDIF_IN | 433 | #ifdef HAVE_SPDIF_IN |
341 | case AUDIO_SRC_SPDIF: | 434 | if (rec_source == AUDIO_SRC_SPDIF) |
342 | /* Int. when 6 samples in FIFO. PDIR2 source = ebu1RcvData */ | 435 | { |
343 | DATAINCONTROL = 0xc038; | 436 | /* must measure SPDIF sample rate before configuring codecs */ |
344 | break; | 437 | unsigned long sr = measure_spdif_sample_rate(); |
345 | #endif /* HAVE_SPDIF_IN */ | 438 | /* round to master list for SPDIF rate */ |
439 | int index = round_value_to_list32(sr, audio_master_sampr_list, | ||
440 | SAMPR_NUM_FREQ, false); | ||
441 | sample_rate = audio_master_sampr_list[index]; | ||
442 | /* round to HW playback rates for monitoring */ | ||
443 | index = round_value_to_list32(sr, hw_freq_sampr, | ||
444 | HW_NUM_FREQ, false); | ||
445 | pcm_set_frequency(hw_freq_sampr[index]); | ||
446 | /* encoders with a limited number of rates do their own rounding */ | ||
447 | } | ||
448 | else | ||
449 | #endif | ||
450 | { | ||
451 | /* set sample rate from frequency selection */ | ||
452 | sample_rate = rec_freq_sampr[rec_frequency]; | ||
453 | pcm_set_frequency(sample_rate); | ||
346 | } | 454 | } |
347 | 455 | ||
348 | sample_rate = frequency; | 456 | pcm_set_monitor(rec_source); |
349 | 457 | pcm_set_rec_source(rec_source); | |
350 | /* Monitoring: route the signals through the coldfire audio interface. */ | ||
351 | 458 | ||
352 | SET_IIS_PLAY(0x800); /* Reset before reprogram */ | 459 | /* apply pcm settings to hardware */ |
460 | pcm_apply_settings(true); | ||
353 | 461 | ||
354 | #ifdef HAVE_SPDIF_IN | 462 | if (audio_load_encoder(enc_config.afmt)) |
355 | if (source == AUDIO_SRC_SPDIF) | ||
356 | { | 463 | { |
357 | /* SCLK2 = Audioclk/4 (can't use EBUin clock), TXSRC = EBU1rcv, 64 bclk/wclk */ | 464 | /* start DMA transfer */ |
358 | IIS2CONFIG = (6 << 12) | (7 << 8) | (4 << 2); | 465 | pcm_record_data(pcm_rec_have_more, NULL, 0); |
359 | /* S/PDIF feed-through already configured */ | 466 | /* do unlock after starting to prevent preincrement of dma_wr_pos */ |
467 | dma_lock = pre_record_ticks == 0; | ||
360 | } | 468 | } |
361 | else | 469 | else |
362 | { | 470 | { |
363 | /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ | 471 | logf("set rec opt: enc load failed"); |
364 | IIS2CONFIG = (8 << 12) | (4 << 8) | (4 << 2); | 472 | is_error = true; |
365 | |||
366 | EBU1CONFIG = 0x800; /* Reset before reprogram */ | ||
367 | /* SCLK2, TXSRC = IIS1recv, validity, normal operation */ | ||
368 | EBU1CONFIG = (7 << 12) | (4 << 8) | (1 << 5) | (5 << 2); | ||
369 | } | ||
370 | #else | ||
371 | /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ | ||
372 | SET_IIS_PLAY( (8 << 12) | (4 << 8) | (4 << 2) ); | ||
373 | #endif | ||
374 | |||
375 | audio_load_encoder(rec_quality_info_afmt[quality]); | ||
376 | } | 473 | } |
377 | 474 | } /* audio_set_recording_options */ | |
378 | 475 | ||
379 | /** | 476 | /** |
380 | * Note that microphone is mono, only left value is used | 477 | * Note that microphone is mono, only left value is used |
@@ -391,8 +488,7 @@ void audio_set_recording_gain(int left, int right, int type) | |||
391 | #elif defined (HAVE_TLV320) | 488 | #elif defined (HAVE_TLV320) |
392 | tlv320_set_recvol(left, right, type); | 489 | tlv320_set_recvol(left, right, type); |
393 | #endif | 490 | #endif |
394 | } | 491 | } /* audio_set_recording_gain */ |
395 | |||
396 | 492 | ||
397 | /** | 493 | /** |
398 | * Start recording | 494 | * Start recording |
@@ -401,585 +497,882 @@ void audio_set_recording_gain(int left, int right, int type) | |||
401 | */ | 497 | */ |
402 | void audio_record(const char *filename) | 498 | void audio_record(const char *filename) |
403 | { | 499 | { |
500 | logf("audio_record: %s", filename); | ||
501 | |||
502 | pcm_thread_wait_for_stop(); | ||
503 | pcm_thread_sync_post(PCMREC_START, (void *)filename); | ||
504 | |||
505 | logf("audio_record_done"); | ||
506 | } /* audio_record */ | ||
507 | |||
508 | void audio_new_file(const char *filename) | ||
509 | { | ||
510 | logf("audio_new_file: %s", filename); | ||
511 | |||
512 | pcm_thread_wait_for_stop(); | ||
513 | pcm_thread_sync_post(PCMREC_NEW_FILE, (void *)filename); | ||
514 | |||
515 | logf("audio_new_file done"); | ||
516 | } /* audio_new_file */ | ||
517 | |||
518 | void audio_stop_recording(void) | ||
519 | { | ||
520 | logf("audio_stop_recording"); | ||
521 | |||
522 | pcm_thread_wait_for_stop(); | ||
523 | |||
404 | if (is_recording) | 524 | if (is_recording) |
405 | { | 525 | dma_lock = true; /* fix DMA write ptr at current position */ |
406 | logf("record while recording"); | 526 | |
407 | return; | 527 | pcm_thread_sync_post(PCMREC_STOP, NULL); |
408 | } | 528 | |
529 | logf("audio_stop_recording done"); | ||
530 | } /* audio_stop_recording */ | ||
531 | |||
532 | void audio_pause_recording(void) | ||
533 | { | ||
534 | logf("audio_pause_recording"); | ||
409 | 535 | ||
410 | strncpy(recording_filename, filename, MAX_PATH - 1); | 536 | pcm_thread_wait_for_stop(); |
411 | recording_filename[MAX_PATH - 1] = 0; | ||
412 | 537 | ||
413 | #ifdef HAVE_SPDIF_IN | 538 | if (is_recording) |
414 | if (rec_source == AUDIO_SRC_SPDIF) | 539 | dma_lock = true; /* fix DMA write ptr at current position */ |
415 | sample_rate = audio_get_spdif_sample_rate(); | ||
416 | #endif | ||
417 | 540 | ||
418 | record_done = false; | 541 | pcm_thread_sync_post(PCMREC_PAUSE, NULL); |
419 | queue_post(&pcmrec_queue, PCMREC_START, 0); | 542 | logf("audio_pause_recording done"); |
543 | } /* audio_pause_recording */ | ||
420 | 544 | ||
421 | while(!record_done) | 545 | void audio_resume_recording(void) |
422 | sleep_thread(1); | 546 | { |
423 | } | 547 | logf("audio_resume_recording"); |
424 | 548 | ||
549 | pcm_thread_wait_for_stop(); | ||
550 | pcm_thread_sync_post(PCMREC_RESUME, NULL); | ||
425 | 551 | ||
426 | void audio_new_file(const char *filename) | 552 | logf("audio_resume_recording done"); |
553 | } /* audio_resume_recording */ | ||
554 | |||
555 | /***************************************************************************/ | ||
556 | /* */ | ||
557 | /* Functions that execute in the context of pcmrec_thread */ | ||
558 | /* */ | ||
559 | /***************************************************************************/ | ||
560 | |||
561 | /** Filename Queue **/ | ||
562 | |||
563 | /* returns true if the queue is empty */ | ||
564 | static inline bool pcmrec_fnq_is_empty(void) | ||
427 | { | 565 | { |
428 | logf("pcm_new_file"); | 566 | return fnq_rd_pos == fnq_wr_pos; |
567 | } /* pcmrec_fnq_is_empty */ | ||
568 | |||
569 | /* empties the filename queue */ | ||
570 | static inline void pcmrec_fnq_set_empty(void) | ||
571 | { | ||
572 | fnq_rd_pos = fnq_wr_pos; | ||
573 | } /* pcmrec_fnq_set_empty */ | ||
429 | 574 | ||
430 | new_file_done = false; | 575 | /* returns true if the queue is full */ |
576 | static bool pcmrec_fnq_is_full(void) | ||
577 | { | ||
578 | ssize_t size = fnq_wr_pos - fnq_rd_pos; | ||
579 | if (size < 0) | ||
580 | size += fnq_size; | ||
431 | 581 | ||
432 | strncpy(recording_filename, filename, MAX_PATH - 1); | 582 | return size >= fnq_size - MAX_PATH; |
433 | recording_filename[MAX_PATH - 1] = 0; | 583 | } /* pcmrec_fnq_is_full */ |
434 | 584 | ||
435 | queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0); | 585 | /* queue another filename - will overwrite oldest one if full */ |
586 | static bool pcmrec_fnq_add_filename(const char *filename) | ||
587 | { | ||
588 | strncpy(fn_queue + fnq_wr_pos, filename, MAX_PATH); | ||
436 | 589 | ||
437 | while(!new_file_done) | 590 | if ((fnq_wr_pos += MAX_PATH) >= fnq_size) |
438 | sleep_thread(1); | 591 | fnq_wr_pos = 0; |
439 | 592 | ||
440 | logf("pcm_new_file done"); | 593 | if (fnq_rd_pos != fnq_wr_pos) |
441 | } | 594 | return true; |
442 | 595 | ||
443 | /** | 596 | /* queue full */ |
444 | * | 597 | if ((fnq_rd_pos += MAX_PATH) >= fnq_size) |
445 | */ | 598 | fnq_rd_pos = 0; |
446 | void audio_stop_recording(void) | 599 | |
600 | return true; | ||
601 | } /* pcmrec_fnq_add_filename */ | ||
602 | |||
603 | /* replace the last filename added */ | ||
604 | static bool pcmrec_fnq_replace_tail(const char *filename) | ||
447 | { | 605 | { |
448 | if (!is_recording) | 606 | int pos; |
449 | return; | 607 | |
608 | if (pcmrec_fnq_is_empty()) | ||
609 | return false; | ||
610 | |||
611 | pos = fnq_wr_pos - MAX_PATH; | ||
612 | if (pos < 0) | ||
613 | pos = fnq_size - MAX_PATH; | ||
614 | |||
615 | strncpy(fn_queue + pos, filename, MAX_PATH); | ||
616 | |||
617 | return true; | ||
618 | } /* pcmrec_fnq_replace_tail */ | ||
450 | 619 | ||
451 | logf("pcm_stop"); | 620 | /* pulls the next filename from the queue */ |
621 | static bool pcmrec_fnq_get_filename(char *filename) | ||
622 | { | ||
623 | if (pcmrec_fnq_is_empty()) | ||
624 | return false; | ||
625 | |||
626 | if (filename) | ||
627 | strncpy(filename, fn_queue + fnq_rd_pos, MAX_PATH); | ||
452 | 628 | ||
453 | is_paused = true; /* fix pcm write ptr at current position */ | 629 | if ((fnq_rd_pos += MAX_PATH) >= fnq_size) |
454 | stop_done = false; | 630 | fnq_rd_pos = 0; |
455 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); | ||
456 | 631 | ||
457 | while(!stop_done) | 632 | return true; |
458 | sleep_thread(1); | 633 | } /* pcmrec_fnq_get_filename */ |
459 | 634 | ||
460 | logf("pcm_stop done"); | 635 | /* close the file number pointed to by fd_p */ |
461 | } | 636 | static void pcmrec_close_file(int *fd_p) |
637 | { | ||
638 | if (*fd_p < 0) | ||
639 | return; /* preserve error */ | ||
462 | 640 | ||
463 | void audio_pause_recording(void) | 641 | close(*fd_p); |
642 | *fd_p = -1; | ||
643 | } /* pcmrec_close_file */ | ||
644 | |||
645 | /** Data Flushing **/ | ||
646 | |||
647 | /** | ||
648 | * called after callback to update sizes if codec changed the amount of data | ||
649 | * a chunk represents | ||
650 | */ | ||
651 | static inline void pcmrec_update_sizes_inl(size_t prev_enc_size, | ||
652 | unsigned long prev_num_pcm) | ||
464 | { | 653 | { |
465 | if (!is_recording) | 654 | if (rec_fdata.new_enc_size != prev_enc_size) |
466 | { | 655 | { |
467 | logf("pause when not recording"); | 656 | ssize_t size_diff = rec_fdata.new_enc_size - prev_enc_size; |
468 | return; | 657 | num_rec_bytes += size_diff; |
658 | accum_rec_bytes += size_diff; | ||
469 | } | 659 | } |
470 | if (is_paused) | 660 | |
661 | if (rec_fdata.new_num_pcm != prev_num_pcm) | ||
471 | { | 662 | { |
472 | logf("pause when paused"); | 663 | unsigned long pcm_diff = rec_fdata.new_num_pcm - prev_num_pcm; |
473 | return; | 664 | num_rec_samples += pcm_diff; |
665 | accum_pcm_samples += pcm_diff; | ||
474 | } | 666 | } |
475 | 667 | } /* pcmrec_update_sizes_inl */ | |
476 | pause_done = false; | ||
477 | queue_post(&pcmrec_queue, PCMREC_PAUSE, 0); | ||
478 | 668 | ||
479 | while(!pause_done) | 669 | /* don't need to inline every instance */ |
480 | sleep_thread(1); | 670 | static void pcmrec_update_sizes(size_t prev_enc_size, |
481 | } | 671 | unsigned long prev_num_pcm) |
672 | { | ||
673 | pcmrec_update_sizes_inl(prev_enc_size, prev_num_pcm); | ||
674 | } /* pcmrec_update_sizes */ | ||
482 | 675 | ||
483 | void audio_resume_recording(void) | 676 | static void pcmrec_start_file(void) |
484 | { | 677 | { |
485 | if (!is_paused) | 678 | size_t enc_size = rec_fdata.new_enc_size; |
679 | unsigned long num_pcm = rec_fdata.new_num_pcm; | ||
680 | int curr_rec_file = rec_fdata.rec_file; | ||
681 | char filename[MAX_PATH]; | ||
682 | |||
683 | /* must always pull the filename that matches with this queue */ | ||
684 | if (!pcmrec_fnq_get_filename(filename)) | ||
486 | { | 685 | { |
487 | logf("resume when not paused"); | 686 | logf("start file: fnq empty"); |
488 | return; | 687 | *filename = '\0'; |
688 | is_error = true; | ||
689 | } | ||
690 | else if (is_error) | ||
691 | { | ||
692 | logf("start file: is_error already"); | ||
693 | } | ||
694 | else if (curr_rec_file >= 0) | ||
695 | { | ||
696 | /* Any previous file should have been closed */ | ||
697 | logf("start file: file already open"); | ||
698 | is_error = true; | ||
489 | } | 699 | } |
490 | 700 | ||
491 | resume_done = false; | 701 | if (is_error) |
492 | queue_post(&pcmrec_queue, PCMREC_RESUME, 0); | 702 | rec_fdata.chunk->flags |= CHUNKF_ERROR; |
493 | 703 | ||
494 | while(!resume_done) | 704 | /* encoder can set error flag here and should increase |
495 | sleep_thread(1); | 705 | enc_new_size and pcm_new_size to reflect additional |
496 | } | 706 | data written if any */ |
707 | rec_fdata.filename = filename; | ||
708 | enc_events_callback(ENC_START_FILE, &rec_fdata); | ||
709 | |||
710 | if (!is_error && (rec_fdata.chunk->flags & CHUNKF_ERROR)) | ||
711 | { | ||
712 | logf("start file: enc error"); | ||
713 | is_error = true; | ||
714 | } | ||
497 | 715 | ||
498 | /* return peaks as int, so convert from short first | 716 | if (is_error) |
499 | note that peak values are always positive */ | 717 | { |
500 | void pcm_rec_get_peaks(int *left, int *right) | 718 | pcmrec_close_file(&curr_rec_file); |
719 | /* Write no more to this file */ | ||
720 | rec_fdata.chunk->flags |= CHUNKF_END_FILE; | ||
721 | } | ||
722 | else | ||
723 | { | ||
724 | pcmrec_update_sizes(enc_size, num_pcm); | ||
725 | } | ||
726 | |||
727 | rec_fdata.chunk->flags &= ~CHUNKF_START_FILE; | ||
728 | } /* pcmrec_start_file */ | ||
729 | |||
730 | static inline void pcmrec_write_chunk(void) | ||
501 | { | 731 | { |
502 | if (left) | 732 | size_t enc_size = rec_fdata.new_enc_size; |
503 | *left = peak_left; | 733 | unsigned long num_pcm = rec_fdata.new_num_pcm; |
504 | if (right) | ||
505 | *right = peak_right; | ||
506 | peak_left = 0; | ||
507 | peak_right = 0; | ||
508 | } | ||
509 | 734 | ||
510 | /***************************************************************************/ | 735 | if (is_error) |
511 | /* Functions that executes in the context of pcmrec_thread */ | 736 | rec_fdata.chunk->flags |= CHUNKF_ERROR; |
512 | /***************************************************************************/ | 737 | |
738 | enc_events_callback(ENC_WRITE_CHUNK, &rec_fdata); | ||
739 | |||
740 | if ((long)rec_fdata.chunk->flags >= 0) | ||
741 | { | ||
742 | pcmrec_update_sizes_inl(enc_size, num_pcm); | ||
743 | } | ||
744 | else if (!is_error) | ||
745 | { | ||
746 | logf("wr chk enc error %d %d", | ||
747 | rec_fdata.chunk->enc_size, rec_fdata.chunk->num_pcm); | ||
748 | is_error = true; | ||
749 | } | ||
750 | } /* pcmrec_write_chunk */ | ||
751 | |||
752 | static void pcmrec_end_file(void) | ||
753 | { | ||
754 | /* all data in output buffer for current file will have been | ||
755 | written and encoder can now do any nescessary steps to | ||
756 | finalize the written file */ | ||
757 | size_t enc_size = rec_fdata.new_enc_size; | ||
758 | unsigned long num_pcm = rec_fdata.new_num_pcm; | ||
759 | |||
760 | enc_events_callback(ENC_END_FILE, &rec_fdata); | ||
761 | |||
762 | if (!is_error) | ||
763 | { | ||
764 | if (rec_fdata.chunk->flags & CHUNKF_ERROR) | ||
765 | { | ||
766 | logf("end file: enc error"); | ||
767 | is_error = true; | ||
768 | } | ||
769 | else | ||
770 | { | ||
771 | pcmrec_update_sizes(enc_size, num_pcm); | ||
772 | } | ||
773 | } | ||
774 | |||
775 | /* Force file close if error */ | ||
776 | if (is_error) | ||
777 | pcmrec_close_file(&rec_fdata.rec_file); | ||
778 | |||
779 | rec_fdata.chunk->flags &= ~CHUNKF_END_FILE; | ||
780 | } /* pcmrec_end_file */ | ||
513 | 781 | ||
514 | /** | 782 | /** |
515 | * Process the chunks | 783 | * Process the chunks |
516 | * | 784 | * |
517 | * This function is called when queue_get_w_tmo times out. | 785 | * This function is called when queue_get_w_tmo times out. |
518 | * | 786 | * |
519 | * Other functions can also call this function with flush = true when | 787 | * Set flush_num to the number of files to flush to disk. |
520 | * they want to save everything in the buffers to disk. | 788 | * flush_num = -1 to flush all available chunks to disk. |
789 | * flush_num = 0 normal write thresholding | ||
790 | * flush_num = 1 or greater - all available chunks of current file plus | ||
791 | * flush_num file starts if first chunk has been processed. | ||
521 | * | 792 | * |
522 | */ | 793 | */ |
523 | static void pcmrec_callback(bool flush) | 794 | static void pcmrec_flush(unsigned flush_num) |
524 | { | 795 | { |
525 | int i, num_ready, size_yield; | 796 | static unsigned long last_flush_tick = 0; |
526 | long *enc_chunk, chunk_size; | 797 | unsigned long start_tick; |
527 | 798 | int num_ready, num; | |
528 | if (!is_recording && !flush) | 799 | int prio; |
529 | return; | 800 | int i; |
530 | 801 | ||
531 | num_ready = enc_wr_index - enc_rd_index; | 802 | num_ready = enc_wr_index - enc_rd_index; |
532 | if (num_ready < 0) | 803 | if (num_ready < 0) |
533 | num_ready += enc_num_chunks; | 804 | num_ready += enc_num_chunks; |
534 | 805 | ||
535 | /* calculate an estimate of recorded bytes */ | 806 | num = num_ready; |
536 | num_rec_bytes = num_file_bytes + num_ready * /* enc_chunk_size */ | ||
537 | ((avrg_bit_rate * 1000 / 8 * enc_samp_per_chunk + 22050) / 44100); | ||
538 | 807 | ||
539 | /* near full state reached: less than 5sec remaining space */ | 808 | if (flush_num == 0) |
540 | if (enc_num_chunks - num_ready < WRITE_THRESHOLD || flush) | ||
541 | { | 809 | { |
542 | logf("writing: %d (%d)", num_ready, flush); | 810 | if (!is_recording) |
543 | 811 | return; | |
544 | cpu_boost_id(true, CPUBOOSTID_PCMRECORD); | ||
545 | 812 | ||
546 | size_yield = 0; | 813 | if (ata_spinup_time != spinup_time) |
547 | for (i=0; i<num_ready; i++) | ||
548 | { | 814 | { |
549 | enc_chunk = GET_ENC_CHUNK(enc_rd_index); | 815 | /* spinup time has changed, calculate new write threshold */ |
550 | chunk_size = *enc_chunk++; | 816 | logf("new t spinup : %d", ata_spinup_time); |
551 | 817 | unsigned long st = spinup_time = ata_spinup_time; | |
552 | /* safety net: if size entry got corrupted => limit */ | 818 | |
553 | if (chunk_size > (long)(enc_chunk_size - sizeof(long))) | 819 | /* write at 5s + st remaining in enc_buffer */ |
554 | chunk_size = enc_chunk_size - sizeof(long); | 820 | if (st < 2*HZ) |
821 | st = 2*HZ; /* my drive is usually < 250 ticks :) */ | ||
822 | else if (st > 10*HZ) | ||
823 | st = 10*HZ; | ||
824 | |||
825 | write_threshold = enc_num_chunks - | ||
826 | (int)(((5ull*HZ + st)*4ull*sample_rate + (enc_chunk_size-1)) / | ||
827 | (enc_chunk_size*HZ)); | ||
828 | |||
829 | if (write_threshold < 0) | ||
830 | write_threshold = 0; | ||
831 | else if (write_threshold > panic_threshold) | ||
832 | write_threshold = panic_threshold; | ||
833 | |||
834 | logf("new wr thresh: %d", write_threshold); | ||
835 | } | ||
555 | 836 | ||
556 | if (enc_set_header_callback != NULL) | 837 | if (num_ready < write_threshold) |
557 | enc_set_header_callback(enc_chunk, enc_chunk_size, | 838 | return; |
558 | num_pcm_samples, false); | ||
559 | 839 | ||
560 | if (write(wav_file, enc_chunk, chunk_size) != chunk_size) | 840 | /* if we're getting called too much and this isn't forced, |
561 | { | 841 | boost stat */ |
562 | close_wave(); | 842 | if (current_tick - last_flush_tick < HZ/2) |
563 | logf("pcmrec: write err"); | 843 | num = panic_threshold; |
564 | is_error = true; | 844 | } |
565 | break; | ||
566 | } | ||
567 | 845 | ||
568 | num_file_bytes += chunk_size; | 846 | start_tick = current_tick; |
569 | num_pcm_samples += enc_samp_per_chunk; | 847 | prio = -1; |
570 | size_yield += chunk_size; | ||
571 | 848 | ||
572 | if (size_yield >= 32768) | 849 | logf("writing: %d (%d)", num_ready, flush_num); |
573 | { /* yield when 32kB written */ | 850 | |
574 | size_yield = 0; | 851 | cpu_boost_id(true, CPUBOOSTID_PCMRECORD); |
575 | yield(); | ||
576 | } | ||
577 | 852 | ||
578 | enc_rd_index = (enc_rd_index + 1) % enc_num_chunks; | 853 | for (i=0; i<num_ready; i++) |
854 | { | ||
855 | if (prio == -1 && (num >= panic_threshold || | ||
856 | current_tick - start_tick > 10*HZ)) | ||
857 | { | ||
858 | /* losing ground - boost priority until finished */ | ||
859 | logf("pcmrec: boost priority"); | ||
860 | prio = thread_set_priority(NULL, thread_get_priority(NULL)-1); | ||
579 | } | 861 | } |
580 | 862 | ||
581 | /* sync file */ | 863 | rec_fdata.chunk = GET_ENC_CHUNK(enc_rd_index); |
582 | fsync(wav_file); | 864 | rec_fdata.new_enc_size = rec_fdata.chunk->enc_size; |
865 | rec_fdata.new_num_pcm = rec_fdata.chunk->num_pcm; | ||
583 | 866 | ||
584 | cpu_boost_id(false, CPUBOOSTID_PCMRECORD); | 867 | if (rec_fdata.chunk->flags & CHUNKF_START_FILE) |
868 | { | ||
869 | pcmrec_start_file(); | ||
870 | if (--flush_num == 0) | ||
871 | i = num_ready; /* stop on next loop - must write this | ||
872 | chunk if it has data */ | ||
873 | } | ||
585 | 874 | ||
586 | logf("done"); | 875 | pcmrec_write_chunk(); |
587 | } | ||
588 | } | ||
589 | 876 | ||
590 | /* Abort dma transfer */ | 877 | if (rec_fdata.chunk->flags & CHUNKF_END_FILE) |
591 | static void pcmrec_dma_stop(void) | 878 | pcmrec_end_file(); |
592 | { | ||
593 | DCR1 = 0; | ||
594 | 879 | ||
595 | error_count++; | 880 | INC_ENC_INDEX(enc_rd_index); |
596 | 881 | ||
597 | DSR1 = 1; /* Clear interrupt */ | 882 | if (is_error) |
598 | IPR |= (1<<15); /* Clear pending interrupt request */ | 883 | break; |
599 | 884 | ||
600 | logf("dma1 stopped"); | 885 | if (prio == -1) |
601 | } | 886 | { |
887 | num = enc_wr_index - enc_rd_index; | ||
888 | if (num < 0) | ||
889 | num += enc_num_chunks; | ||
890 | } | ||
602 | 891 | ||
603 | static void pcmrec_dma_start(void) | 892 | /* no yielding, the file apis called in the codecs do that */ |
604 | { | 893 | } /* end for */ |
605 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ | ||
606 | SAR1 = (unsigned long)&PDIR2; /* Source address */ | ||
607 | BCR1 = CHUNK_SIZE; /* Bytes to transfer */ | ||
608 | 894 | ||
609 | /* Start the DMA transfer.. */ | 895 | /* sync file */ |
610 | #ifdef HAVE_SPDIF_IN | 896 | if (rec_fdata.rec_file >= 0) |
611 | INTERRUPTCLEAR = 0x03c00000; | 897 | fsync(rec_fdata.rec_file); |
612 | #endif | 898 | |
899 | cpu_boost_id(false, CPUBOOSTID_PCMRECORD); | ||
613 | 900 | ||
614 | /* 16Byte transfers prevents from sporadic errors during cpu_boost() */ | 901 | if (prio != -1) |
615 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_DSIZE(3) | DMA_START; | 902 | { |
903 | /* return to original priority */ | ||
904 | logf("pcmrec: unboost priority"); | ||
905 | thread_set_priority(NULL, prio); | ||
906 | } | ||
616 | 907 | ||
617 | logf("dma1 started"); | 908 | last_flush_tick = current_tick; /* save tick when we left */ |
618 | } | 909 | logf("done"); |
910 | } /* pcmrec_flush */ | ||
619 | 911 | ||
620 | /* DMA1 Interrupt is called when the DMA has finished transfering a chunk */ | 912 | /** |
621 | void DMA1(void) __attribute__ ((interrupt_handler, section(".icode"))); | 913 | * Marks a new stream in the buffer and gives the encoder a chance for special |
622 | void DMA1(void) | 914 | * handling of transition from one to the next. The encoder may change the |
915 | * chunk that ends the old stream by requesting more chunks and similiarly for | ||
916 | * the new but must always advance the position though the interface. It can | ||
917 | * later reject any data it cares to when writing the file but should mark the | ||
918 | * chunk so it can recognize this. ENC_WRITE_CHUNK event must be able to accept | ||
919 | * a NULL data pointer without error as well. | ||
920 | */ | ||
921 | static void pcmrec_new_stream(const char *filename, /* next file name */ | ||
922 | unsigned long flags, /* CHUNKF_* flags */ | ||
923 | int pre_index) /* index for prerecorded data */ | ||
623 | { | 924 | { |
624 | int res = DSR1; | 925 | logf("pcmrec_new_stream"); |
625 | 926 | ||
626 | DSR1 = 1; /* Clear interrupt */ | 927 | struct enc_buffer_event_data data; |
928 | bool (*fnq_add_fn)(const char *) = NULL; | ||
929 | struct enc_chunk_hdr *start = NULL; | ||
627 | 930 | ||
628 | if (res & 0x70) | 931 | int get_chunk_index(struct enc_chunk_hdr *chunk) |
629 | { | 932 | { |
630 | DCR1 = 0; /* Stop DMA transfer */ | 933 | return ((char *)chunk - (char *)enc_buffer) / enc_chunk_size; |
631 | error_count++; | 934 | } |
632 | |||
633 | logf("dma1 err: 0x%x", res); | ||
634 | |||
635 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ | ||
636 | BCR1 = CHUNK_SIZE; | ||
637 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START; | ||
638 | 935 | ||
639 | /* Flush recorded data to disk and stop recording */ | 936 | struct enc_chunk_hdr * get_prev_chunk(int index) |
640 | queue_post(&pcmrec_queue, PCMREC_STOP, NULL); | ||
641 | } | ||
642 | #ifdef HAVE_SPDIF_IN | ||
643 | else if ((rec_source == AUDIO_SRC_SPDIF) && | ||
644 | (INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */ | ||
645 | { | 937 | { |
646 | INTERRUPTCLEAR = 0x03c00000; | 938 | DEC_ENC_INDEX(index); |
647 | error_count++; | 939 | return GET_ENC_CHUNK(index); |
940 | } | ||
648 | 941 | ||
649 | logf("spdif err"); | 942 | data.pre_chunk = NULL; |
943 | data.chunk = GET_ENC_CHUNK(enc_wr_index); | ||
650 | 944 | ||
651 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ | 945 | /* end chunk */ |
652 | BCR1 = CHUNK_SIZE; | 946 | if (flags & CHUNKF_END_FILE) |
653 | } | ||
654 | #endif | ||
655 | else | ||
656 | { | 947 | { |
657 | long peak_l, peak_r; | 948 | data.chunk->flags &= CHUNKF_START_FILE | CHUNKF_END_FILE; |
658 | long *ptr, j; | ||
659 | |||
660 | ptr = GET_CHUNK(write_pos); | ||
661 | 949 | ||
662 | if (!is_paused) /* advance write position */ | 950 | if (data.chunk->flags & CHUNKF_START_FILE) |
663 | write_pos = (write_pos + CHUNK_SIZE) & CHUNK_MASK; | 951 | { |
952 | /* cannot start and end on same unprocessed chunk */ | ||
953 | logf("file end on start"); | ||
954 | flags &= ~CHUNKF_END_FILE; | ||
955 | } | ||
956 | else if (enc_rd_index == enc_wr_index) | ||
957 | { | ||
958 | /* all data flushed but file not ended - chunk will be left | ||
959 | empty */ | ||
960 | logf("end on dead end"); | ||
961 | data.chunk->flags = 0; | ||
962 | data.chunk->enc_size = 0; | ||
963 | data.chunk->num_pcm = 0; | ||
964 | data.chunk->enc_data = NULL; | ||
965 | INC_ENC_INDEX(enc_wr_index); | ||
966 | data.chunk = GET_ENC_CHUNK(enc_wr_index); | ||
967 | } | ||
968 | else | ||
969 | { | ||
970 | struct enc_chunk_hdr *last = get_prev_chunk(enc_wr_index); | ||
664 | 971 | ||
665 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ | 972 | if (last->flags & CHUNKF_END_FILE) |
666 | BCR1 = CHUNK_SIZE; | 973 | { |
974 | /* end already processed and marked - can't end twice */ | ||
975 | logf("file end again"); | ||
976 | flags &= ~CHUNKF_END_FILE; | ||
977 | } | ||
978 | } | ||
979 | } | ||
667 | 980 | ||
668 | peak_l = peak_r = 0; | 981 | /* start chunk */ |
982 | if (flags & CHUNKF_START_FILE) | ||
983 | { | ||
984 | bool pre = flags & CHUNKF_PRERECORD; | ||
669 | 985 | ||
670 | /* only peak every 4th sample */ | 986 | if (pre) |
671 | for (j=0; j<CHUNK_SIZE/4; j+=4) | ||
672 | { | 987 | { |
673 | long value = ptr[j]; | 988 | logf("stream prerecord start"); |
674 | #ifdef ROCKBOX_BIG_ENDIAN | 989 | start = data.pre_chunk = GET_ENC_CHUNK(pre_index); |
675 | if (value > peak_l) peak_l = value; | 990 | start->flags &= CHUNKF_START_FILE | CHUNKF_PRERECORD; |
676 | else if (-value > peak_l) peak_l = -value; | 991 | } |
677 | 992 | else | |
678 | value <<= 16; | 993 | { |
679 | if (value > peak_r) peak_r = value; | 994 | logf("stream normal start"); |
680 | else if (-value > peak_r) peak_r = -value; | 995 | start = data.chunk; |
681 | #else | 996 | start->flags &= CHUNKF_START_FILE; |
682 | if (value > peak_r) peak_r = value; | ||
683 | else if (-value > peak_r) peak_r = -value; | ||
684 | |||
685 | value <<= 16; | ||
686 | if (value > peak_l) peak_l = value; | ||
687 | else if (-value > peak_l) peak_l = -value; | ||
688 | #endif | ||
689 | } | 997 | } |
690 | 998 | ||
691 | peak_left = (int)(peak_l >> 16); | 999 | /* if encoder hasn't yet processed the last start - abort the start |
692 | peak_right = (int)(peak_r >> 16); | 1000 | of the previous file queued or else it will be empty and invalid */ |
1001 | if (start->flags & CHUNKF_START_FILE) | ||
1002 | { | ||
1003 | logf("replacing fnq tail: %s", filename); | ||
1004 | fnq_add_fn = pcmrec_fnq_replace_tail; | ||
1005 | } | ||
1006 | else | ||
1007 | { | ||
1008 | logf("adding filename: %s", filename); | ||
1009 | fnq_add_fn = pcmrec_fnq_add_filename; | ||
1010 | } | ||
693 | } | 1011 | } |
694 | 1012 | ||
695 | IPR |= (1<<15); /* Clear pending interrupt request */ | 1013 | data.flags = flags; |
696 | } | 1014 | enc_events_callback(ENC_REC_NEW_STREAM, &data); |
697 | |||
698 | /* Create WAVE file and write header */ | ||
699 | /* Sets returns 0 if success, -1 on failure */ | ||
700 | static int start_wave(void) | ||
701 | { | ||
702 | wav_file = open(recording_filename, O_RDWR|O_CREAT|O_TRUNC); | ||
703 | 1015 | ||
704 | if (wav_file < 0) | 1016 | if (flags & CHUNKF_END_FILE) |
705 | { | 1017 | { |
706 | wav_file = -1; | 1018 | int i = get_chunk_index(data.chunk); |
707 | logf("rec: create failed: %d", wav_file); | 1019 | get_prev_chunk(i)->flags |= CHUNKF_END_FILE; |
708 | is_error = true; | ||
709 | return -1; | ||
710 | } | 1020 | } |
711 | 1021 | ||
712 | /* add main file header (enc_head_size=0 for encoders without) */ | 1022 | if (start) |
713 | if (enc_head_size != write(wav_file, enc_head_buffer, enc_head_size)) | ||
714 | { | 1023 | { |
715 | close(wav_file); | 1024 | if (!(flags & CHUNKF_PRERECORD)) |
716 | wav_file = -1; | 1025 | { |
717 | logf("rec: write failed"); | 1026 | /* get stats on data added to start - sort of a prerecord operation */ |
718 | is_error = true; | 1027 | int i = get_chunk_index(data.chunk); |
719 | return -1; | 1028 | struct enc_chunk_hdr *chunk = data.chunk; |
720 | } | ||
721 | 1029 | ||
722 | return 0; | 1030 | logf("start data: %d %d", i, enc_wr_index); |
723 | } | ||
724 | 1031 | ||
725 | /* Update header and set correct length values */ | 1032 | num_rec_bytes = 0; |
726 | static void close_wave(void) | 1033 | num_rec_samples = 0; |
727 | { | ||
728 | unsigned char head[100]; /* assume maximum 100 bytes for file header */ | ||
729 | int size_read; | ||
730 | 1034 | ||
731 | if (wav_file != -1) | 1035 | while (i != enc_wr_index) |
732 | { | 1036 | { |
733 | /* update header before closing the file (wav+wv encoder will do) */ | 1037 | num_rec_bytes += chunk->enc_size; |
734 | if (enc_set_header_callback != NULL) | 1038 | num_rec_samples += chunk->num_pcm; |
735 | { | 1039 | INC_ENC_INDEX(i); |
736 | lseek(wav_file, 0, SEEK_SET); | 1040 | chunk = GET_ENC_CHUNK(i); |
737 | /* try to read the head size (but we'll accept less) */ | 1041 | } |
738 | size_read = read(wav_file, head, sizeof(head)); | 1042 | |
1043 | start->flags &= ~CHUNKF_START_FILE; | ||
1044 | start = data.chunk; | ||
1045 | } | ||
1046 | |||
1047 | start->flags |= CHUNKF_START_FILE; | ||
739 | 1048 | ||
740 | enc_set_header_callback(head, size_read, num_pcm_samples, true); | 1049 | /* flush one file out if full and adding */ |
741 | lseek(wav_file, 0, SEEK_SET); | 1050 | if (fnq_add_fn == pcmrec_fnq_add_filename && pcmrec_fnq_is_full()) |
742 | write(wav_file, head, size_read); | 1051 | { |
1052 | logf("fnq full: flushing 1"); | ||
1053 | pcmrec_flush(1); | ||
743 | } | 1054 | } |
744 | close(wav_file); | 1055 | |
745 | wav_file = -1; | 1056 | fnq_add_fn(filename); |
746 | } | 1057 | } |
747 | } | 1058 | } /* pcmrec_new_stream */ |
748 | 1059 | ||
749 | static void pcmrec_start(void) | 1060 | /** event handlers for pcmrec thread */ |
1061 | |||
1062 | /* PCMREC_INIT */ | ||
1063 | static void pcmrec_init(void) | ||
750 | { | 1064 | { |
751 | long max_pre_chunks, pre_ticks, max_pre_ticks; | 1065 | rec_fdata.rec_file = -1; |
1066 | |||
1067 | /* pcm FIFO */ | ||
1068 | dma_lock = true; | ||
1069 | pcm_rd_pos = 0; | ||
1070 | dma_wr_pos = 0; | ||
1071 | |||
1072 | /* encoder FIFO */ | ||
1073 | enc_wr_index = 0; | ||
1074 | enc_rd_index = 0; | ||
1075 | |||
1076 | /* filename queue */ | ||
1077 | fnq_rd_pos = 0; | ||
1078 | fnq_wr_pos = 0; | ||
1079 | |||
1080 | /* stats */ | ||
1081 | num_rec_bytes = 0; | ||
1082 | num_rec_samples = 0; | ||
1083 | accum_rec_bytes = 0; | ||
1084 | accum_pcm_samples = 0; | ||
1085 | |||
1086 | pcm_thread_unsignal_event(PCMREC_CLOSE); | ||
1087 | is_recording = false; | ||
1088 | is_paused = false; | ||
1089 | is_stopping = false; | ||
1090 | is_error = false; | ||
1091 | |||
1092 | pcm_buffer = audio_get_recording_buffer(&rec_buffer_size); | ||
1093 | /* Line align pcm_buffer 2^4=16 bytes */ | ||
1094 | pcm_buffer = (unsigned char *)ALIGN_UP_P2((unsigned)pcm_buffer, 4); | ||
1095 | enc_buffer = pcm_buffer + ALIGN_UP_P2(PCM_NUM_CHUNKS*PCM_CHUNK_SIZE + | ||
1096 | PCM_MAX_FEED_SIZE, 2); | ||
1097 | |||
1098 | pcm_init_recording(); | ||
1099 | pcm_thread_signal_event(PCMREC_INIT); | ||
1100 | } /* pcmrec_init */ | ||
1101 | |||
1102 | /* PCMREC_CLOSE */ | ||
1103 | static void pcmrec_close(void) | ||
1104 | { | ||
1105 | dma_lock = true; | ||
1106 | pcm_close_recording(); | ||
1107 | pcm_thread_unsignal_event(PCMREC_INIT); | ||
1108 | pcm_thread_signal_event(PCMREC_CLOSE); | ||
1109 | } /* pcmrec_close */ | ||
1110 | |||
1111 | /* PCMREC_START */ | ||
1112 | static void pcmrec_start(const char *filename) | ||
1113 | { | ||
1114 | unsigned long pre_sample_ticks; | ||
1115 | int rd_start; | ||
752 | 1116 | ||
753 | logf("pcmrec_start"); | 1117 | logf("pcmrec_start: %s", filename); |
754 | 1118 | ||
755 | if (is_recording) | 1119 | if (is_recording) |
756 | { | 1120 | { |
757 | logf("already recording"); | 1121 | logf("already recording"); |
758 | record_done = true; | 1122 | goto already_recording; |
759 | return; | ||
760 | } | 1123 | } |
761 | 1124 | ||
762 | if (wav_file != -1) | 1125 | /* reset stats */ |
763 | close_wave(); | 1126 | num_rec_bytes = 0; |
1127 | num_rec_samples = 0; | ||
1128 | accum_rec_bytes = 0; | ||
1129 | accum_pcm_samples = 0; | ||
1130 | spinup_time = -1; | ||
1131 | |||
1132 | rd_start = enc_wr_index; | ||
1133 | pre_sample_ticks = 0; | ||
764 | 1134 | ||
765 | if (start_wave() != 0) | 1135 | if (pre_record_ticks) |
766 | { | 1136 | { |
767 | /* failed to create the file */ | 1137 | int i; |
768 | record_done = true; | ||
769 | return; | ||
770 | } | ||
771 | 1138 | ||
772 | /* calculate maximum available chunks & resulting ticks */ | 1139 | /* calculate number of available chunks */ |
773 | max_pre_chunks = (enc_wr_index - enc_rd_index + | 1140 | unsigned long avail_pre_chunks = (enc_wr_index - enc_rd_index + |
774 | enc_num_chunks) % enc_num_chunks; | ||
775 | if (max_pre_chunks > enc_num_chunks - WRITE_THRESHOLD) | ||
776 | max_pre_chunks = enc_num_chunks - WRITE_THRESHOLD; | ||
777 | max_pre_ticks = max_pre_chunks * HZ * enc_samp_per_chunk / 44100; | ||
778 | |||
779 | /* limit prerecord if not enough data available */ | ||
780 | pre_ticks = pre_record_ticks > max_pre_ticks ? | ||
781 | max_pre_ticks : pre_record_ticks; | ||
782 | max_pre_chunks = 44100 * pre_ticks / HZ / enc_samp_per_chunk; | ||
783 | enc_rd_index = (enc_wr_index - max_pre_chunks + | ||
784 | enc_num_chunks) % enc_num_chunks; | 1141 | enc_num_chunks) % enc_num_chunks; |
1142 | /* overflow at 974 seconds of prerecording at 44.1kHz */ | ||
1143 | unsigned long pre_record_sample_ticks = enc_sample_rate*pre_record_ticks; | ||
1144 | |||
1145 | /* Get exact measure of recorded data as number of samples aren't | ||
1146 | nescessarily going to be the max for each chunk */ | ||
1147 | for (i = rd_start; avail_pre_chunks-- > 0;) | ||
1148 | { | ||
1149 | struct enc_chunk_hdr *chunk; | ||
1150 | unsigned long chunk_sample_ticks; | ||
1151 | |||
1152 | DEC_ENC_INDEX(i); | ||
1153 | |||
1154 | chunk = GET_ENC_CHUNK(i); | ||
1155 | |||
1156 | /* must have data to be counted */ | ||
1157 | if (chunk->enc_data == NULL) | ||
1158 | continue; | ||
785 | 1159 | ||
786 | record_start_time = current_tick - pre_ticks; | 1160 | chunk_sample_ticks = chunk->num_pcm*HZ; |
787 | 1161 | ||
788 | num_rec_bytes = enc_num_chunks * CHUNK_SIZE; | 1162 | rd_start = i; |
789 | num_file_bytes = 0; | 1163 | pre_sample_ticks += chunk_sample_ticks; |
790 | num_pcm_samples = 0; | 1164 | num_rec_bytes += chunk->enc_size; |
791 | pause_start_time = 0; | 1165 | num_rec_samples += chunk->num_pcm; |
1166 | |||
1167 | /* stop here if enough already */ | ||
1168 | if (pre_sample_ticks >= pre_record_sample_ticks) | ||
1169 | break; | ||
1170 | } | ||
1171 | |||
1172 | accum_rec_bytes = num_rec_bytes; | ||
1173 | accum_pcm_samples = num_rec_samples; | ||
1174 | } | ||
1175 | |||
1176 | enc_rd_index = rd_start; | ||
1177 | |||
1178 | /* filename queue should be empty */ | ||
1179 | if (!pcmrec_fnq_is_empty()) | ||
1180 | { | ||
1181 | logf("fnq: not empty!"); | ||
1182 | pcmrec_fnq_set_empty(); | ||
1183 | } | ||
792 | 1184 | ||
1185 | dma_lock = false; | ||
793 | is_paused = false; | 1186 | is_paused = false; |
794 | is_recording = true; | 1187 | is_recording = true; |
795 | record_done = true; | ||
796 | } | ||
797 | 1188 | ||
1189 | pcmrec_new_stream(filename, | ||
1190 | CHUNKF_START_FILE | | ||
1191 | (pre_sample_ticks > 0 ? CHUNKF_PRERECORD : 0), | ||
1192 | enc_rd_index); | ||
1193 | |||
1194 | already_recording: | ||
1195 | pcm_thread_signal_event(PCMREC_START); | ||
1196 | logf("pcmrec_start done"); | ||
1197 | } /* pcmrec_start */ | ||
1198 | |||
1199 | /* PCMREC_STOP */ | ||
798 | static void pcmrec_stop(void) | 1200 | static void pcmrec_stop(void) |
799 | { | 1201 | { |
800 | logf("pcmrec_stop"); | 1202 | logf("pcmrec_stop"); |
801 | 1203 | ||
802 | if (is_recording) | 1204 | if (!is_recording) |
803 | { | 1205 | { |
804 | /* wait for encoding finish */ | 1206 | logf("not recording"); |
805 | is_paused = true; | 1207 | goto not_recording_or_stopping; |
806 | while(!wav_queue_empty) | 1208 | } |
807 | sleep_thread(1); | 1209 | else if (is_stopping) |
808 | 1210 | { | |
809 | is_recording = false; | 1211 | logf("already stopping"); |
810 | 1212 | goto not_recording_or_stopping; | |
811 | /* Flush buffers to file */ | ||
812 | pcmrec_callback(true); | ||
813 | close_wave(); | ||
814 | } | 1213 | } |
815 | 1214 | ||
816 | is_paused = false; | 1215 | is_stopping = true; |
817 | stop_done = true; | 1216 | dma_lock = true; /* lock dma write position */ |
1217 | queue_post(&pcmrec_queue, PCMREC_FINISH_STOP, NULL); | ||
818 | 1218 | ||
1219 | not_recording_or_stopping: | ||
1220 | pcm_thread_signal_event(PCMREC_STOP); | ||
819 | logf("pcmrec_stop done"); | 1221 | logf("pcmrec_stop done"); |
820 | } | 1222 | } /* pcmrec_stop */ |
821 | 1223 | ||
822 | static void pcmrec_new_file(void) | 1224 | /* PCMREC_FINISH_STOP */ |
1225 | static void pcmrec_finish_stop(void) | ||
823 | { | 1226 | { |
824 | logf("pcmrec_new_file"); | 1227 | logf("pcmrec_finish_stop"); |
825 | 1228 | ||
826 | if (!is_recording) | 1229 | if (!is_stopping) |
827 | { | 1230 | { |
828 | logf("not recording"); | 1231 | logf("not stopping"); |
829 | new_file_done = true; | 1232 | goto not_stopping; |
830 | return; | ||
831 | } | 1233 | } |
832 | 1234 | ||
833 | /* Since pcmrec_callback() blocks until the data has been written, | 1235 | /* flush all available data first to avoid overflow while waiting |
834 | here is a good approximation when recording to the new file starts | 1236 | for encoding to finish */ |
835 | */ | 1237 | pcmrec_flush(-1); |
836 | record_start_time = current_tick; | ||
837 | 1238 | ||
838 | if (is_paused) | 1239 | /* wait for encoder to finish remaining data */ |
839 | pause_start_time = record_start_time; | 1240 | if (!is_error) |
1241 | { | ||
1242 | while (!wav_queue_empty) | ||
1243 | yield(); | ||
1244 | } | ||
840 | 1245 | ||
841 | /* Flush what we got in buffers to file */ | 1246 | /* end stream at last data */ |
842 | pcmrec_callback(true); | 1247 | pcmrec_new_stream(NULL, CHUNKF_END_FILE, 0); |
843 | 1248 | ||
844 | close_wave(); | 1249 | /* flush anything else encoder added */ |
845 | 1250 | pcmrec_flush(-1); | |
846 | num_rec_bytes = 0; | 1251 | |
847 | num_file_bytes = 0; | 1252 | /* remove any pending file start not yet processed - should be at |
848 | num_pcm_samples = 0; | 1253 | most one at enc_wr_index */ |
1254 | pcmrec_fnq_get_filename(NULL); | ||
1255 | /* encoder should abort any chunk it was in midst of processing */ | ||
1256 | GET_ENC_CHUNK(enc_wr_index)->flags = CHUNKF_ABORT; | ||
849 | 1257 | ||
850 | /* start the new file */ | 1258 | /* filename queue should be empty */ |
851 | if (start_wave() != 0) | 1259 | if (!pcmrec_fnq_is_empty()) |
852 | { | 1260 | { |
853 | logf("new_file failed"); | 1261 | logf("fnq: not empty!"); |
854 | pcmrec_stop(); | 1262 | pcmrec_fnq_set_empty(); |
855 | } | 1263 | } |
856 | 1264 | ||
857 | new_file_done = true; | 1265 | /* be absolutely sure the file is closed */ |
858 | logf("pcmrec_new_file done"); | 1266 | if (is_error) |
859 | } | 1267 | pcmrec_close_file(&rec_fdata.rec_file); |
1268 | rec_fdata.rec_file = -1; | ||
1269 | |||
1270 | is_recording = false; | ||
1271 | is_paused = false; | ||
1272 | is_stopping = false; | ||
1273 | dma_lock = pre_record_ticks == 0; | ||
1274 | |||
1275 | not_stopping: | ||
1276 | logf("pcmrec_finish_stop done"); | ||
1277 | } /* pcmrec_finish_stop */ | ||
860 | 1278 | ||
1279 | /* PCMREC_PAUSE */ | ||
861 | static void pcmrec_pause(void) | 1280 | static void pcmrec_pause(void) |
862 | { | 1281 | { |
863 | logf("pcmrec_pause"); | 1282 | logf("pcmrec_pause"); |
864 | 1283 | ||
865 | if (!is_recording) | 1284 | if (!is_recording) |
866 | { | 1285 | { |
867 | logf("pause: not recording"); | 1286 | logf("not recording"); |
868 | pause_done = true; | 1287 | goto not_recording_or_paused; |
869 | return; | 1288 | } |
1289 | else if (is_paused) | ||
1290 | { | ||
1291 | logf("already paused"); | ||
1292 | goto not_recording_or_paused; | ||
870 | } | 1293 | } |
871 | 1294 | ||
872 | pause_start_time = current_tick; | 1295 | dma_lock = true; /* fix DMA write pointer at current position */ |
873 | is_paused = true; | 1296 | is_paused = true; |
874 | pause_done = true; | ||
875 | 1297 | ||
1298 | not_recording_or_paused: | ||
1299 | pcm_thread_signal_event(PCMREC_PAUSE); | ||
876 | logf("pcmrec_pause done"); | 1300 | logf("pcmrec_pause done"); |
877 | } | 1301 | } /* pcmrec_pause */ |
878 | |||
879 | 1302 | ||
1303 | /* PCMREC_RESUME */ | ||
880 | static void pcmrec_resume(void) | 1304 | static void pcmrec_resume(void) |
881 | { | 1305 | { |
882 | logf("pcmrec_resume"); | 1306 | logf("pcmrec_resume"); |
883 | 1307 | ||
884 | if (!is_paused) | 1308 | if (!is_recording) |
885 | { | 1309 | { |
886 | logf("resume: not paused"); | 1310 | logf("not recording"); |
887 | resume_done = true; | 1311 | goto not_recording_or_not_paused; |
888 | return; | 1312 | } |
1313 | else if (!is_paused) | ||
1314 | { | ||
1315 | logf("not paused"); | ||
1316 | goto not_recording_or_not_paused; | ||
889 | } | 1317 | } |
890 | 1318 | ||
891 | is_paused = false; | 1319 | is_paused = false; |
892 | is_recording = true; | 1320 | is_recording = true; |
1321 | dma_lock = false; | ||
893 | 1322 | ||
894 | /* Compensate for the time we have been paused */ | 1323 | not_recording_or_not_paused: |
895 | if (pause_start_time) | 1324 | pcm_thread_signal_event(PCMREC_RESUME); |
896 | { | ||
897 | record_start_time += current_tick - pause_start_time; | ||
898 | pause_start_time = 0; | ||
899 | } | ||
900 | |||
901 | resume_done = true; | ||
902 | logf("pcmrec_resume done"); | 1325 | logf("pcmrec_resume done"); |
903 | } | 1326 | } /* pcmrec_resume */ |
904 | 1327 | ||
905 | /** | 1328 | /* PCMREC_NEW_FILE */ |
906 | * audio_init_recording calls this function using PCMREC_INIT | 1329 | static void pcmrec_new_file(const char *filename) |
907 | * | ||
908 | */ | ||
909 | static void pcmrec_init(void) | ||
910 | { | 1330 | { |
911 | wav_file = -1; | 1331 | logf("pcmrec_new_file: %s", filename); |
912 | read_pos = 0; | ||
913 | write_pos = 0; | ||
914 | enc_wr_index = 0; | ||
915 | enc_rd_index = 0; | ||
916 | 1332 | ||
917 | avrg_bit_rate = 0; | 1333 | if (!is_recording) |
918 | curr_bit_rate = 0; | 1334 | { |
919 | curr_chunk_cnt = 0; | 1335 | logf("not recording"); |
920 | 1336 | goto not_recording; | |
921 | peak_left = 0; | 1337 | } |
922 | peak_right = 0; | ||
923 | 1338 | ||
924 | num_rec_bytes = 0; | 1339 | num_rec_bytes = 0; |
925 | num_file_bytes = 0; | 1340 | num_rec_samples = 0; |
926 | num_pcm_samples = 0; | ||
927 | record_start_time = 0; | ||
928 | pause_start_time = 0; | ||
929 | |||
930 | close_done = false; | ||
931 | is_recording = false; | ||
932 | is_paused = false; | ||
933 | is_error = false; | ||
934 | |||
935 | rec_buffer = (unsigned char*)(((long)audiobuf + 15) & ~15); | ||
936 | enc_buffer = rec_buffer + NUM_CHUNKS * CHUNK_SIZE + MAX_FEED_SIZE; | ||
937 | /* 8000Bytes at audiobufend */ | ||
938 | enc_buffer_size = audiobufend - enc_buffer - 8000; | ||
939 | |||
940 | SET_IIS_PLAY(0x800); /* Stop any playback */ | ||
941 | AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ | ||
942 | DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */ | ||
943 | |||
944 | DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */ | ||
945 | DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ | ||
946 | DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2; | ||
947 | ICR7 = 0x1c; /* Enable interrupt at level 7, priority 0 */ | ||
948 | IMR &= ~(1<<15); /* bit 15 is DMA1 */ | ||
949 | |||
950 | #ifdef HAVE_SPDIF_IN | ||
951 | PHASECONFIG = 0x34; /* Gain = 3*2^13, source = EBUIN */ | ||
952 | #endif | ||
953 | pcmrec_dma_start(); | ||
954 | |||
955 | init_done = 1; | ||
956 | } | ||
957 | 1341 | ||
958 | static void pcmrec_close(void) | 1342 | pcmrec_new_stream(filename, |
959 | { | 1343 | CHUNKF_START_FILE | CHUNKF_END_FILE, |
960 | DMAROUTE = (DMAROUTE & 0xffff00ff); | 1344 | 0); |
961 | ICR7 = 0x00; /* Disable interrupt */ | ||
962 | IMR |= (1<<15); /* bit 15 is DMA1 */ | ||
963 | 1345 | ||
964 | pcmrec_dma_stop(); | 1346 | not_recording: |
965 | 1347 | pcm_thread_signal_event(PCMREC_NEW_FILE); | |
966 | /* Reset PDIR2 data flow */ | 1348 | logf("pcmrec_new_file done"); |
967 | DATAINCONTROL = 0x200; | 1349 | } /* pcmrec_new_file */ |
968 | close_done = true; | ||
969 | init_done = false; | ||
970 | } | ||
971 | 1350 | ||
1351 | static void pcmrec_thread(void) __attribute__((noreturn)); | ||
972 | static void pcmrec_thread(void) | 1352 | static void pcmrec_thread(void) |
973 | { | 1353 | { |
974 | struct event ev; | 1354 | struct event ev; |
975 | 1355 | ||
976 | logf("thread pcmrec start"); | 1356 | logf("thread pcmrec start"); |
977 | 1357 | ||
978 | error_count = 0; | ||
979 | |||
980 | while(1) | 1358 | while(1) |
981 | { | 1359 | { |
982 | queue_wait_w_tmo(&pcmrec_queue, &ev, HZ / 4); | 1360 | if (is_recording) |
1361 | { | ||
1362 | /* Poll periodically to flush data */ | ||
1363 | queue_wait_w_tmo(&pcmrec_queue, &ev, HZ/5); | ||
1364 | |||
1365 | if (ev.id == SYS_TIMEOUT) | ||
1366 | { | ||
1367 | pcmrec_flush(0); /* flush if getting full */ | ||
1368 | continue; | ||
1369 | } | ||
1370 | } | ||
1371 | else | ||
1372 | { | ||
1373 | /* Not doing anything - sit and wait for commands */ | ||
1374 | queue_wait(&pcmrec_queue, &ev); | ||
1375 | } | ||
983 | 1376 | ||
984 | switch (ev.id) | 1377 | switch (ev.id) |
985 | { | 1378 | { |
@@ -992,13 +1385,17 @@ static void pcmrec_thread(void) | |||
992 | break; | 1385 | break; |
993 | 1386 | ||
994 | case PCMREC_START: | 1387 | case PCMREC_START: |
995 | pcmrec_start(); | 1388 | pcmrec_start((const char *)ev.data); |
996 | break; | 1389 | break; |
997 | 1390 | ||
998 | case PCMREC_STOP: | 1391 | case PCMREC_STOP: |
999 | pcmrec_stop(); | 1392 | pcmrec_stop(); |
1000 | break; | 1393 | break; |
1001 | 1394 | ||
1395 | case PCMREC_FINISH_STOP: | ||
1396 | pcmrec_finish_stop(); | ||
1397 | break; | ||
1398 | |||
1002 | case PCMREC_PAUSE: | 1399 | case PCMREC_PAUSE: |
1003 | pcmrec_pause(); | 1400 | pcmrec_pause(); |
1004 | break; | 1401 | break; |
@@ -1008,11 +1405,11 @@ static void pcmrec_thread(void) | |||
1008 | break; | 1405 | break; |
1009 | 1406 | ||
1010 | case PCMREC_NEW_FILE: | 1407 | case PCMREC_NEW_FILE: |
1011 | pcmrec_new_file(); | 1408 | pcmrec_new_file((const char *)ev.data); |
1012 | break; | 1409 | break; |
1013 | 1410 | ||
1014 | case SYS_TIMEOUT: | 1411 | case PCMREC_FLUSH_NUM: |
1015 | pcmrec_callback(false); | 1412 | pcmrec_flush((unsigned)ev.data); |
1016 | break; | 1413 | break; |
1017 | 1414 | ||
1018 | case SYS_USB_CONNECTED: | 1415 | case SYS_USB_CONNECTED: |
@@ -1023,140 +1420,267 @@ static void pcmrec_thread(void) | |||
1023 | usb_wait_for_disconnect(&pcmrec_queue); | 1420 | usb_wait_for_disconnect(&pcmrec_queue); |
1024 | } | 1421 | } |
1025 | break; | 1422 | break; |
1026 | } | 1423 | } /* end switch */ |
1027 | } | 1424 | } /* end while */ |
1425 | } /* pcmrec_thread */ | ||
1028 | 1426 | ||
1029 | logf("thread pcmrec done"); | 1427 | /****************************************************************************/ |
1030 | } | 1428 | /* */ |
1429 | /* following functions will be called by the encoder codec */ | ||
1430 | /* */ | ||
1431 | /****************************************************************************/ | ||
1031 | 1432 | ||
1032 | /* Select VINL & VINR source: 0=Line-in, 1=FM Radio */ | 1433 | /* pass the encoder settings to the encoder */ |
1033 | void pcm_rec_mux(int source) | 1434 | void enc_get_inputs(struct enc_inputs *inputs) |
1034 | { | 1435 | { |
1035 | #ifdef IRIVER_H300_SERIES | 1436 | inputs->sample_rate = sample_rate; |
1036 | if(source == 0) | 1437 | inputs->num_channels = num_channels; |
1037 | and_l(~0x40000000, &GPIO_OUT); /* Line In */ | 1438 | inputs->config = &enc_config; |
1038 | else | 1439 | } /* enc_get_inputs */ |
1039 | or_l(0x40000000, &GPIO_OUT); /* FM radio */ | ||
1040 | 1440 | ||
1041 | or_l(0x40000000, &GPIO_ENABLE); | 1441 | /* set the encoder dimensions (called by encoder codec at initialization and |
1042 | or_l(0x40000000, &GPIO_FUNCTION); | 1442 | termination) */ |
1043 | #elif defined(IRIVER_H100_SERIES) | 1443 | void enc_set_parameters(struct enc_parameters *params) |
1044 | if(source == 0) | 1444 | { |
1045 | and_l(~0x00800000, &GPIO_OUT); /* Line In */ | 1445 | size_t bufsize, resbytes; |
1046 | else | ||
1047 | or_l(0x00800000, &GPIO_OUT); /* FM radio */ | ||
1048 | 1446 | ||
1049 | or_l(0x00800000, &GPIO_ENABLE); | 1447 | logf("enc_set_parameters"); |
1050 | or_l(0x00800000, &GPIO_FUNCTION); | ||
1051 | 1448 | ||
1052 | #elif defined(IAUDIO_X5) | 1449 | if (!params) |
1053 | if(source == 0) | 1450 | { |
1054 | or_l((1<<29), &GPIO_OUT); /* Line In */ | 1451 | logf("reset"); |
1055 | else | 1452 | /* Encoder is terminating */ |
1056 | and_l(~(1<<29), &GPIO_OUT); /* FM radio */ | 1453 | memset(&enc_config, 0, sizeof (enc_config)); |
1454 | enc_sample_rate = 0; | ||
1455 | return; | ||
1456 | } | ||
1457 | |||
1458 | enc_sample_rate = params->enc_sample_rate; | ||
1459 | logf("enc sampr:%d", enc_sample_rate); | ||
1460 | |||
1461 | pcm_rd_pos = dma_wr_pos; | ||
1462 | |||
1463 | enc_config.afmt = params->afmt; | ||
1464 | /* addition of the header is always implied - chunk size 4-byte aligned */ | ||
1465 | enc_chunk_size = | ||
1466 | ALIGN_UP_P2(ENC_CHUNK_HDR_SIZE + params->chunk_size, 2); | ||
1467 | enc_data_size = enc_chunk_size - ENC_CHUNK_HDR_SIZE; | ||
1468 | enc_events_callback = params->events_callback; | ||
1469 | |||
1470 | logf("chunk size:%d", enc_chunk_size); | ||
1471 | |||
1472 | /*** Configure the buffers ***/ | ||
1473 | |||
1474 | /* Layout of recording buffer: | ||
1475 | * [ax] = possible alignment x multiple | ||
1476 | * [sx] = possible size alignment of x multiple | ||
1477 | * |[a16]|[s4]:PCM Buffer+PCM Guard|[s4 each]:Encoder Chunks|-> | ||
1478 | * |[[s4]:Reserved Bytes]|Filename Queue->|[space]| | ||
1479 | */ | ||
1480 | resbytes = ALIGN_UP_P2(params->reserve_bytes, 2); | ||
1481 | logf("resbytes:%d", resbytes); | ||
1482 | |||
1483 | bufsize = rec_buffer_size - (enc_buffer - pcm_buffer) - | ||
1484 | resbytes - FNQ_MIN_NUM_PATHS*MAX_PATH; | ||
1485 | |||
1486 | enc_num_chunks = bufsize / enc_chunk_size; | ||
1487 | logf("num chunks:%d", enc_num_chunks); | ||
1057 | 1488 | ||
1058 | or_l((1<<29), &GPIO_ENABLE); | 1489 | /* get real amount used by encoder chunks */ |
1059 | or_l((1<<29), &GPIO_FUNCTION); | 1490 | bufsize = enc_num_chunks*enc_chunk_size; |
1491 | logf("enc size:%d", bufsize); | ||
1492 | |||
1493 | /* panic boost thread priority at 1 second remaining */ | ||
1494 | panic_threshold = enc_num_chunks - | ||
1495 | (4*sample_rate + (enc_chunk_size-1)) / enc_chunk_size; | ||
1496 | if (panic_threshold < 0) | ||
1497 | panic_threshold = 0; | ||
1498 | |||
1499 | logf("panic thr:%d", panic_threshold); | ||
1500 | |||
1501 | /** set OUT parameters **/ | ||
1502 | params->enc_buffer = enc_buffer; | ||
1503 | params->buf_chunk_size = enc_chunk_size; | ||
1504 | params->num_chunks = enc_num_chunks; | ||
1505 | |||
1506 | /* calculate reserve buffer start and return pointer to encoder */ | ||
1507 | params->reserve_buffer = NULL; | ||
1508 | if (resbytes > 0) | ||
1509 | { | ||
1510 | params->reserve_buffer = enc_buffer + bufsize; | ||
1511 | bufsize += resbytes; | ||
1512 | } | ||
1060 | 1513 | ||
1061 | /* iAudio x5 */ | 1514 | /* place filename queue at end of buffer using up whatever remains */ |
1515 | fnq_rd_pos = 0; /* reset */ | ||
1516 | fnq_wr_pos = 0; /* reset */ | ||
1517 | fn_queue = enc_buffer + bufsize; | ||
1518 | fnq_size = pcm_buffer + rec_buffer_size - fn_queue; | ||
1519 | fnq_size = ALIGN_DOWN(fnq_size, MAX_PATH); | ||
1520 | logf("fnq files: %d", fnq_size / MAX_PATH); | ||
1521 | |||
1522 | #if 0 | ||
1523 | logf("ab :%08X", (unsigned long)audiobuf); | ||
1524 | logf("pcm:%08X", (unsigned long)pcm_buffer); | ||
1525 | logf("enc:%08X", (unsigned long)enc_buffer); | ||
1526 | logf("res:%08X", (unsigned long)params->reserve_buffer); | ||
1527 | logf("fnq:%08X", (unsigned long)fn_queue); | ||
1528 | logf("end:%08X", (unsigned long)fn_queue + fnq_size); | ||
1529 | logf("abe:%08X", (unsigned long)audiobufend); | ||
1062 | #endif | 1530 | #endif |
1063 | } | ||
1064 | 1531 | ||
1532 | /* init all chunk headers and reset indexes */ | ||
1533 | enc_rd_index = 0; | ||
1534 | for (enc_wr_index = enc_num_chunks; enc_wr_index > 0; ) | ||
1535 | GET_ENC_CHUNK(--enc_wr_index)->flags = 0; | ||
1065 | 1536 | ||
1066 | /****************************************************************************/ | 1537 | logf("enc_set_parameters done"); |
1067 | /* */ | 1538 | } /* enc_set_parameters */ |
1068 | /* following functions will be called by the encoder codec */ | ||
1069 | /* */ | ||
1070 | /****************************************************************************/ | ||
1071 | 1539 | ||
1072 | /* pass the encoder buffer pointer/size, mono/stereo, quality to the encoder */ | 1540 | /* return encoder chunk at current write position */ |
1073 | void enc_get_inputs(int *buffer_size, int *channels, int *quality) | 1541 | struct enc_chunk_hdr * enc_get_chunk(void) |
1074 | { | 1542 | { |
1075 | *buffer_size = enc_buffer_size; | 1543 | struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index); |
1076 | *channels = enc_channels; | 1544 | chunk->flags &= CHUNKF_START_FILE; |
1077 | *quality = enc_quality; | ||
1078 | } | ||
1079 | 1545 | ||
1080 | /* set the encoder dimensions (called by encoder codec at initialization) */ | 1546 | if (!is_recording) |
1081 | void enc_set_parameters(int chunk_size, int num_chunks, int samp_per_chunk, | 1547 | chunk->flags |= CHUNKF_PRERECORD; |
1082 | char *head_ptr, int head_size, int enc_id) | ||
1083 | { | ||
1084 | /* set read_pos just in front of current write_pos */ | ||
1085 | read_pos = (write_pos - CHUNK_SIZE) & CHUNK_MASK; | ||
1086 | |||
1087 | enc_rd_index = 0; /* reset */ | ||
1088 | enc_wr_index = 0; /* reset */ | ||
1089 | enc_chunk_size = chunk_size; /* max chunk size */ | ||
1090 | enc_num_chunks = num_chunks; /* total number of chunks */ | ||
1091 | enc_samp_per_chunk = samp_per_chunk; /* pcm samples / encoderchunk */ | ||
1092 | enc_head_buffer = head_ptr; /* optional file header data (wav) */ | ||
1093 | enc_head_size = head_size; /* optional file header data (wav) */ | ||
1094 | audio_enc_id = enc_id; /* AFMT_* id */ | ||
1095 | } | ||
1096 | 1548 | ||
1097 | /* allocate encoder chunk */ | 1549 | return chunk; |
1098 | unsigned int *enc_alloc_chunk(void) | 1550 | } /* enc_get_chunk */ |
1099 | { | ||
1100 | return (unsigned int*)(enc_buffer + enc_wr_index * enc_chunk_size); | ||
1101 | } | ||
1102 | 1551 | ||
1103 | /* free previously allocated encoder chunk */ | 1552 | /* releases the current chunk into the available chunks */ |
1104 | void enc_free_chunk(void) | 1553 | void enc_finish_chunk(void) |
1105 | { | 1554 | { |
1106 | unsigned long *enc_chunk; | 1555 | struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index); |
1107 | 1556 | ||
1108 | enc_chunk = GET_ENC_CHUNK(enc_wr_index); | 1557 | /* encoder may have set error flag or written too much data */ |
1109 | curr_chunk_cnt++; | 1558 | if ((long)chunk->flags < 0 || chunk->enc_size > enc_data_size) |
1110 | /* curr_bit_rate += *enc_chunk * 44100 * 8 / (enc_samp_per_chunk * 1000); */ | 1559 | { |
1111 | curr_bit_rate += *enc_chunk * 441 * 8 / (enc_samp_per_chunk * 10 ); | 1560 | is_error = true; |
1112 | avrg_bit_rate = (curr_bit_rate + curr_chunk_cnt / 2) / curr_chunk_cnt; | ||
1113 | 1561 | ||
1114 | /* advance enc_wr_index to the next chunk */ | 1562 | #ifdef ROCKBOX_HAS_LOGF |
1115 | enc_wr_index = (enc_wr_index + 1) % enc_num_chunks; | 1563 | if (chunk->enc_size > enc_data_size) |
1564 | { | ||
1565 | /* illegal to scribble over next chunk */ | ||
1566 | logf("finish chk ovf: %d>%d", chunk->enc_size, enc_data_size); | ||
1567 | } | ||
1568 | else | ||
1569 | { | ||
1570 | /* encoder set error flag */ | ||
1571 | logf("finish chk enc error"); | ||
1572 | } | ||
1573 | #endif | ||
1574 | } | ||
1575 | |||
1576 | /* advance enc_wr_index to the next encoder chunk */ | ||
1577 | INC_ENC_INDEX(enc_wr_index); | ||
1116 | 1578 | ||
1117 | /* buffer full: advance enc_rd_index (for prerecording purpose) */ | 1579 | if (enc_rd_index != enc_wr_index) |
1118 | if (enc_rd_index == enc_wr_index) | ||
1119 | { | 1580 | { |
1120 | enc_rd_index = (enc_rd_index + 1) % enc_num_chunks; | 1581 | num_rec_bytes += chunk->enc_size; |
1582 | accum_rec_bytes += chunk->enc_size; | ||
1583 | num_rec_samples += chunk->num_pcm; | ||
1584 | accum_pcm_samples += chunk->num_pcm; | ||
1121 | } | 1585 | } |
1122 | } | 1586 | else if (is_recording) /* buffer full */ |
1587 | { | ||
1588 | /* keep current position */ | ||
1589 | logf("enc_buffer ovf"); | ||
1590 | DEC_ENC_INDEX(enc_wr_index); | ||
1591 | } | ||
1592 | else | ||
1593 | { | ||
1594 | /* advance enc_rd_index for prerecording */ | ||
1595 | INC_ENC_INDEX(enc_rd_index); | ||
1596 | } | ||
1597 | } /* enc_finish_chunk */ | ||
1123 | 1598 | ||
1124 | /* checks near empty state on wav input buffer */ | 1599 | /* checks near empty state on pcm input buffer */ |
1125 | int enc_wavbuf_near_empty(void) | 1600 | int enc_pcm_buf_near_empty(void) |
1126 | { | 1601 | { |
1127 | /* less than 1sec raw data? => unboost encoder */ | 1602 | /* less than 1sec raw data? => unboost encoder */ |
1128 | if (((write_pos - read_pos) & CHUNK_MASK) < 44100*4) | 1603 | size_t avail = (dma_wr_pos - pcm_rd_pos) & PCM_CHUNK_MASK; |
1129 | return 1; | 1604 | return avail < (sample_rate << 2) ? 1 : 0; |
1130 | else | 1605 | } /* enc_pcm_buf_near_empty */ |
1131 | return 0; | ||
1132 | } | ||
1133 | 1606 | ||
1134 | /* passes a pointer to next chunk of unprocessed wav data */ | 1607 | /* passes a pointer to next chunk of unprocessed wav data */ |
1135 | char *enc_get_wav_data(int size) | 1608 | /* TODO: this really should give the actual size returned */ |
1609 | unsigned char * enc_get_pcm_data(size_t size) | ||
1136 | { | 1610 | { |
1137 | char *ptr; | 1611 | size_t avail = (dma_wr_pos - pcm_rd_pos) & PCM_CHUNK_MASK; |
1138 | int avail; | ||
1139 | 1612 | ||
1140 | /* limit the requested pcm data size */ | 1613 | /* limit the requested pcm data size */ |
1141 | if(size > MAX_FEED_SIZE) | 1614 | if (size > PCM_MAX_FEED_SIZE) |
1142 | size = MAX_FEED_SIZE; | 1615 | size = PCM_MAX_FEED_SIZE; |
1143 | |||
1144 | avail = (write_pos - read_pos) & CHUNK_MASK; | ||
1145 | 1616 | ||
1146 | if (avail >= size) | 1617 | if (avail >= size) |
1147 | { | 1618 | { |
1148 | ptr = rec_buffer + read_pos; | 1619 | unsigned char *ptr = pcm_buffer + pcm_rd_pos; |
1149 | read_pos = (read_pos + size) & CHUNK_MASK; | 1620 | pcm_rd_pos = (pcm_rd_pos + size) & PCM_CHUNK_MASK; |
1150 | 1621 | ||
1151 | /* ptr must point to continous data at wraparound position */ | 1622 | /* ptr must point to continous data at wraparound position */ |
1152 | if (read_pos < size) | 1623 | if ((size_t)pcm_rd_pos < size) |
1153 | memcpy(rec_buffer + NUM_CHUNKS * CHUNK_SIZE, | 1624 | memcpy(pcm_buffer + PCM_NUM_CHUNKS*PCM_CHUNK_SIZE, |
1154 | rec_buffer, read_pos); | 1625 | pcm_buffer, pcm_rd_pos); |
1155 | 1626 | ||
1156 | wav_queue_empty = false; | 1627 | wav_queue_empty = false; |
1157 | return ptr; | 1628 | return ptr; |
1158 | } | 1629 | } |
1159 | 1630 | ||
1631 | /* not enough data available - encoder should idle */ | ||
1160 | wav_queue_empty = true; | 1632 | wav_queue_empty = true; |
1161 | return NULL; | 1633 | return NULL; |
1162 | } | 1634 | } /* enc_get_pcm_data */ |
1635 | |||
1636 | /* puts some pcm data back in the queue */ | ||
1637 | size_t enc_unget_pcm_data(size_t size) | ||
1638 | { | ||
1639 | /* can't let DMA advance write position when doing this */ | ||
1640 | int level = set_irq_level(HIGHEST_IRQ_LEVEL); | ||
1641 | |||
1642 | if (pcm_rd_pos != dma_wr_pos) | ||
1643 | { | ||
1644 | /* disallow backing up into current DMA write chunk */ | ||
1645 | size_t old_avail = (pcm_rd_pos - dma_wr_pos - PCM_CHUNK_SIZE) | ||
1646 | & PCM_CHUNK_MASK; | ||
1647 | |||
1648 | /* limit size to amount of old data remaining */ | ||
1649 | if (size > old_avail) | ||
1650 | size = old_avail; | ||
1651 | |||
1652 | pcm_rd_pos = (pcm_rd_pos - size) & PCM_CHUNK_MASK; | ||
1653 | } | ||
1654 | |||
1655 | set_irq_level(level); | ||
1656 | |||
1657 | return size; | ||
1658 | } /* enc_unget_pcm_data */ | ||
1659 | |||
1660 | /** Low level pcm recording apis **/ | ||
1661 | |||
1662 | /**************************************************************************** | ||
1663 | * Functions that do not require targeted implementation but only a targeted | ||
1664 | * interface | ||
1665 | */ | ||
1666 | void pcm_record_data(pcm_more_callback_type more_ready, | ||
1667 | unsigned char *start, size_t size) | ||
1668 | { | ||
1669 | pcm_callback_more_ready = more_ready; | ||
1670 | |||
1671 | if (!(start && size)) | ||
1672 | { | ||
1673 | size = 0; | ||
1674 | if (more_ready) | ||
1675 | more_ready(&start, &size); | ||
1676 | } | ||
1677 | |||
1678 | if (start && size) | ||
1679 | pcm_rec_dma_start(start, size); | ||
1680 | } /* pcm_record_data */ | ||
1681 | |||
1682 | void pcm_stop_recording(void) | ||
1683 | { | ||
1684 | if (pcm_recording) | ||
1685 | pcm_rec_dma_stop(); | ||
1686 | } /* pcm_stop_recording */ | ||
diff --git a/firmware/system.c b/firmware/system.c index 242d84d16c..96d5f96602 100644 --- a/firmware/system.c +++ b/firmware/system.c | |||
@@ -390,8 +390,7 @@ int system_memory_guard(int newmode) | |||
390 | (void)newmode; | 390 | (void)newmode; |
391 | return 0; | 391 | return 0; |
392 | } | 392 | } |
393 | #elif defined(CPU_COLDFIRE) | 393 | |
394 | /* system code is in target tree for all coldfire targets */ | ||
395 | #elif CONFIG_CPU == SH7034 | 394 | #elif CONFIG_CPU == SH7034 |
396 | #include "led.h" | 395 | #include "led.h" |
397 | #include "system.h" | 396 | #include "system.h" |
diff --git a/firmware/target/coldfire/iaudio/x5/system-x5.c b/firmware/target/coldfire/iaudio/x5/system-x5.c index 6be6d25ce0..30a4f6e71b 100644 --- a/firmware/target/coldfire/iaudio/x5/system-x5.c +++ b/firmware/target/coldfire/iaudio/x5/system-x5.c | |||
@@ -42,7 +42,7 @@ void set_cpu_frequency(long frequency) | |||
42 | PLLCR &= ~1; /* Bypass mode */ | 42 | PLLCR &= ~1; /* Bypass mode */ |
43 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); | 43 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); |
44 | RECALC_DELAYS(CPUFREQ_MAX); | 44 | RECALC_DELAYS(CPUFREQ_MAX); |
45 | PLLCR = 0x13442045; | 45 | PLLCR = 0x03042045 | (PLLCR & 0x70C00000); |
46 | CSCR0 = 0x00001180; /* Flash: 4 wait states */ | 46 | CSCR0 = 0x00001180; /* Flash: 4 wait states */ |
47 | CSCR1 = 0x00000980; /* LCD: 2 wait states */ | 47 | CSCR1 = 0x00000980; /* LCD: 2 wait states */ |
48 | while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. | 48 | while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. |
@@ -60,7 +60,7 @@ void set_cpu_frequency(long frequency) | |||
60 | PLLCR &= ~1; /* Bypass mode */ | 60 | PLLCR &= ~1; /* Bypass mode */ |
61 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); | 61 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); |
62 | RECALC_DELAYS(CPUFREQ_NORMAL); | 62 | RECALC_DELAYS(CPUFREQ_NORMAL); |
63 | PLLCR = 0x16430045; | 63 | PLLCR = 0x06030045 | (PLLCR & 0x70C00000); |
64 | CSCR0 = 0x00000580; /* Flash: 1 wait state */ | 64 | CSCR0 = 0x00000580; /* Flash: 1 wait state */ |
65 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ | 65 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ |
66 | while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. | 66 | while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. |
@@ -77,7 +77,8 @@ void set_cpu_frequency(long frequency) | |||
77 | PLLCR &= ~1; /* Bypass mode */ | 77 | PLLCR &= ~1; /* Bypass mode */ |
78 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); | 78 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); |
79 | RECALC_DELAYS(CPUFREQ_DEFAULT); | 79 | RECALC_DELAYS(CPUFREQ_DEFAULT); |
80 | PLLCR = 0x10400200; /* Power down PLL, but keep CLSEL and CRSEL */ | 80 | /* Power down PLL, but keep CLSEL and CRSEL */ |
81 | PLLCR = 0x00000200 | (PLLCR & 0x70C00000); | ||
81 | CSCR0 = 0x00000180; /* Flash: 0 wait states */ | 82 | CSCR0 = 0x00000180; /* Flash: 0 wait states */ |
82 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ | 83 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ |
83 | DCR = (0x8000 | DEFAULT_REFRESH_TIMER); /* Refresh timer */ | 84 | DCR = (0x8000 | DEFAULT_REFRESH_TIMER); /* Refresh timer */ |
diff --git a/firmware/target/coldfire/iriver/system-iriver.c b/firmware/target/coldfire/iriver/system-iriver.c index 3517788641..43ba4eeed4 100644 --- a/firmware/target/coldfire/iriver/system-iriver.c +++ b/firmware/target/coldfire/iriver/system-iriver.c | |||
@@ -81,7 +81,7 @@ void set_cpu_frequency(long frequency) | |||
81 | PLLCR &= ~1; /* Bypass mode */ | 81 | PLLCR &= ~1; /* Bypass mode */ |
82 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); | 82 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); |
83 | RECALC_DELAYS(CPUFREQ_MAX); | 83 | RECALC_DELAYS(CPUFREQ_MAX); |
84 | PLLCR = 0x11c56005; | 84 | PLLCR = 0x01056005 | (PLLCR & 0x70c00000); |
85 | CSCR0 = 0x00001180; /* Flash: 4 wait states */ | 85 | CSCR0 = 0x00001180; /* Flash: 4 wait states */ |
86 | CSCR1 = 0x00001580; /* LCD: 5 wait states */ | 86 | CSCR1 = 0x00001580; /* LCD: 5 wait states */ |
87 | #if CONFIG_USBOTG == USBOTG_ISP1362 | 87 | #if CONFIG_USBOTG == USBOTG_ISP1362 |
@@ -108,7 +108,7 @@ void set_cpu_frequency(long frequency) | |||
108 | PLLCR &= ~1; /* Bypass mode */ | 108 | PLLCR &= ~1; /* Bypass mode */ |
109 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); | 109 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); |
110 | RECALC_DELAYS(CPUFREQ_NORMAL); | 110 | RECALC_DELAYS(CPUFREQ_NORMAL); |
111 | PLLCR = 0x13c5e005; | 111 | PLLCR = 0x0305e005 | (PLLCR & 0x70c00000); |
112 | CSCR0 = 0x00000580; /* Flash: 1 wait state */ | 112 | CSCR0 = 0x00000580; /* Flash: 1 wait state */ |
113 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ | 113 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ |
114 | #if CONFIG_USBOTG == USBOTG_ISP1362 | 114 | #if CONFIG_USBOTG == USBOTG_ISP1362 |
@@ -134,7 +134,8 @@ void set_cpu_frequency(long frequency) | |||
134 | PLLCR &= ~1; /* Bypass mode */ | 134 | PLLCR &= ~1; /* Bypass mode */ |
135 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); | 135 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); |
136 | RECALC_DELAYS(CPUFREQ_DEFAULT); | 136 | RECALC_DELAYS(CPUFREQ_DEFAULT); |
137 | PLLCR = 0x10c00200; /* Power down PLL, but keep CLSEL and CRSEL */ | 137 | /* Power down PLL, but keep CLSEL and CRSEL */ |
138 | PLLCR = 0x00000200 | (PLLCR & 0x70c00000); | ||
138 | CSCR0 = 0x00000180; /* Flash: 0 wait states */ | 139 | CSCR0 = 0x00000180; /* Flash: 0 wait states */ |
139 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ | 140 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ |
140 | #if CONFIG_USBOTG == USBOTG_ISP1362 | 141 | #if CONFIG_USBOTG == USBOTG_ISP1362 |
diff --git a/firmware/target/coldfire/system-coldfire.c b/firmware/target/coldfire/system-coldfire.c index 66e4feb154..2fc81496db 100644 --- a/firmware/target/coldfire/system-coldfire.c +++ b/firmware/target/coldfire/system-coldfire.c | |||
@@ -310,3 +310,10 @@ int system_memory_guard(int newmode) | |||
310 | 310 | ||
311 | return oldmode; | 311 | return oldmode; |
312 | } | 312 | } |
313 | |||
314 | /* allow setting of audio clock related bits */ | ||
315 | void coldfire_set_pllcr_audio_bits(long bits) | ||
316 | { | ||
317 | PLLCR = (PLLCR & ~0x70c00000) | (bits & 0x70c00000); | ||
318 | } | ||
319 | |||
diff --git a/firmware/target/coldfire/system-target.h b/firmware/target/coldfire/system-target.h index 03852115ad..24e3fb8705 100644 --- a/firmware/target/coldfire/system-target.h +++ b/firmware/target/coldfire/system-target.h | |||
@@ -110,6 +110,28 @@ static inline unsigned long swap32(unsigned long value) | |||
110 | return value; | 110 | return value; |
111 | } | 111 | } |
112 | 112 | ||
113 | static inline unsigned long swap_odd_even32(unsigned long value) | ||
114 | { | ||
115 | /* | ||
116 | result[31..24],[15.. 8] = value[23..16],[ 7.. 0] | ||
117 | result[23..16],[ 7.. 0] = value[31..24],[15.. 8] | ||
118 | */ | ||
119 | unsigned long mask = 0x00FF00FF; | ||
120 | |||
121 | asm ( /* val = ABCD */ | ||
122 | "and.l %[val],%[mask] \n" /* mask = .B.D */ | ||
123 | "eor.l %[mask],%[val] \n" /* val = A.C. */ | ||
124 | "lsl.l #8,%[mask] \n" /* mask = B.D. */ | ||
125 | "lsr.l #8,%[val] \n" /* val = .A.C */ | ||
126 | "or.l %[mask],%[val] \n" /* val = BADC */ | ||
127 | : /* outputs */ | ||
128 | [val] "+d"(value), | ||
129 | [mask]"+d"(mask) | ||
130 | ); | ||
131 | |||
132 | return value; | ||
133 | } | ||
134 | |||
113 | static inline void invalidate_icache(void) | 135 | static inline void invalidate_icache(void) |
114 | { | 136 | { |
115 | asm volatile ("move.l #0x01000000,%d0\n" | 137 | asm volatile ("move.l #0x01000000,%d0\n" |
@@ -118,6 +140,13 @@ static inline void invalidate_icache(void) | |||
118 | "movec.l %d0,%cacr"); | 140 | "movec.l %d0,%cacr"); |
119 | } | 141 | } |
120 | 142 | ||
143 | #ifdef IAUDIO_X5 | ||
144 | #define DEFAULT_PLLCR_AUDIO_BITS 0x10400000 | ||
145 | #else | ||
146 | #define DEFAULT_PLLCR_AUDIO_BITS 0x10c00000 | ||
147 | #endif | ||
148 | void coldfire_set_pllcr_audio_bits(long bits); | ||
149 | |||
121 | /* 11.2896 MHz */ | 150 | /* 11.2896 MHz */ |
122 | #define CPUFREQ_DEFAULT_MULT 1 | 151 | #define CPUFREQ_DEFAULT_MULT 1 |
123 | #define CPUFREQ_DEFAULT (CPUFREQ_DEFAULT_MULT * CPU_FREQ) | 152 | #define CPUFREQ_DEFAULT (CPUFREQ_DEFAULT_MULT * CPU_FREQ) |
diff --git a/firmware/thread.c b/firmware/thread.c index 6a94a52333..4094877742 100644 --- a/firmware/thread.c +++ b/firmware/thread.c | |||
@@ -711,6 +711,14 @@ int thread_set_priority(struct thread_entry *thread, int priority) | |||
711 | 711 | ||
712 | return old_priority; | 712 | return old_priority; |
713 | } | 713 | } |
714 | |||
715 | int thread_get_priority(struct thread_entry *thread) | ||
716 | { | ||
717 | if (thread == NULL) | ||
718 | thread = cores[CURRENT_CORE].running; | ||
719 | |||
720 | return thread->priority; | ||
721 | } | ||
714 | #endif | 722 | #endif |
715 | 723 | ||
716 | void init_threads(void) | 724 | void init_threads(void) |