1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ANDROID_AUDIO_PRIMITIVES_H
18#define ANDROID_AUDIO_PRIMITIVES_H
19
20#include <stdint.h>
21#include <stdlib.h>
22#include <sys/cdefs.h>
23
24__BEGIN_DECLS
25
26/**
27 * Dither and clamp pairs of 32-bit input samples (sums) to 16-bit output samples (out).
28 * Each 32-bit input sample is a signed fixed-point Q19.12.
29 * The .12 fraction is dithered, and the integer portion is then clamped to Q15.
30 * For interleaved stereo, c is the number of sample pairs,
31 * and out is an array of interleaved pairs of 16-bit samples per channel.
32 * For mono, c is the number of samples / 2, and out is an array of 16-bit samples.
33 * The name "dither" is a misnomer; the current implementation does not actually dither
34 * but uses truncation.  This may change.
35 * The out and sums buffers must either be completely separate (non-overlapping), or
36 * they must both start at the same address.  Partially overlapping buffers are not supported.
37 */
38void ditherAndClamp(int32_t* out, const int32_t *sums, size_t c);
39
40/* Expand and copy samples from unsigned 8-bit offset by 0x80 to signed 16-bit.
41 * Parameters:
42 *  dst     Destination buffer
43 *  src     Source buffer
44 *  count   Number of samples to copy
45 * The destination and source buffers must either be completely separate (non-overlapping), or
46 * they must both start at the same address.  Partially overlapping buffers are not supported.
47 */
48void memcpy_to_i16_from_u8(int16_t *dst, const uint8_t *src, size_t count);
49
50/* Shrink and copy samples from signed 16-bit to unsigned 8-bit offset by 0x80.
51 * Parameters:
52 *  dst     Destination buffer
53 *  src     Source buffer
54 *  count   Number of samples to copy
55 * The destination and source buffers must either be completely separate (non-overlapping), or
56 * they must both start at the same address.  Partially overlapping buffers are not supported.
57 * The conversion is done by truncation, without dithering, so it loses resolution.
58 */
59void memcpy_to_u8_from_i16(uint8_t *dst, const int16_t *src, size_t count);
60
61/* Shrink and copy samples from signed 32-bit fixed-point Q0.31 to signed 16-bit Q0.15.
62 * Parameters:
63 *  dst     Destination buffer
64 *  src     Source buffer
65 *  count   Number of samples to copy
66 * The destination and source buffers must either be completely separate (non-overlapping), or
67 * they must both start at the same address.  Partially overlapping buffers are not supported.
68 * The conversion is done by truncation, without dithering, so it loses resolution.
69 */
70void memcpy_to_i16_from_i32(int16_t *dst, const int32_t *src, size_t count);
71
72/* Shrink and copy samples from single-precision floating-point to signed 16-bit.
73 * Each float should be in the range -1.0 to 1.0.  Values outside that range are clamped.
74 * Parameters:
75 *  dst     Destination buffer
76 *  src     Source buffer
77 *  count   Number of samples to copy
78 * The destination and source buffers must either be completely separate (non-overlapping), or
79 * they must both start at the same address.  Partially overlapping buffers are not supported.
80 * The conversion is done by truncation, without dithering, so it loses resolution.
81 */
82void memcpy_to_i16_from_float(int16_t *dst, const float *src, size_t count);
83
84/* Downmix pairs of interleaved stereo input 16-bit samples to mono output 16-bit samples.
85 * Parameters:
86 *  dst     Destination buffer
87 *  src     Source buffer
88 *  count   Number of stereo frames to downmix
89 * The destination and source buffers must be completely separate (non-overlapping).
90 * The current implementation truncates the sum rather than dither, but this may change.
91 */
92void downmix_to_mono_i16_from_stereo_i16(int16_t *dst, const int16_t *src, size_t count);
93
94/* Upmix mono input 16-bit samples to pairs of interleaved stereo output 16-bit samples by
95 * duplicating.
96 * Parameters:
97 *  dst     Destination buffer
98 *  src     Source buffer
99 *  count   Number of mono samples to upmix
100 * The destination and source buffers must be completely separate (non-overlapping).
101 */
102void upmix_to_stereo_i16_from_mono_i16(int16_t *dst, const int16_t *src, size_t count);
103
104/**
105 * Clamp (aka hard limit or clip) a signed 32-bit sample to 16-bit range.
106 */
107static inline int16_t clamp16(int32_t sample)
108{
109    if ((sample>>15) ^ (sample>>31))
110        sample = 0x7FFF ^ (sample>>31);
111    return sample;
112}
113
114/**
115 * Multiply-accumulate 16-bit terms with 32-bit result: return a + in*v.
116 */
117static inline
118int32_t mulAdd(int16_t in, int16_t v, int32_t a)
119{
120#if defined(__arm__) && !defined(__thumb__)
121    int32_t out;
122    asm( "smlabb %[out], %[in], %[v], %[a] \n"
123         : [out]"=r"(out)
124         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
125         : );
126    return out;
127#else
128    return a + in * (int32_t)v;
129#endif
130}
131
132/**
133 * Multiply 16-bit terms with 32-bit result: return in*v.
134 */
135static inline
136int32_t mul(int16_t in, int16_t v)
137{
138#if defined(__arm__) && !defined(__thumb__)
139    int32_t out;
140    asm( "smulbb %[out], %[in], %[v] \n"
141         : [out]"=r"(out)
142         : [in]"%r"(in), [v]"r"(v)
143         : );
144    return out;
145#else
146    return in * (int32_t)v;
147#endif
148}
149
150/**
151 * Similar to mulAdd, but the 16-bit terms are extracted from a 32-bit interleaved stereo pair.
152 */
153static inline
154int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
155{
156#if defined(__arm__) && !defined(__thumb__)
157    int32_t out;
158    if (left) {
159        asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n"
160             : [out]"=r"(out)
161             : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
162             : );
163    } else {
164        asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n"
165             : [out]"=r"(out)
166             : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
167             : );
168    }
169    return out;
170#else
171    if (left) {
172        return a + (int16_t)(inRL&0xFFFF) * (int16_t)(vRL&0xFFFF);
173    } else {
174        return a + (int16_t)(inRL>>16) * (int16_t)(vRL>>16);
175    }
176#endif
177}
178
179/**
180 * Similar to mul, but the 16-bit terms are extracted from a 32-bit interleaved stereo pair.
181 */
182static inline
183int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
184{
185#if defined(__arm__) && !defined(__thumb__)
186    int32_t out;
187    if (left) {
188        asm( "smulbb %[out], %[inRL], %[vRL] \n"
189             : [out]"=r"(out)
190             : [inRL]"%r"(inRL), [vRL]"r"(vRL)
191             : );
192    } else {
193        asm( "smultt %[out], %[inRL], %[vRL] \n"
194             : [out]"=r"(out)
195             : [inRL]"%r"(inRL), [vRL]"r"(vRL)
196             : );
197    }
198    return out;
199#else
200    if (left) {
201        return (int16_t)(inRL&0xFFFF) * (int16_t)(vRL&0xFFFF);
202    } else {
203        return (int16_t)(inRL>>16) * (int16_t)(vRL>>16);
204    }
205#endif
206}
207
208__END_DECLS
209
210#endif  // ANDROID_AUDIO_PRIMITIVES_H
211