summaryrefslogtreecommitdiff
path: root/firmware/target/arm
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
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')
-rw-r--r--firmware/target/arm/as3525/pcm-as3525.c9
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c3
-rw-r--r--firmware/target/arm/pcm-mixer-armv4.c182
-rw-r--r--firmware/target/arm/pcm-mixer-armv5.c106
-rw-r--r--firmware/target/arm/pcm-mixer-armv6.c118
-rw-r--r--firmware/target/arm/pcm-pp.c43
-rw-r--r--firmware/target/arm/pcm-telechips.c26
-rw-r--r--firmware/target/arm/pnx0101/pcm-pnx0101.c13
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c3
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c5
-rw-r--r--firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c3
-rw-r--r--firmware/target/arm/s5l8700/pcm-s5l8700.c17
-rw-r--r--firmware/target/arm/s5l8702/pcm-s5l8702.c3
-rw-r--r--firmware/target/arm/tms320dm320/creative-zvm/pcm-creativezvm.c1
-rw-r--r--firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c3
15 files changed, 514 insertions, 21 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c
index 469833b05c..1b22d48f7f 100644
--- a/firmware/target/arm/as3525/pcm-as3525.c
+++ b/firmware/target/arm/as3525/pcm-as3525.c
@@ -29,6 +29,7 @@
29#include "as3514.h" 29#include "as3514.h"
30#include "audiohw.h" 30#include "audiohw.h"
31#include "mmu-arm.h" 31#include "mmu-arm.h"
32#include "pcm-internal.h"
32 33
33#define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA 34#define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA
34 * i.e. 32 bits at once (size of I2SO_DATA) 35 * i.e. 32 bits at once (size of I2SO_DATA)
@@ -104,9 +105,13 @@ static void dma_callback(void)
104 105
105 /* force writeback */ 106 /* force writeback */
106 clean_dcache_range(dma_start_addr, dma_start_size); 107 clean_dcache_range(dma_start_addr, dma_start_size);
108 play_start_pcm();
109 pcm_play_dma_started_callback();
110 }
111 else
112 {
113 play_start_pcm();
107 } 114 }
108
109 play_start_pcm();
110} 115}
111 116
112void pcm_play_dma_start(const void *addr, size_t size) 117void pcm_play_dma_start(const void *addr, size_t size)
diff --git a/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c
index c8c1283d12..1f6eef435a 100644
--- a/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c
@@ -26,6 +26,7 @@
26#include "ccm-imx31.h" 26#include "ccm-imx31.h"
27#include "sdma-imx31.h" 27#include "sdma-imx31.h"
28#include "mmu-imx31.h" 28#include "mmu-imx31.h"
29#include "pcm-internal.h"
29 30
30#define DMA_PLAY_CH_NUM 2 31#define DMA_PLAY_CH_NUM 2
31#define DMA_REC_CH_NUM 1 32#define DMA_REC_CH_NUM 1
@@ -105,6 +106,8 @@ static void play_dma_callback(void)
105 dma_play_bd.mode.command = TRANSFER_16BIT; 106 dma_play_bd.mode.command = TRANSFER_16BIT;
106 dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR; 107 dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
107 sdma_channel_run(DMA_PLAY_CH_NUM); 108 sdma_channel_run(DMA_PLAY_CH_NUM);
109
110 pcm_play_dma_started_callback();
108} 111}
109 112
110void pcm_play_lock(void) 113void pcm_play_lock(void)
diff --git a/firmware/target/arm/pcm-mixer-armv4.c b/firmware/target/arm/pcm-mixer-armv4.c
new file mode 100644
index 0000000000..4818544d7b
--- /dev/null
+++ b/firmware/target/arm/pcm-mixer-armv4.c
@@ -0,0 +1,182 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#define MIXER_OPTIMIZED_WRITE_SAMPLES
23#define MIXER_OPTIMIZED_MIX_SAMPLES
24
25/* Mix channels' samples and apply gain factors */
26static FORCE_INLINE void mix_samples(void *out,
27 void *src0,
28 int32_t src0_amp,
29 void *src1,
30 int32_t src1_amp,
31 size_t size)
32{
33 if (src0_amp == MIX_AMP_UNITY && src1_amp == MIX_AMP_UNITY)
34 {
35 /* Both are unity amplitude */
36 int32_t l0, l1, h0, h1;
37 asm volatile (
38 "1: \n"
39 "ldrsh %4, [%1], #2 \n"
40 "ldrsh %5, [%2], #2 \n"
41 "ldrsh %6, [%1], #2 \n"
42 "ldrsh %7, [%2], #2 \n"
43 "add %4, %4, %5 \n"
44 "add %6, %6, %7 \n"
45 "mov %5, %4, asr #15 \n"
46 "teq %5, %5, asr #31 \n"
47 "eorne %4, %8, %4, asr #31 \n"
48 "mov %7, %6, asr #15 \n"
49 "teq %7, %7, asr #31 \n"
50 "eorne %6, %8, %6, asr #31 \n"
51 "subs %3, %3, #4 \n"
52 "and %4, %4, %8, lsr #16 \n"
53 "orr %6, %4, %6, lsl #16 \n"
54 "str %6, [%0], #4 \n"
55 "bhi 1b \n"
56 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
57 "=&r"(l0), "=&r"(l1), "=&r"(h0), "=&r"(h1)
58 : "r"(0xffff7fff));
59 }
60 else if (src0_amp != MIX_AMP_UNITY && src1_amp != MIX_AMP_UNITY)
61 {
62 /* Neither are unity amplitude */
63 int32_t l0, l1, h0, h1;
64 asm volatile (
65 "1: \n"
66 "ldrsh %4, [%1], #2 \n"
67 "ldrsh %5, [%2], #2 \n"
68 "ldrsh %6, [%1], #2 \n"
69 "ldrsh %7, [%2], #2 \n"
70 "mul %4, %8, %4 \n"
71 "mul %5, %9, %5 \n"
72 "mul %6, %8, %6 \n"
73 "mul %7, %9, %7 \n"
74 "mov %4, %4, asr #16 \n"
75 "add %4, %4, %5, asr #16 \n"
76 "mov %6, %6, asr #16 \n"
77 "add %6, %6, %7, asr #16 \n"
78 "mov %5, %4, asr #15 \n"
79 "teq %5, %5, asr #31 \n"
80 "eorne %4, %10, %4, asr #31 \n"
81 "mov %7, %6, asr #15 \n"
82 "teq %7, %7, asr #31 \n"
83 "eorne %6, %10, %6, asr #31 \n"
84 "subs %3, %3, #4 \n"
85 "and %4, %4, %10, lsr #16 \n"
86 "orr %6, %4, %6, lsl #16 \n"
87 "str %6, [%0], #4 \n"
88 "bhi 1b \n"
89 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
90 "=&r"(l0), "=&r"(l1), "=&r"(h0), "=&r"(h1)
91 : "r"(src0_amp), "r"(src1_amp), "r"(0xffff7fff));
92 }
93 else
94 {
95 /* One is unity amplitude */
96 if (src0_amp != MIX_AMP_UNITY)
97 {
98 /* Keep unity in src0, amp0 */
99 int16_t *src_tmp = src0;
100 src0 = src1;
101 src1 = src_tmp;
102 src1_amp = src0_amp;
103 src0_amp = MIX_AMP_UNITY;
104 }
105
106 int32_t l0, l1, h0, h1;
107 asm volatile (
108 "1: \n"
109 "ldrsh %4, [%1], #2 \n"
110 "ldrsh %5, [%2], #2 \n"
111 "ldrsh %6, [%1], #2 \n"
112 "ldrsh %7, [%2], #2 \n"
113 "mul %5, %8, %5 \n"
114 "mul %7, %8, %7 \n"
115 "add %4, %4, %5, asr #16 \n"
116 "add %6, %6, %7, asr #16 \n"
117 "mov %5, %4, asr #15 \n"
118 "teq %5, %5, asr #31 \n"
119 "eorne %4, %9, %4, asr #31 \n"
120 "mov %7, %6, asr #15 \n"
121 "teq %7, %7, asr #31 \n"
122 "eorne %6, %9, %6, asr #31 \n"
123 "subs %3, %3, #4 \n"
124 "and %4, %4, %9, lsr #16 \n"
125 "orr %6, %4, %6, lsl #16 \n"
126 "str %6, [%0], #4 \n"
127 "bhi 1b \n"
128 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
129 "=&r"(l0), "=&r"(l1), "=&r"(h0), "=&r"(h1)
130 : "r"(src1_amp), "r"(0xffff7fff));
131 }
132}
133
134/* Write channel's samples and apply gain factor */
135static FORCE_INLINE void write_samples(void *out,
136 void *src,
137 int32_t amp,
138 size_t size)
139{
140 if (LIKELY(amp == MIX_AMP_UNITY))
141 {
142 /* Channel is unity amplitude */
143 asm volatile (
144 "ands r1, %2, #0x1f \n"
145 "beq 2f \n"
146 "1: \n"
147 "ldr r0, [%1], #4 \n"
148 "subs r1, r1, #4 \n"
149 "str r0, [%0], #4 \n"
150 "bne 1b \n"
151 "bics %2, %2, #0x1f \n"
152 "beq 3f \n"
153 "2: \n"
154 "ldmia %1!, { r0-r7 } \n"
155 "subs %2, %2, #32 \n"
156 "stmia %0!, { r0-r7 } \n"
157 "bhi 2b \n"
158 "3: \n"
159 : "+r"(out), "+r"(src), "+r"(size)
160 :
161 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7");
162 }
163 else
164 {
165 /* Channel needs amplitude cut */
166 uint32_t l, h;
167 asm volatile (
168 "1: \n"
169 "ldrsh %3, [%1], #2 \n"
170 "ldrsh %4, [%1], #2 \n"
171 "subs %2, %2, #4 \n"
172 "mul %3, %5, %3 \n"
173 "mul %4, %5, %4 \n"
174 "and %4, %4, %6, lsl #16 \n"
175 "orr %4, %4, %3, lsr #16 \n"
176 "str %4, [%0], #4 \n"
177 "bhi 1b \n"
178 : "+r"(out), "+r"(src), "+r"(size),
179 "=&r"(l), "=&r"(h)
180 : "r"(amp), "r"(0xffffffffu));
181 }
182}
diff --git a/firmware/target/arm/pcm-mixer-armv5.c b/firmware/target/arm/pcm-mixer-armv5.c
new file mode 100644
index 0000000000..64f2c86f52
--- /dev/null
+++ b/firmware/target/arm/pcm-mixer-armv5.c
@@ -0,0 +1,106 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#define MIXER_OPTIMIZED_WRITE_SAMPLES
23#define MIXER_OPTIMIZED_MIX_SAMPLES
24
25/* Mix channels' samples and apply gain factors */
26static FORCE_INLINE void mix_samples(void *out,
27 void *src0,
28 int32_t src0_amp,
29 void *src1,
30 int32_t src1_amp,
31 size_t size)
32{
33 int32_t s0, s1, tmp;
34 asm volatile (
35 "1: \n"
36 "ldr %4, [%1], #4 \n"
37 "ldr %5, [%2], #4 \n"
38 "smulwb %6, %7, %4 \n"
39 "smulwt %4, %7, %4 \n"
40 "smlawb %6, %8, %5, %6 \n"
41 "smlawt %4, %8, %5, %4 \n"
42 "mov %5, %6, asr #15 \n"
43 "teq %5, %5, asr #31 \n"
44 "eorne %6, %9, %6, asr #31 \n"
45 "mov %5, %4, asr #15 \n"
46 "teq %5, %5, asr #31 \n"
47 "eorne %4, %9, %4, asr #31 \n"
48 "subs %3, %3, #4 \n"
49 "and %6, %6, %9, lsr #16 \n"
50 "orr %6, %6, %4, lsl #16 \n"
51 "str %6, [%0], #4 \n"
52 "bhi 1b \n"
53 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
54 "=&r"(s0), "=&r"(s1), "=&r"(tmp)
55 : "r"(src0_amp), "r"(src1_amp), "r"(0xffff7fff));
56}
57
58/* Write channel's samples and apply gain factor */
59static FORCE_INLINE void write_samples(void *out,
60 void *src,
61 int32_t amp,
62 size_t size)
63{
64 if (LIKELY(amp == MIX_AMP_UNITY))
65 {
66 /* Channel is unity amplitude */
67 asm volatile (
68 "ands r1, %2, #0x1f \n"
69 "beq 2f \n"
70 "1: \n"
71 "ldr r0, [%1], #4 \n"
72 "subs r1, r1, #4 \n"
73 "str r0, [%0], #4 \n"
74 "bne 1b \n"
75 "bics %2, %2, #0x1f \n"
76 "beq 3f \n"
77 "2: \n"
78 "ldmia %1!, { r0-r7 } \n"
79 "subs %2, %2, #32 \n"
80 "stmia %0!, { r0-r7 } \n"
81 "bhi 2b \n"
82 "3: \n"
83 : "+r"(out), "+r"(src), "+r"(size)
84 :
85 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7");
86 }
87 else
88 {
89 /* Channel needs amplitude cut */
90 uint32_t l, h;
91 asm volatile (
92 "1: \n"
93 "ldr %3, [%1], #4 \n"
94 "subs %2, %2, #4 \n"
95 "smulwt %4, %5, %3 \n"
96 "smulwb %3, %5, %3 \n"
97 "mov %4, %4, lsl #16 \n"
98 "mov %3, %3, lsl #16 \n"
99 "orr %4, %4, %3, lsr #16 \n"
100 "str %4, [%0], #4 \n"
101 "bhi 1b \n"
102 : "+r"(out), "+r"(src), "+r"(size),
103 "=&r"(l), "=&r"(h)
104 : "r"(amp));
105 }
106}
diff --git a/firmware/target/arm/pcm-mixer-armv6.c b/firmware/target/arm/pcm-mixer-armv6.c
new file mode 100644
index 0000000000..94eecd0f90
--- /dev/null
+++ b/firmware/target/arm/pcm-mixer-armv6.c
@@ -0,0 +1,118 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#define MIXER_OPTIMIZED_MIX_SAMPLES
22#define MIXER_OPTIMIZED_WRITE_SAMPLES
23
24/* Mix channels' samples and apply gain factors */
25static FORCE_INLINE void mix_samples(void *out,
26 void *src0,
27 int32_t src0_amp,
28 void *src1,
29 int32_t src1_amp,
30 size_t size)
31{
32 uint32_t s0, s1;
33
34 if (src0_amp == MIX_AMP_UNITY && src1_amp == MIX_AMP_UNITY)
35 {
36 /* Both are unity amplitude */
37 asm volatile (
38 "1: \n"
39 "ldr %4, [%1], #4 \n"
40 "ldr %5, [%2], #4 \n"
41 "subs %3, %3, #4 \n"
42 "qadd16 %5, %5, %4 \n"
43 "str %5, [%0], #4 \n"
44 "bhi 1b \n"
45 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
46 "=&r"(s0), "=&r"(s1));
47 }
48 else
49 {
50 /* One or neither are unity amplitude */
51 uint32_t tmp;
52 asm volatile (
53 "1: \n"
54 "ldr %4, [%1], #4 \n"
55 "ldr %5, [%2], #4 \n"
56 "subs %3, %3, #4 \n"
57 "smulwb %6, %7, %4 \n"
58 "smulwt %4, %7, %4 \n"
59 "smlawb %6, %8, %5, %6 \n"
60 "smlawt %4, %8, %5, %4 \n"
61 "ssat %6, #16, %6 \n"
62 "ssat %4, #16, %4 \n"
63 "pkhbt %6, %6, %4, asl #16 \n"
64 "str %6, [%0], #4 \n"
65 "bhi 1b \n"
66 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
67 "=&r"(s0), "=&r"(s1), "=&r"(tmp)
68 : "r"(src0_amp), "r"(src1_amp));
69 }
70}
71
72/* Write channel's samples and apply gain factor */
73static FORCE_INLINE void write_samples(void *out,
74 void *src,
75 int32_t amp,
76 size_t size)
77{
78 if (LIKELY(amp == MIX_AMP_UNITY))
79 {
80 /* Channel is unity amplitude */
81 asm volatile (
82 "ands r1, %2, #0x1f \n"
83 "beq 2f \n"
84 "1: \n"
85 "ldr r0, [%1], #4 \n"
86 "subs r1, r1, #4 \n"
87 "str r0, [%0], #4 \n"
88 "bne 1b \n"
89 "bics %2, %2, #0x1f \n"
90 "beq 3f \n"
91 "2: \n"
92 "ldmia %1!, { r0-r7 } \n"
93 "subs %2, %2, #32 \n"
94 "stmia %0!, { r0-r7 } \n"
95 "bhi 2b \n"
96 "3: \n"
97 : "+r"(out), "+r"(src), "+r"(size)
98 :
99 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7");
100 }
101 else
102 {
103 /* Channel needs amplitude cut */
104 uint32_t s, tmp;
105 asm volatile(
106 "1: \n"
107 "ldr %3, [%1], #4 \n"
108 "subs %2, %2, #4 \n"
109 "smulwt %4, %5, %3 \n"
110 "smulwb %3, %5, %3 \n"
111 "pkhbt %4, %3, %4, asl #16 \n"
112 "str %4, [%0], #4 \n"
113 "bhi 1b \n"
114 : "+r"(out), "+r"(src), "+r"(size),
115 "=&r"(s), "=&r"(tmp)
116 : "r"(amp));
117 }
118}
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 */
diff --git a/firmware/target/arm/pcm-telechips.c b/firmware/target/arm/pcm-telechips.c
index 851ebee7de..aff43171f6 100644
--- a/firmware/target/arm/pcm-telechips.c
+++ b/firmware/target/arm/pcm-telechips.c
@@ -27,6 +27,7 @@
27#include "sound.h" 27#include "sound.h"
28#include "i2s.h" 28#include "i2s.h"
29#include "pcm.h" 29#include "pcm.h"
30#include "pcm-internal.h"
30 31
31struct dma_data 32struct dma_data
32{ 33{
@@ -247,6 +248,8 @@ void fiq_handler(void)
247 * r0-r3 and r12 is a working register. 248 * r0-r3 and r12 is a working register.
248 */ 249 */
249 asm volatile ( 250 asm volatile (
251 "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */
252 "mov r4, #0 \n" /* Was the callback called? */
250#if defined(CPU_TCC780X) 253#if defined(CPU_TCC780X)
251 "mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */ 254 "mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */
252 "ldr r9, =0xf3001004 \n" /* CREQ */ 255 "ldr r9, =0xf3001004 \n" /* CREQ */
@@ -279,33 +282,41 @@ void fiq_handler(void)
279 "sub r9, r9, #0x10 \n" /* 4 words written */ 282 "sub r9, r9, #0x10 \n" /* 4 words written */
280 "stmia r11, { r8-r9 } \n" /* save p and size */ 283 "stmia r11, { r8-r9 } \n" /* save p and size */
281 284
285 "cmp r4, #0 \n" /* Callback called? */
286 "beq .exit \n"
287 /* "mov r4, #0 \n" If get_more could be called multiple times! */
288 "ldr r2, =pcm_play_dma_started\n"
289 "ldr r2, [r2] \n"
290 "cmp r2, #0 \n"
291 "blxne r2 \n"
292
282 ".exit: \n" 293 ".exit: \n"
294 "ldmfd sp!, { r0-r4, lr } \n"
283 "subs pc, lr, #4 \n" /* FIQ specific return sequence */ 295 "subs pc, lr, #4 \n" /* FIQ specific return sequence */
284 296
285 ".more_data: \n" 297 ".more_data: \n"
286 "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */ 298 "mov r4, #1 \n" /* Remember we got more data in this FIQ */
287 "ldr r2, =pcm_play_get_more_callback \n" 299 "ldr r2, =pcm_play_get_more_callback \n"
288 "mov r0, r11 \n" /* r0 = &p */ 300 "mov r0, r11 \n" /* r0 = &p */
289 "add r1, r11, #4 \n" /* r1 = &size */ 301 "add r1, r11, #4 \n" /* r1 = &size */
290 "blx r2 \n" /* call pcm_play_get_more_callback */ 302 "blx r2 \n" /* call pcm_play_get_more_callback */
291 "ldmia r11, { r8-r9 } \n" /* load new p and size */ 303 "ldmia r11, { r8-r9 } \n" /* load new p and size */
292 "cmp r9, #0x10 \n" /* did we actually get enough data? */ 304 "cmp r9, #0x10 \n" /* did we actually get enough data? */
293 "ldmfd sp!, { r0-r3, lr } \n"
294 "bpl .fill_fifo \n" /* not stop and enough? refill */ 305 "bpl .fill_fifo \n" /* not stop and enough? refill */
295 "b .exit \n" 306 "b .exit \n"
296 ".ltorg \n" 307 ".ltorg \n"
297 ); 308 );
298} 309}
299#else /* C version for reference */ 310#else /* C version for reference */
300void fiq_handler(void) ICODE_ATTR __attribute__((naked)); 311void fiq_handler(void) ICODE_ATTR;
301void fiq_handler(void) 312void fiq_handler(void)
302{ 313{
303 asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */ 314 register bool new_buffer = false;
304 "sub sp, sp, #8 \n"); /* Reserve stack */
305 315
306 if (dma_play_data.size < 16) 316 if (dma_play_data.size < 16)
307 { 317 {
308 /* p is empty, get some more data */ 318 /* p is empty, get some more data */
319 new_buffer = true;
309 pcm_play_get_more_callback((void**)&dma_play_data.p, 320 pcm_play_get_more_callback((void**)&dma_play_data.p,
310 &dma_play_data.size); 321 &dma_play_data.size);
311 } 322 }
@@ -327,9 +338,8 @@ void fiq_handler(void)
327 /* Clear FIQ status */ 338 /* Clear FIQ status */
328 CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK; 339 CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK;
329 340
330 asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */ 341 if (new_buffer)
331 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */ 342 pcm_play_dma_started_callback();
332 "subs pc, lr, #4 \n"); /* Return from FIQ */
333} 343}
334#endif 344#endif
335 345
diff --git a/firmware/target/arm/pnx0101/pcm-pnx0101.c b/firmware/target/arm/pnx0101/pcm-pnx0101.c
index 9d4ffbd773..d4c17454ed 100644
--- a/firmware/target/arm/pnx0101/pcm-pnx0101.c
+++ b/firmware/target/arm/pnx0101/pcm-pnx0101.c
@@ -21,6 +21,7 @@
21#include "system.h" 21#include "system.h"
22#include "audio.h" 22#include "audio.h"
23#include "string.h" 23#include "string.h"
24#include "pcm-internal.h"
24 25
25#define DMA_BUF_SAMPLES 0x100 26#define DMA_BUF_SAMPLES 0x100
26 27
@@ -63,6 +64,8 @@ static inline void fill_dma_buf(int offset)
63 64
64 if (pcm_playing && !pcm_paused) 65 if (pcm_playing && !pcm_paused)
65 { 66 {
67 bool new_buffer =false;
68
66 do 69 do
67 { 70 {
68 int count; 71 int count;
@@ -102,10 +105,20 @@ static inline void fill_dma_buf(int offset)
102 count--; 105 count--;
103 } 106 }
104 p = tmp_p; 107 p = tmp_p;
108
109 if (new_buffer)
110 {
111 new_buffer = false;
112 pcm_play_dma_started_callback();
113 }
114
105 if (l >= lend) 115 if (l >= lend)
106 return; 116 return;
107 117
108 pcm_play_get_more_callback((void**)&p, &p_size); 118 pcm_play_get_more_callback((void**)&p, &p_size);
119
120 if (p_size)
121 new_buffer = true;
109 } 122 }
110 while (p_size); 123 while (p_size);
111 } 124 }
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
index c1c9017fbb..33194ae5d9 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
@@ -25,6 +25,7 @@
25#include "audio.h" 25#include "audio.h"
26#include "sound.h" 26#include "sound.h"
27#include "file.h" 27#include "file.h"
28#include "pcm-internal.h"
28 29
29/* PCM interrupt routine lockout */ 30/* PCM interrupt routine lockout */
30static struct 31static struct
@@ -235,6 +236,8 @@ void fiq_handler(void)
235 236
236 /* Re-Activate the channel */ 237 /* Re-Activate the channel */
237 DMASKTRIG2 = 0x2; 238 DMASKTRIG2 = 0x2;
239
240 pcm_play_dma_started_callback();
238} 241}
239 242
240size_t pcm_get_bytes_waiting(void) 243size_t pcm_get_bytes_waiting(void)
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
index 01b177da6c..eea4c58e4b 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
@@ -99,14 +99,15 @@ void TIMER3(void)
99 INTPND = TIMER3_MASK; 99 INTPND = TIMER3_MASK;
100} 100}
101 101
102void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude) 102void beep_play(unsigned int frequency, unsigned int duration,
103 unsigned int amplitude)
103{ 104{
104 #define TIMER3_TICK_SEC (TIMER_FREQ / TIMER234_PRESCALE) 105 #define TIMER3_TICK_SEC (TIMER_FREQ / TIMER234_PRESCALE)
105 106
106 unsigned long tcnt, tcmp; 107 unsigned long tcnt, tcmp;
107 int oldstatus; 108 int oldstatus;
108 109
109 if (amplitude <= 0) 110 if (frequency == 0 || duration == 0 || amplitude == 0)
110 { 111 {
111 beep_stop(); /* won't hear it anyway */ 112 beep_stop(); /* won't hear it anyway */
112 return; 113 return;
diff --git a/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c b/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c
index 8a6b62f31f..0c69c1e6d3 100644
--- a/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c
+++ b/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c
@@ -26,6 +26,7 @@
26#include "audio.h" 26#include "audio.h"
27#include "sound.h" 27#include "sound.h"
28#include "file.h" 28#include "file.h"
29#include "pcm-internal.h"
29 30
30/* PCM interrupt routine lockout */ 31/* PCM interrupt routine lockout */
31static struct 32static struct
@@ -275,6 +276,8 @@ void fiq_handler(void)
275 276
276 /* Re-Activate the channel */ 277 /* Re-Activate the channel */
277 DMASKTRIG2 = 0x2; 278 DMASKTRIG2 = 0x2;
279
280 pcm_play_dma_started_callback();
278} 281}
279 282
280size_t pcm_get_bytes_waiting(void) 283size_t pcm_get_bytes_waiting(void)
diff --git a/firmware/target/arm/s5l8700/pcm-s5l8700.c b/firmware/target/arm/s5l8700/pcm-s5l8700.c
index 08086c37d8..14c515ec47 100644
--- a/firmware/target/arm/s5l8700/pcm-s5l8700.c
+++ b/firmware/target/arm/s5l8700/pcm-s5l8700.c
@@ -27,6 +27,7 @@
27#include "panic.h" 27#include "panic.h"
28#include "audiohw.h" 28#include "audiohw.h"
29#include "pcm.h" 29#include "pcm.h"
30#include "pcm-internal.h"
30#include "pcm_sampr.h" 31#include "pcm_sampr.h"
31#include "dma-target.h" 32#include "dma-target.h"
32#include "mmu-arm.h" 33#include "mmu-arm.h"
@@ -100,6 +101,7 @@ void pcm_play_unlock(void)
100void INT_DMA(void) ICODE_ATTR; 101void INT_DMA(void) ICODE_ATTR;
101void INT_DMA(void) 102void INT_DMA(void)
102{ 103{
104 bool new_buffer = false;
103 DMACOM0 = 7; 105 DMACOM0 = 7;
104 while (!(DMACON0 & (1 << 18))) 106 while (!(DMACON0 & (1 << 18)))
105 { 107 {
@@ -112,8 +114,12 @@ void INT_DMA(void)
112 } 114 }
113 else 115 else
114 { 116 {
115 if (!nextsize) pcm_play_get_more_callback((void**)&nextbuf, &nextsize); 117 if (!nextsize)
116 if (!nextsize) break; 118 {
119 pcm_play_get_more_callback((void**)&nextbuf, &nextsize);
120 if (!nextsize) break;
121 new_buffer = true;
122 }
117 queuedsize = MIN(sizeof(dblbuf), nextsize / 2); 123 queuedsize = MIN(sizeof(dblbuf), nextsize / 2);
118 nextsize -= queuedsize; 124 nextsize -= queuedsize;
119 queuedbuf = nextbuf + nextsize; 125 queuedbuf = nextbuf + nextsize;
@@ -124,7 +130,14 @@ void INT_DMA(void)
124 clean_dcache(); 130 clean_dcache();
125 DMACOM0 = 4; 131 DMACOM0 = 4;
126 DMACOM0 = 7; 132 DMACOM0 = 7;
133
134 if (new_buffer)
135 {
136 pcm_play_dma_started_callback();
137 new_buffer = false;
138 }
127 } 139 }
140
128} 141}
129 142
130void pcm_play_dma_start(const void* addr, size_t size) 143void pcm_play_dma_start(const void* addr, size_t size)
diff --git a/firmware/target/arm/s5l8702/pcm-s5l8702.c b/firmware/target/arm/s5l8702/pcm-s5l8702.c
index c0498a9ce2..dbadf3bac0 100644
--- a/firmware/target/arm/s5l8702/pcm-s5l8702.c
+++ b/firmware/target/arm/s5l8702/pcm-s5l8702.c
@@ -27,6 +27,7 @@
27#include "panic.h" 27#include "panic.h"
28#include "audiohw.h" 28#include "audiohw.h"
29#include "pcm.h" 29#include "pcm.h"
30#include "pcm-internal.h"
30#include "pcm_sampr.h" 31#include "pcm_sampr.h"
31#include "mmu-arm.h" 32#include "mmu-arm.h"
32#include "pcm-target.h" 33#include "pcm-target.h"
@@ -113,6 +114,8 @@ void INT_DMAC0C0(void)
113 DMAC0C0CONFIG = 0x8a81; 114 DMAC0C0CONFIG = 0x8a81;
114 } 115 }
115 else DMAC0C0NEXTLLI = pcm_lli; 116 else DMAC0C0NEXTLLI = pcm_lli;
117
118 pcm_play_dma_started_callback();
116} 119}
117 120
118void pcm_play_dma_start(const void* addr, size_t size) 121void pcm_play_dma_start(const void* addr, size_t size)
diff --git a/firmware/target/arm/tms320dm320/creative-zvm/pcm-creativezvm.c b/firmware/target/arm/tms320dm320/creative-zvm/pcm-creativezvm.c
index 3c54ce81fb..5ec62cf876 100644
--- a/firmware/target/arm/tms320dm320/creative-zvm/pcm-creativezvm.c
+++ b/firmware/target/arm/tms320dm320/creative-zvm/pcm-creativezvm.c
@@ -27,6 +27,7 @@
27#include "dm320.h" 27#include "dm320.h"
28#include "audiohw.h" 28#include "audiohw.h"
29#include "dsp-target.h" 29#include "dsp-target.h"
30#include "pcm-internal.h"
30 31
31void pcm_play_dma_init(void) 32void pcm_play_dma_init(void)
32{ 33{
diff --git a/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c b/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c
index fb94adae71..90c342e868 100644
--- a/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c
+++ b/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c
@@ -28,6 +28,7 @@
28#include "dsp-target.h" 28#include "dsp-target.h"
29#include "dsp/ipc.h" 29#include "dsp/ipc.h"
30#include "mmu-arm.h" 30#include "mmu-arm.h"
31#include "pcm-internal.h"
31 32
32/* This is global to save some latency when pcm_play_dma_get_peak_buffer is 33/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
33 * called. 34 * called.
@@ -178,6 +179,8 @@ void DSPHINT(void)
178 179
179 DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx", 180 DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx",
180 (unsigned long)start, (unsigned long)sdem_addr); 181 (unsigned long)start, (unsigned long)sdem_addr);
182
183 pcm_play_dma_started_callback();
181 } 184 }
182 185
183 break; 186 break;