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 <sys/cdefs.h>
22
23__BEGIN_DECLS
24
25/**
26 * Dither and clamp pairs of 32-bit input samples (sums) to 16-bit output samples (out).
27 * Each 32-bit input sample is a signed fixed-point Q19.12.
28 * The .12 fraction is dithered, and the integer portion is then clamped to Q15.
29 * For interleaved stereo, c is the number of sample pairs,
30 * and out is an array of interleaved pairs of 16-bit samples per channel.
31 * For mono, c is the number of samples / 2, and out is an array of 16-bit samples.
32 * The name "dither" is a misnomer; the current implementation does not actually dither
33 * but uses truncation.  This may change.
34 */
35void ditherAndClamp(int32_t* out, const int32_t *sums, size_t c);
36
37/* Expand and copy samples from unsigned 8-bit offset by 0x80 to signed 16-bit.
38 * Parameters:
39 *  dst     Destination buffer
40 *  src     Source buffer
41 *  count   Number of samples to copy
42 * The destination and source buffers must either be completely separate (non-overlapping), or
43 * they must both start at the same address.  Partially overlapping buffers are not supported.
44 */
45void memcpy_to_i16_from_u8(int16_t *dst, const uint8_t *src, size_t count);
46
47/* Downmix pairs of interleaved stereo input 16-bit samples to mono output 16-bit samples.
48 * Parameters:
49 *  dst     Destination buffer
50 *  src     Source buffer
51 *  count   Number of stereo frames to downmix
52 * The destination and source buffers must be completely separate (non-overlapping).
53 * The current implementation truncates the sum rather than dither, but this may change.
54 */
55void downmix_to_mono_i16_from_stereo_i16(int16_t *dst, const int16_t *src, size_t count);
56
57/* Upmix mono input 16-bit samples to pairs of interleaved stereo output 16-bit samples by
58 * duplicating.
59 * Parameters:
60 *  dst     Destination buffer
61 *  src     Source buffer
62 *  count   Number of mono samples to upmix
63 * The destination and source buffers must be completely separate (non-overlapping).
64 */
65void upmix_to_stereo_i16_from_mono_i16(int16_t *dst, const int16_t *src, size_t count);
66
67/**
68 * Clamp (aka hard limit or clip) a signed 32-bit sample to 16-bit range.
69 */
70static inline int16_t clamp16(int32_t sample)
71{
72    if ((sample>>15) ^ (sample>>31))
73        sample = 0x7FFF ^ (sample>>31);
74    return sample;
75}
76
77/**
78 * Multiply-accumulate 16-bit terms with 32-bit result: return a + in*v.
79 */
80static inline
81int32_t mulAdd(int16_t in, int16_t v, int32_t a)
82{
83#if defined(__arm__) && !defined(__thumb__)
84    int32_t out;
85    asm( "smlabb %[out], %[in], %[v], %[a] \n"
86         : [out]"=r"(out)
87         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
88         : );
89    return out;
90#else
91    return a + in * (int32_t)v;
92#endif
93}
94
95/**
96 * Multiply 16-bit terms with 32-bit result: return in*v.
97 */
98static inline
99int32_t mul(int16_t in, int16_t v)
100{
101#if defined(__arm__) && !defined(__thumb__)
102    int32_t out;
103    asm( "smulbb %[out], %[in], %[v] \n"
104         : [out]"=r"(out)
105         : [in]"%r"(in), [v]"r"(v)
106         : );
107    return out;
108#else
109    return in * (int32_t)v;
110#endif
111}
112
113/**
114 * Similar to mulAdd, but the 16-bit terms are extracted from a 32-bit interleaved stereo pair.
115 */
116static inline
117int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
118{
119#if defined(__arm__) && !defined(__thumb__)
120    int32_t out;
121    if (left) {
122        asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n"
123             : [out]"=r"(out)
124             : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
125             : );
126    } else {
127        asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n"
128             : [out]"=r"(out)
129             : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
130             : );
131    }
132    return out;
133#else
134    if (left) {
135        return a + (int16_t)(inRL&0xFFFF) * (int16_t)(vRL&0xFFFF);
136    } else {
137        return a + (int16_t)(inRL>>16) * (int16_t)(vRL>>16);
138    }
139#endif
140}
141
142/**
143 * Similar to mul, but the 16-bit terms are extracted from a 32-bit interleaved stereo pair.
144 */
145static inline
146int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
147{
148#if defined(__arm__) && !defined(__thumb__)
149    int32_t out;
150    if (left) {
151        asm( "smulbb %[out], %[inRL], %[vRL] \n"
152             : [out]"=r"(out)
153             : [inRL]"%r"(inRL), [vRL]"r"(vRL)
154             : );
155    } else {
156        asm( "smultt %[out], %[inRL], %[vRL] \n"
157             : [out]"=r"(out)
158             : [inRL]"%r"(inRL), [vRL]"r"(vRL)
159             : );
160    }
161    return out;
162#else
163    if (left) {
164        return (int16_t)(inRL&0xFFFF) * (int16_t)(vRL&0xFFFF);
165    } else {
166        return (int16_t)(inRL>>16) * (int16_t)(vRL>>16);
167    }
168#endif
169}
170
171__END_DECLS
172
173#endif  // ANDROID_AUDIO_PRIMITIVES_H
174