andrewm@318
|
1 @
|
andrewm@318
|
2 @ FormatConvert.S
|
andrewm@318
|
3 @
|
andrewm@318
|
4 @ NEON-based vector functions for converting data between int
|
andrewm@318
|
5 @ and float with clipping and optional level scaling.
|
andrewm@318
|
6 @ Written in assembly for performance reasons.
|
andrewm@318
|
7 @
|
andrewm@318
|
8 @ Bela: http://bela.io
|
andrewm@318
|
9 @
|
andrewm@318
|
10 @ (c) 2016 Andrew McPherson
|
andrewm@318
|
11 @ Centre for Digital Music
|
andrewm@318
|
12 @ Queen Mary University of London
|
andrewm@318
|
13 @
|
andrewm@318
|
14
|
andrewm@318
|
15 .syntax unified
|
andrewm@318
|
16 .arch armv7-a
|
andrewm@318
|
17 .fpu neon
|
andrewm@318
|
18
|
andrewm@318
|
19 @ void int16_to_float_audio(int numSamples, int16_t *inBuffer, float *outBuffer);
|
andrewm@318
|
20 @
|
andrewm@318
|
21 @ Convert 16-bit signed ints to floats between -1.0 and 1.0. Used for audio input.
|
andrewm@318
|
22 @
|
andrewm@318
|
23 @ numSamples should be a multiple of 4 (i.e. with stereo audio, frames should be even)
|
andrewm@318
|
24 @ inBuffer should be aligned on an 8-byte boundary.
|
andrewm@318
|
25 @ outBuffer should be aligned on a 16-byte boundary.
|
andrewm@318
|
26
|
andrewm@318
|
27 @ Registers:
|
andrewm@318
|
28 @ r0: numSamples How many frames to convert
|
andrewm@318
|
29 @ r1: inBuffer Buffer for input samples from ADC
|
andrewm@318
|
30 @ r2: outBuffer Buffer to store output samples for render function
|
andrewm@318
|
31
|
andrewm@318
|
32 dIFAu_Input .dn D0.S16
|
andrewm@318
|
33 qIFAu_Expanded .qn Q1.S32
|
andrewm@318
|
34 qIFAu_Output .qn Q2.F32
|
andrewm@318
|
35 dIFAu_Output_0 .dn D4.F32
|
andrewm@318
|
36 dIFAu_Output_1 .dn D5.F32
|
andrewm@318
|
37
|
andrewm@318
|
38 .align 2
|
andrewm@318
|
39 .global int16_to_float_audio
|
andrewm@318
|
40 .thumb
|
andrewm@318
|
41 .thumb_func
|
andrewm@318
|
42 .type int16_to_float_audio, %function
|
andrewm@318
|
43 int16_to_float_audio:
|
andrewm@318
|
44 lsr r0, r0, #2
|
andrewm@318
|
45 lsl r0, r0, #2 @ Clip off the last two bits of numSamples (only multiples of 4 allowed)
|
andrewm@318
|
46 cmp r0, #0 @ Check for trivial case: zero samples
|
andrewm@318
|
47 it eq
|
andrewm@318
|
48 bxeq lr @ Return if that's the case
|
andrewm@318
|
49
|
andrewm@318
|
50 @ ---- loop: iterate over the number of samples ----
|
andrewm@318
|
51 int16_to_float_audio_loop:
|
andrewm@318
|
52 vld1 {dIFAu_Input}, [r1]! @ Load four 16-bit signed ints from inBuffer++
|
andrewm@318
|
53 vmovl qIFAu_Expanded, dIFAu_Input @ Convert four 16-bit signed ints to 32-bit signed ints
|
andrewm@318
|
54 vcvt qIFAu_Output, qIFAu_Expanded, #15 @ Convert four Q17.15 fixed points to floats (equiv. to / 32768)
|
andrewm@318
|
55 vst1 {dIFAu_Output_0, dIFAu_Output_1}, [r2]! @ Store floats back into memory
|
andrewm@318
|
56
|
andrewm@318
|
57 subs r0, r0, #4 @ numSamples -= 4
|
andrewm@318
|
58 it gt
|
andrewm@318
|
59 bgt int16_to_float_audio_loop @ Loop if numSamples > 0
|
andrewm@318
|
60
|
andrewm@318
|
61 bx lr
|
andrewm@318
|
62
|
andrewm@318
|
63
|
andrewm@318
|
64
|
andrewm@318
|
65 @ void int16_to_float_analog(int numSamples, uint16_t *inBuffer, float *outBuffer);
|
andrewm@318
|
66 @
|
andrewm@318
|
67 @ Convert 16-bit unsigned ints to floats between 0.0 and 1.0. Used for analog input.
|
andrewm@318
|
68 @
|
andrewm@318
|
69 @ numSamples should be a multiple of 4 (i.e. integer numFrames at 4 channels)
|
andrewm@318
|
70 @ inBuffer should be aligned on an 8-byte boundary.
|
andrewm@318
|
71 @ outBuffer should be aligned on a 16-byte boundary.
|
andrewm@318
|
72
|
andrewm@318
|
73 @ Registers:
|
andrewm@318
|
74 @ r0: numSamples How many frames to convert
|
andrewm@318
|
75 @ r1: inBuffer Buffer for input samples from ADC
|
andrewm@318
|
76 @ r2: outBuffer Buffer to store output samples for render function
|
andrewm@318
|
77
|
andrewm@318
|
78 dIFAn_Input .dn D0.U16
|
andrewm@318
|
79 qIFAn_Expanded .qn Q1.U32
|
andrewm@318
|
80 qIFAn_Output .qn Q2.F32
|
andrewm@318
|
81 dIFAn_Output_0 .dn D4.F32
|
andrewm@318
|
82 dIFAn_Output_1 .dn D5.F32
|
andrewm@318
|
83
|
andrewm@318
|
84 .align 2
|
andrewm@318
|
85 .global int16_to_float_analog
|
andrewm@318
|
86 .thumb
|
andrewm@318
|
87 .thumb_func
|
andrewm@318
|
88 .type int16_to_float_analog, %function
|
andrewm@318
|
89 int16_to_float_analog:
|
andrewm@318
|
90 lsr r0, r0, #2
|
andrewm@318
|
91 lsl r0, r0, #2 @ Clip off the last two bits of numSamples (only multiples of 4 allowed)
|
andrewm@318
|
92 cmp r0, #0 @ Check for trivial case: zero samples
|
andrewm@318
|
93 it eq
|
andrewm@318
|
94 bxeq lr @ Return if that's the case
|
andrewm@318
|
95
|
andrewm@318
|
96 @ ---- loop: iterate over the number of samples ----
|
andrewm@318
|
97 int16_to_float_analog_loop:
|
andrewm@318
|
98 vld1 {dIFAn_Input}, [r1]! @ Load four 16-bit signed ints from inBuffer++
|
andrewm@318
|
99 vmovl qIFAn_Expanded, dIFAn_Input @ Convert four 16-bit signed ints to 32-bit signed ints
|
andrewm@318
|
100 vcvt qIFAn_Output, qIFAn_Expanded, #16 @ Convert four Q16.16 fixed points to floats (equiv. to / 65536)
|
andrewm@318
|
101 vst1 {dIFAn_Output_0, dIFAn_Output_1}, [r2]! @ Store floats back into memory
|
andrewm@318
|
102
|
andrewm@318
|
103 subs r0, r0, #4 @ numSamples -= 4
|
andrewm@318
|
104 it gt
|
andrewm@318
|
105 bgt int16_to_float_analog_loop @ Loop if numSamples > 0
|
andrewm@318
|
106
|
andrewm@318
|
107 bx lr
|
andrewm@318
|
108
|
andrewm@318
|
109
|
andrewm@318
|
110 @ void float_to_int16_audio(int numSamples, float *inBuffer, int16_t *outBuffer);
|
andrewm@318
|
111 @
|
andrewm@318
|
112 @ Convert floats between -1.0 and 1.0 to 16-bit signed ints, with saturation.
|
andrewm@318
|
113 @ Used for audio output.
|
andrewm@318
|
114 @
|
andrewm@318
|
115 @ numSamples should be a multiple of 4 (i.e. with stereo audio, frames should be even)
|
andrewm@318
|
116 @ inBuffer should be aligned on a 16-byte boundary.
|
andrewm@318
|
117 @ outBuffer should be aligned on an 8-byte boundary.
|
andrewm@318
|
118
|
andrewm@318
|
119 @ Registers:
|
andrewm@318
|
120 @ r0: numSamples How many frames to convert
|
andrewm@318
|
121 @ r1: inBuffer Buffer for input samples from render function
|
andrewm@318
|
122 @ r2: outBuffer Buffer to store output samples for DAC
|
andrewm@318
|
123
|
andrewm@318
|
124 qFIAu_Input .qn Q0.F32
|
andrewm@318
|
125 dFIAu_Input_0 .dn D0.F32
|
andrewm@318
|
126 dFIAu_Input_1, .dn D1.F32
|
andrewm@318
|
127 qFIAu_Converted .qn Q1.S32
|
andrewm@318
|
128 dFIAu_Narrowed .dn D4.S16
|
andrewm@318
|
129
|
andrewm@318
|
130 .align 2
|
andrewm@318
|
131 .global float_to_int16_audio
|
andrewm@318
|
132 .thumb
|
andrewm@318
|
133 .thumb_func
|
andrewm@318
|
134 .type float_to_int16_audio, %function
|
andrewm@318
|
135
|
andrewm@318
|
136 float_to_int16_audio:
|
andrewm@318
|
137 lsr r0, r0, #2
|
andrewm@318
|
138 lsl r0, r0, #2 @ Clip off the last two bits of numSamples (only multiples of 4 allowed)
|
andrewm@318
|
139 cmp r0, #0 @ Check for trivial case: zero samples
|
andrewm@318
|
140 it eq
|
andrewm@318
|
141 bxeq lr @ Return if that's the case
|
andrewm@318
|
142
|
andrewm@318
|
143 @ ---- loop: iterate over the number of samples ----
|
andrewm@318
|
144 float_to_int16_audio_loop:
|
andrewm@318
|
145 vld1 {dFIAu_Input_0, dFIAu_Input_1}, [r1]! @ Load four floats from inBuffer++
|
andrewm@318
|
146 vcvt qFIAu_Converted, qFIAu_Input, #15 @ Convert four floats into four Q17.15 fixed points (equiv. to * 32768)
|
andrewm@318
|
147 @ This will truncate the result to a 32-bit representable value
|
andrewm@318
|
148 vqmovn dFIAu_Narrowed, qFIAu_Converted @ Convert four 32-bit signed ints to 16-bit signed ints, with saturation
|
andrewm@318
|
149 vst1 {dFIAu_Narrowed}, [r2]! @ Store ints back into memory
|
andrewm@318
|
150
|
andrewm@318
|
151 subs r0, r0, #4 @ numSamples -= 4
|
andrewm@318
|
152 it gt
|
andrewm@318
|
153 bgt float_to_int16_audio_loop @ Loop if numSamples > 0
|
andrewm@318
|
154
|
andrewm@318
|
155 bx lr
|
andrewm@318
|
156
|
andrewm@318
|
157
|
andrewm@318
|
158 @ void float_to_int16_analog(int numSamples, float *inBuffer, uint16_t *outBuffer);
|
andrewm@318
|
159 @
|
andrewm@318
|
160 @ Convert floats between 0.0 and 1.0 to 16-bit unsigned ints, with saturation.
|
andrewm@318
|
161 @ Used for analog output.
|
andrewm@318
|
162 @
|
andrewm@318
|
163 @ numSamples should be a multiple of 4 (i.e. with stereo audio, frames should be even)
|
andrewm@318
|
164 @ inBuffer should be aligned on a 16-byte boundary.
|
andrewm@318
|
165 @ outBuffer should be aligned on an 8-byte boundary.
|
andrewm@318
|
166
|
andrewm@318
|
167 @ Registers:
|
andrewm@318
|
168 @ r0: numSamples How many frames to convert
|
andrewm@318
|
169 @ r1: inBuffer Buffer for input samples from render function
|
andrewm@318
|
170 @ r2: outBuffer Buffer to store output samples for DAC
|
andrewm@318
|
171
|
andrewm@318
|
172 qFIAn_Input .qn Q0.F32
|
andrewm@318
|
173 dFIAn_Input_0 .dn D0.F32
|
andrewm@318
|
174 dFIAn_Input_1, .dn D1.F32
|
andrewm@318
|
175 qFIAn_Converted .qn Q1.U32
|
andrewm@318
|
176 dFIAn_Narrowed .dn D4.U16
|
andrewm@318
|
177
|
andrewm@318
|
178 .align 2
|
andrewm@318
|
179 .global float_to_int16_analog
|
andrewm@318
|
180 .thumb
|
andrewm@318
|
181 .thumb_func
|
andrewm@318
|
182 .type float_to_int16_analog, %function
|
andrewm@318
|
183
|
andrewm@318
|
184 float_to_int16_analog:
|
andrewm@318
|
185 lsr r0, r0, #2
|
andrewm@318
|
186 lsl r0, r0, #2 @ Clip off the last two bits of numSamples (only multiples of 4 allowed)
|
andrewm@318
|
187 cmp r0, #0 @ Check for trivial case: zero samples
|
andrewm@318
|
188 it eq
|
andrewm@318
|
189 bxeq lr @ Return if that's the case
|
andrewm@318
|
190
|
andrewm@318
|
191 @ ---- loop: iterate over the number of samples ----
|
andrewm@318
|
192 float_to_int16_analog_loop:
|
andrewm@318
|
193 vld1 {dFIAn_Input_0, dFIAn_Input_1}, [r1]! @ Load four floats from inBuffer++
|
andrewm@318
|
194 vcvt qFIAn_Converted, qFIAn_Input, #16 @ Convert four floats into four Q16.16 fixed points (equiv. to * 65536)
|
andrewm@318
|
195 @ This will truncate the result to a 32-bit representable value
|
andrewm@318
|
196 vqmovn dFIAn_Narrowed, qFIAn_Converted @ Convert four 32-bit unsigned ints to 16-bit unsigned ints, with saturation
|
andrewm@318
|
197 vst1 {dFIAn_Narrowed}, [r2]! @ Store ints back into memory
|
andrewm@318
|
198
|
andrewm@318
|
199 subs r0, r0, #4 @ numSamples -= 4
|
andrewm@318
|
200 it gt
|
andrewm@318
|
201 bgt float_to_int16_analog_loop @ Loop if numSamples > 0
|
andrewm@318
|
202
|
andrewm@318
|
203 bx lr
|
andrewm@318
|
204
|