diff options
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) |