summaryrefslogtreecommitdiff
path: root/firmware/target/arm/pcm-pp.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-06-29 06:37:04 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-06-29 06:37:04 +0000
commita2b6703a369f6cdbfec1f150c408dadc877631fb (patch)
tree3145a8c1372c44711d38feefeba39c7d4098f139 /firmware/target/arm/pcm-pp.c
parent8411614b8a068a4f274c3841aa55aab1df1bc246 (diff)
downloadrockbox-a2b6703a369f6cdbfec1f150c408dadc877631fb.tar.gz
rockbox-a2b6703a369f6cdbfec1f150c408dadc877631fb.zip
Commit FS#12150 - Fully-functional audio mixer - and finally whip old limitations about playback of voice and other sounds when paused. Channels are independent in state and amplitude. Fade on stop/pause is handled by the channel's volume control rather than global volume which means it now works from anywhere. Opens up the possibility of plugin sounds during music playback by merely adding an additional channel enum. If any PCM drivers were not properly modified, see one of the last comments in the task for a description of the simple change that is expected. Some params are tunable in firmware/export/pcm-mixer.h as well.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30097 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/pcm-pp.c')
-rw-r--r--firmware/target/arm/pcm-pp.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c
index c446f98fcf..704296d407 100644
--- a/firmware/target/arm/pcm-pp.c
+++ b/firmware/target/arm/pcm-pp.c
@@ -26,6 +26,7 @@
26#include "sound.h" 26#include "sound.h"
27#include "pcm.h" 27#include "pcm.h"
28#include "pcm_sampr.h" 28#include "pcm_sampr.h"
29#include "pcm-internal.h"
29 30
30/** DMA **/ 31/** DMA **/
31 32
@@ -115,6 +116,7 @@ void pcm_dma_apply_settings(void)
115/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ 116/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
116void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void) 117void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
117{ 118{
119 bool new_buffer = false;
118 register size_t size; 120 register size_t size;
119 121
120 DMA0_STATUS; /* Clear any pending interrupt */ 122 DMA0_STATUS; /* Clear any pending interrupt */
@@ -136,9 +138,14 @@ void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
136 /* Set the new DMA values and activate channel */ 138 /* Set the new DMA values and activate channel */
137 DMA0_RAM_ADDR = dma_play_data.addr; 139 DMA0_RAM_ADDR = dma_play_data.addr;
138 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; 140 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
141
142 if (new_buffer)
143 pcm_play_dma_started_callback();
139 return; 144 return;
140 } 145 }
141 146
147 new_buffer = true;
148
142 /* Buffer empty. Try to get more. */ 149 /* Buffer empty. Try to get more. */
143 pcm_play_get_more_callback((void **)&dma_play_data.addr, 150 pcm_play_get_more_callback((void **)&dma_play_data.addr,
144 &dma_play_data.size); 151 &dma_play_data.size);
@@ -181,8 +188,9 @@ void fiq_playback(void)
181 * r0-r3 and r12 is a working register. 188 * r0-r3 and r12 is a working register.
182 */ 189 */
183 asm volatile ( 190 asm volatile (
184 "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */ 191 "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */
185 192
193 "mov r4, #0 \n" /* Was the callback called? */
186#if CONFIG_CPU == PP5002 194#if CONFIG_CPU == PP5002
187 "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */ 195 "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */
188 "ldr r12, [r12] \n" 196 "ldr r12, [r12] \n"
@@ -212,16 +220,13 @@ void fiq_playback(void)
212 "tst r1, #1 \n" /* two samples (one word) left? */ 220 "tst r1, #1 \n" /* two samples (one word) left? */
213 "ldrne r12, [r8], #4 \n" /* load two samples */ 221 "ldrne r12, [r8], #4 \n" /* load two samples */
214 "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ 222 "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
215
216 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
217 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
218#elif SAMPLE_SIZE == 32 223#elif SAMPLE_SIZE == 32
219 ".check_fifo: \n" 224 ".check_fifo: \n"
220 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ 225 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
221 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */ 226 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */
222 227
223 "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */ 228 "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */
224 "beq .exit \n" /* no complete pair? -> exit */ 229 "beq .fifo_fill_complete \n" /* no complete pair? -> exit */
225 "cmp r1, r9, lsr #2 \n" /* number of words from source */ 230 "cmp r1, r9, lsr #2 \n" /* number of words from source */
226 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ 231 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
227 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ 232 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
@@ -234,11 +239,23 @@ void fiq_playback(void)
234 "subs r1, r1, #1 \n" /* one more loop? */ 239 "subs r1, r1, #1 \n" /* one more loop? */
235 "bgt .fifo_loop \n" /* yes, continue */ 240 "bgt .fifo_loop \n" /* yes, continue */
236 241
242 ".fifo_fill_complete: \n"
243#endif
244 "cmp r4, #0 \n" /* If fill came after get_more... */
245 "beq .still_old_buffer \n"
246 "mov r4, #0 \n"
247 "ldr r2, =pcm_play_dma_started \n"
248 "ldrne r2, [r2] \n"
249 "cmp r2, #0 \n"
250 "movne lr, pc \n"
251 "bxne r2 \n"
252
253 ".still_old_buffer: \n"
237 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */ 254 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
238 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */ 255 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
239#endif
240 256
241 ".more_data: \n" 257 ".more_data: \n"
258 "mov r4, #1 \n" /* Remember we did this */
242 "ldr r2, =pcm_play_get_more_callback \n" 259 "ldr r2, =pcm_play_get_more_callback \n"
243 "mov r0, r11 \n" /* r0 = &p */ 260 "mov r0, r11 \n" /* r0 = &p */
244 "add r1, r11, #4 \n" /* r1 = &size */ 261 "add r1, r11, #4 \n" /* r1 = &size */
@@ -250,7 +267,7 @@ void fiq_playback(void)
250 267
251 ".exit: \n" /* (r9=0 if stopping, look above) */ 268 ".exit: \n" /* (r9=0 if stopping, look above) */
252 "stmia r11, { r8-r9 } \n" /* save p and size */ 269 "stmia r11, { r8-r9 } \n" /* save p and size */
253 "ldmfd sp!, { r0-r3, lr } \n" 270 "ldmfd sp!, { r0-r4, lr } \n"
254 "subs pc, lr, #4 \n" /* FIQ specific return sequence */ 271 "subs pc, lr, #4 \n" /* FIQ specific return sequence */
255 ".ltorg \n" 272 ".ltorg \n"
256 : /* These must only be integers! No regs */ 273 : /* These must only be integers! No regs */
@@ -264,6 +281,8 @@ void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR;
264/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ 281/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
265void fiq_playback(void) 282void fiq_playback(void)
266{ 283{
284 bool new_buffer = false;
285
267#if CONFIG_CPU == PP5002 286#if CONFIG_CPU == PP5002
268 inl(0xcf001040); 287 inl(0xcf001040);
269#endif 288#endif
@@ -271,6 +290,10 @@ void fiq_playback(void)
271 do { 290 do {
272 while (dma_play_data.size > 0) { 291 while (dma_play_data.size > 0) {
273 if (IIS_TX_FREE_COUNT < 2) { 292 if (IIS_TX_FREE_COUNT < 2) {
293 if (new_buffer) {
294 new_buffer = false;
295 pcm_play_dma_started_callback();
296 }
274 return; 297 return;
275 } 298 }
276#if SAMPLE_SIZE == 16 299#if SAMPLE_SIZE == 16
@@ -282,9 +305,15 @@ void fiq_playback(void)
282 dma_play_data.size -= 4; 305 dma_play_data.size -= 4;
283 } 306 }
284 307
308 if (new_buffer) {
309 new_buffer = false;
310 pcm_play_dma_started_callback();
311 }
312
285 /* p is empty, get some more data */ 313 /* p is empty, get some more data */
286 pcm_play_get_more_callback((void **)&dma_play_data.addr, 314 pcm_play_get_more_callback((void **)&dma_play_data.addr,
287 &dma_play_data.size); 315 &dma_play_data.size);
316 new_buffer = true;
288 } while (dma_play_data.size); 317 } while (dma_play_data.size);
289 318
290 /* No more data */ 319 /* No more data */