A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007-2010 Michael Sevakis (jhMikeS)
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#if !SPC_NOINTERP
22
23#define SPC_GAUSSIAN_FAST_INTERP
24static inline int gaussian_fast_interp( int16_t const* samples,
25 int32_t position,
26 int16_t const* fwd,
27 int16_t const* rev )
28{
29 int output;
30 int t0, t1, t2, t3;
31
32 asm volatile (
33 "ldrsh %[t0], [%[samp]] \n"
34 "ldrsh %[t2], [%[fwd]] \n"
35 "ldrsh %[t1], [%[samp], #2] \n"
36 "ldrsh %[t3], [%[fwd], #2] \n"
37 "mul %[out], %[t0], %[t2] \n" /* out= fwd[0]*samp[0] */
38 "ldrsh %[t0], [%[samp], #4] \n"
39 "ldrsh %[t2], [%[rev], #2] \n"
40 "mla %[out], %[t1], %[t3], %[out] \n" /* out+=fwd[1]*samp[1] */
41 "ldrsh %[t1], [%[samp], #6] \n"
42 "ldrsh %[t3], [%[rev]] \n"
43 "mla %[out], %[t0], %[t2], %[out] \n" /* out+=rev[1]*samp[2] */
44 "mla %[out], %[t1], %[t3], %[out] \n" /* out+=rev[0]*samp[3] */
45 : [out]"=&r"(output),
46 [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3)
47 : [fwd]"r"(fwd), [rev]"r"(rev),
48 [samp]"r"(samples + (position >> 12)));
49
50 return output;
51}
52
53#if 0 // first asm block generates "Rd and Rm should be different in mul" error
54#define SPC_GAUSSIAN_FAST_AMP
55static inline int gaussian_fast_amp( struct voice_t* voice, int output,
56 int* amp_0, int* amp_1 )
57{
58 int t0;
59
60 asm volatile (
61 "mov %[t0], %[out], asr #11 \n"
62 "mul %[out], %[t0], %[envx] \n"
63 : [out]"+r"(output), [t0]"=&r"(t0)
64 : [envx]"r"((int) voice->envx));
65
66 asm volatile (
67 "mov %[out], %[out], asr #11 \n"
68 "mul %[a0], %[out], %[v0] \n"
69 "mul %[a1], %[out], %[v1] \n"
70 : [out]"+r"(output),
71 [a0]"=&r"(*amp_0), [a1]"=r"(*amp_1)
72 : [v0]"r"((int) voice->volume [0]),
73 [v1]"r"((int) voice->volume [1]));
74
75 return output;
76}
77#endif
78
79#define SPC_GAUSSIAN_SLOW_INTERP
80static inline int gaussian_slow_interp( int16_t const* samples,
81 int32_t position,
82 int16_t const* fwd,
83 int16_t const* rev )
84{
85 int output;
86 int t0, t1, t2, t3;
87
88 asm volatile (
89 "ldrsh %[t0], [%[samp]] \n"
90 "ldrsh %[t2], [%[fwd]] \n"
91 "ldrsh %[t1], [%[samp], #2] \n"
92 "ldrsh %[t3], [%[fwd], #2] \n"
93 "mul %[out], %[t2], %[t0] \n" /* fwd[0]*samp[0] */
94 "ldrsh %[t2], [%[rev], #2] \n"
95 "mul %[t0], %[t3], %[t1] \n" /* fwd[1]*samp[1] */
96 "ldrsh %[t1], [%[samp], #4] \n"
97 "mov %[out], %[out], asr #12 \n"
98 "ldrsh %[t3], [%[rev]] \n"
99 "mul %[t2], %[t1], %[t2] \n" /* rev[1]*samp[2] */
100 "ldrsh %[t1], [%[samp], #6] \n"
101 "add %[t0], %[out], %[t0], asr #12 \n"
102 "mul %[t3], %[t1], %[t3] \n" /* rev[0]*samp[3] */
103 "add %[t2], %[t0], %[t2], asr #12 \n"
104 "mov %[t2], %[t2], lsl #17 \n"
105 "mov %[t3], %[t3], asr #12 \n"
106 "mov %[t3], %[t3], asl #1 \n"
107 "add %[out], %[t3], %[t2], asr #16 \n"
108 : [out]"=&r"(output),
109 [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3)
110 : [fwd]"r"(fwd), [rev]"r"(rev),
111 [samp]"r"(samples + (position >> 12)));
112
113 return CLAMP16( output );
114}
115
116#define SPC_GAUSSIAN_SLOW_AMP
117static inline int gaussian_slow_amp( struct voice_t* voice, int output,
118 int* amp_0, int* amp_1 )
119{
120 int t0;
121
122 asm volatile (
123 "mul %[t0], %[out], %[envx]"
124 : [t0]"=r"(t0)
125 : [out]"r"(output), [envx]"r"((int) voice->envx));
126 asm volatile (
127 "mov %[t0], %[t0], asr #11 \n"
128 "bic %[t0], %[t0], #0x1 \n"
129 "mul %[a0], %[t0], %[v0] \n"
130 "mul %[a1], %[t0], %[v1] \n"
131 : [t0]"+r"(t0),
132 [a0]"=&r"(*amp_0), [a1]"=r"(*amp_1)
133 : [v0]"r"((int) voice->volume [0]),
134 [v1]"r"((int) voice->volume [1]));
135
136 return t0;
137}
138
139#else /* SPC_NOINTERP */
140
141#define SPC_LINEAR_INTERP
142static inline int linear_interp( int16_t const* samples, int32_t position )
143{
144 int output = (int) samples;
145 int y1;
146
147 asm volatile(
148 "mov %[y1], %[f], lsr #12 \n"
149 "eor %[f], %[f], %[y1], lsl #12 \n"
150 "add %[y1], %[y0], %[y1], lsl #1 \n"
151 "ldrsh %[y0], [%[y1], #2] \n"
152 "ldrsh %[y1], [%[y1], #4] \n"
153 "sub %[y1], %[y1], %[y0] \n"
154 "mul %[f], %[y1], %[f] \n"
155 "add %[y0], %[y0], %[f], asr #12 \n"
156 : [f]"+r"(position), [y0]"+r"(output), [y1]"=&r"(y1));
157
158 return output;
159}
160
161#define SPC_LINEAR_AMP
162static inline int linear_amp( struct voice_t* voice, int output,
163 int* amp_0, int* amp_1 )
164{
165 int t0;
166
167 asm volatile(
168 "mul %[t0], %[out], %[envx]"
169 : [t0]"=&r"(t0)
170 : [out]"r"(output), [envx]"r"(voice->envx));
171 asm volatile(
172 "mov %[t0], %[t0], asr #11 \n"
173 "mul %[a1], %[t0], %[v1] \n"
174 "mul %[a0], %[t0], %[v0] \n"
175 : [t0]"+r"(t0),
176 [a0]"=&r"(*amp_0), [a1]"=&r"(*amp_1)
177 : [v0]"r"((int) voice->volume [0]),
178 [v1]"r"((int) voice->volume [1]));
179
180 return t0;
181}
182
183#endif /* !SPC_NOINTERP */
184
185
186#if !SPC_NOECHO
187
188#define SPC_DSP_ECHO_APPLY
189
190/* Echo filter history */
191static int32_t fir_buf[FIR_BUF_CNT] IBSS_ATTR_SPC
192 __attribute__(( aligned(FIR_BUF_ALIGN*1) ));
193
194static inline void echo_init( struct Spc_Dsp* this )
195{
196 this->fir.ptr = fir_buf;
197 ci->memset( fir_buf, 0, sizeof fir_buf );
198}
199
200static inline void echo_apply( struct Spc_Dsp* this, uint8_t *echo_ptr,
201 int* out_0, int* out_1 )
202{
203 int t0 = GET_LE16SA( echo_ptr );
204 int t1 = GET_LE16SA( echo_ptr + 2 );
205
206 /* Keep last 8 samples */
207 int32_t *fir_ptr;
208 asm volatile (
209 "add %[p], %[t_p], #8 \n"
210 "bic %[t_p], %[p], %[mask] \n"
211 "str %[t0], [%[p], #-8] \n"
212 "str %[t1], [%[p], #-4] \n"
213 /* duplicate at +8 eliminates wrap checking below */
214 "str %[t0], [%[p], #56] \n"
215 "str %[t1], [%[p], #60] \n"
216 : [p]"=&r"(fir_ptr), [t_p]"+r"(this->fir.ptr)
217 : [t0]"r"(t0), [t1]"r"(t1), [mask]"i"(~FIR_BUF_MASK));
218
219 int32_t *fir_coeff = this->fir.coeff;
220
221 asm volatile (
222 "ldmia %[c]!, { r0-r1 } \n"
223 "ldmia %[p]!, { r4-r5 } \n"
224 "mul %[acc0], r0, %[acc0] \n"
225 "mul %[acc1], r0, %[acc1] \n"
226 "mla %[acc0], r4, r1, %[acc0] \n"
227 "mla %[acc1], r5, r1, %[acc1] \n"
228 "ldmia %[c]!, { r0-r1 } \n"
229 "ldmia %[p]!, { r2-r5 } \n"
230 "mla %[acc0], r2, r0, %[acc0] \n"
231 "mla %[acc1], r3, r0, %[acc1] \n"
232 "mla %[acc0], r4, r1, %[acc0] \n"
233 "mla %[acc1], r5, r1, %[acc1] \n"
234 "ldmia %[c]!, { r0-r1 } \n"
235 "ldmia %[p]!, { r2-r5 } \n"
236 "mla %[acc0], r2, r0, %[acc0] \n"
237 "mla %[acc1], r3, r0, %[acc1] \n"
238 "mla %[acc0], r4, r1, %[acc0] \n"
239 "mla %[acc1], r5, r1, %[acc1] \n"
240 "ldmia %[c]!, { r0-r1 } \n"
241 "ldmia %[p]!, { r2-r5 } \n"
242 "mla %[acc0], r2, r0, %[acc0] \n"
243 "mla %[acc1], r3, r0, %[acc1] \n"
244 "mla %[acc0], r4, r1, %[acc0] \n"
245 "mla %[acc1], r5, r1, %[acc1] \n"
246 : [acc0]"+r"(t0), [acc1]"+r"(t1),
247 [p]"+r"(fir_ptr), [c]"+r"(fir_coeff)
248 :
249 : "r0", "r1", "r2", "r3", "r4", "r5");
250
251 *out_0 = t0;
252 *out_1 = t1;
253}
254
255#endif /* SPC_NOECHO */