primitives.h revision 632e0c016c9a518b36f09988b740b3bc1199c3e4
1632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten/* 2632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * Copyright (C) 2011 The Android Open Source Project 3632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * 4632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 5632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * you may not use this file except in compliance with the License. 6632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * You may obtain a copy of the License at 7632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * 8632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 9632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * 10632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * Unless required by applicable law or agreed to in writing, software 11632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 12632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * See the License for the specific language governing permissions and 14632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * limitations under the License. 15632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten */ 16632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 17632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#ifndef ANDROID_AUDIO_PRIMITIVES_H 18632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#define ANDROID_AUDIO_PRIMITIVES_H 19632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 20632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#include <stdint.h> 21632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#include <sys/cdefs.h> 22632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 23632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten__BEGIN_DECLS 24632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 25632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten/** 26632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * Dither and clamp pairs of 32-bit input samples (sums) to 16-bit output samples (out). 27632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * Each 32-bit input sample is a signed fixed-point Q19.12. 28632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * The .12 fraction is dithered, and the integer portion is then clamped to Q15. 29632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * For interleaved stereo, c is the number of sample pairs, 30632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * and out is an array of interleaved pairs of 16-bit samples per channel. 31632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * For mono, c is the number of samples / 2, and out is an array of 16-bit samples. 32632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * The name "dither" is a misnomer; the current implementation does not actually dither 33632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * but uses truncation. This may change. 34632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten */ 35632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kastenvoid ditherAndClamp(int32_t* out, const int32_t *sums, size_t c); 36632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 37632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten/** 38632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * Clamp (aka hard limit or clip) a signed 32-bit sample to 16-bit range. 39632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten */ 40632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kastenstatic inline int16_t clamp16(int32_t sample) 41632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten{ 42632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten if ((sample>>15) ^ (sample>>31)) 43632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten sample = 0x7FFF ^ (sample>>31); 44632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return sample; 45632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten} 46632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 47632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten/** 48632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * Multiply-accumulate 16-bit terms with 32-bit result: return a + in*v. 49632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten */ 50632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kastenstatic inline 51632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kastenint32_t mulAdd(int16_t in, int16_t v, int32_t a) 52632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten{ 53632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#if defined(__arm__) && !defined(__thumb__) 54632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten int32_t out; 55632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten asm( "smlabb %[out], %[in], %[v], %[a] \n" 56632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [out]"=r"(out) 57632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [in]"%r"(in), [v]"r"(v), [a]"r"(a) 58632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : ); 59632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return out; 60632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#else 61632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return a + in * (int32_t)v; 62632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#endif 63632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten} 64632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 65632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten/** 66632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * Multiply 16-bit terms with 32-bit result: return in*v. 67632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten */ 68632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kastenstatic inline 69632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kastenint32_t mul(int16_t in, int16_t v) 70632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten{ 71632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#if defined(__arm__) && !defined(__thumb__) 72632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten int32_t out; 73632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten asm( "smulbb %[out], %[in], %[v] \n" 74632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [out]"=r"(out) 75632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [in]"%r"(in), [v]"r"(v) 76632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : ); 77632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return out; 78632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#else 79632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return in * (int32_t)v; 80632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#endif 81632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten} 82632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 83632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten/** 84632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * Similar to mulAdd, but the 16-bit terms are extracted from a 32-bit interleaved stereo pair. 85632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten */ 86632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kastenstatic inline 87632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kastenint32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a) 88632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten{ 89632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#if defined(__arm__) && !defined(__thumb__) 90632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten int32_t out; 91632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten if (left) { 92632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n" 93632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [out]"=r"(out) 94632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a) 95632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : ); 96632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten } else { 97632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n" 98632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [out]"=r"(out) 99632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a) 100632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : ); 101632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten } 102632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return out; 103632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#else 104632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten if (left) { 105632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return a + (int16_t)(inRL&0xFFFF) * (int16_t)(vRL&0xFFFF); 106632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten } else { 107632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return a + (int16_t)(inRL>>16) * (int16_t)(vRL>>16); 108632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten } 109632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#endif 110632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten} 111632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 112632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten/** 113632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten * Similar to mul, but the 16-bit terms are extracted from a 32-bit interleaved stereo pair. 114632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten */ 115632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kastenstatic inline 116632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kastenint32_t mulRL(int left, uint32_t inRL, uint32_t vRL) 117632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten{ 118632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#if defined(__arm__) && !defined(__thumb__) 119632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten int32_t out; 120632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten if (left) { 121632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten asm( "smulbb %[out], %[inRL], %[vRL] \n" 122632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [out]"=r"(out) 123632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [inRL]"%r"(inRL), [vRL]"r"(vRL) 124632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : ); 125632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten } else { 126632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten asm( "smultt %[out], %[inRL], %[vRL] \n" 127632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [out]"=r"(out) 128632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : [inRL]"%r"(inRL), [vRL]"r"(vRL) 129632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten : ); 130632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten } 131632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return out; 132632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#else 133632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten if (left) { 134632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return (int16_t)(inRL&0xFFFF) * (int16_t)(vRL&0xFFFF); 135632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten } else { 136632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten return (int16_t)(inRL>>16) * (int16_t)(vRL>>16); 137632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten } 138632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#endif 139632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten} 140632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 141632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten__END_DECLS 142632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten 143632e0c016c9a518b36f09988b740b3bc1199c3e4Glenn Kasten#endif // ANDROID_AUDIO_PRIMITIVES_H 144