You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

748 lines
19KB

  1. // Copyright 2009 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // A set of basic operands, especially useful for fixed-point arithmetic, with
  19. // fast ASM implementations.
  20. #ifndef AVRLIB_OP_H_
  21. #define AVRLIB_OP_H_
  22. #define USE_OPTIMIZED_OP
  23. #include <avr/pgmspace.h>
  24. #include "avrlib/base.h"
  25. namespace avrlib {
  26. static inline int16_t Clip(int16_t value, int16_t min, int16_t max) {
  27. return value < min ? min : (value > max ? max : value);
  28. }
  29. static inline int16_t S16ClipU14(int16_t value) {
  30. uint8_t msb = static_cast<uint16_t>(value) >> 8;
  31. if (msb & 0x80) {
  32. return 0;
  33. } if (msb & 0x40) {
  34. return 16383;
  35. }
  36. return value;
  37. }
  38. static inline uint8_t U8AddClip(uint8_t value, uint8_t increment, uint8_t max) {
  39. value += increment;
  40. if (value > max) {
  41. value = max;
  42. }
  43. return value;
  44. }
  45. // Correct only if the input is positive.
  46. static inline uint8_t S16ShiftRight8(int16_t value) {
  47. return static_cast<uint16_t>(value) >> 8;
  48. }
  49. #ifdef USE_OPTIMIZED_OP
  50. static inline uint24c_t U24AddC(uint24c_t a, uint24_t b) {
  51. uint16_t a_int = a.integral;
  52. uint16_t b_int = b.integral;
  53. uint8_t a_frac = a.fractional;
  54. uint8_t b_frac = b.fractional;
  55. uint8_t a_carry = 0;
  56. uint24c_t result;
  57. asm(
  58. "add %0, %6" "\n\t"
  59. "adc %A1, %A7" "\n\t"
  60. "adc %B1, %B7" "\n\t"
  61. "adc %2, r1" "\n\t"
  62. : "=r" (a_frac), "=r" (a_int), "=r" (a_carry)
  63. : "0" (a_frac), "1" (a_int), "2" (a_carry), "a" (b_frac), "a" (b_int)
  64. );
  65. result.integral = a_int;
  66. result.fractional = a_frac;
  67. result.carry = a_carry;
  68. return result;
  69. }
  70. static inline uint24_t U24Add(uint24_t a, uint24_t b) {
  71. uint16_t a_int = a.integral;
  72. uint16_t b_int = b.integral;
  73. uint8_t a_frac = a.fractional;
  74. uint8_t b_frac = b.fractional;
  75. uint24_t result;
  76. asm(
  77. "add %0, %4" "\n\t"
  78. "adc %A1, %A5" "\n\t"
  79. "adc %B1, %B5" "\n\t"
  80. : "=r" (a_frac), "=r" (a_int)
  81. : "0" (a_frac), "1" (a_int), "a" (b_frac), "a" (b_int)
  82. );
  83. result.integral = a_int;
  84. result.fractional = a_frac;
  85. return result;
  86. }
  87. static inline uint24_t U24Sub(uint24_t a, uint24_t b) {
  88. uint16_t a_int = a.integral;
  89. uint16_t b_int = b.integral;
  90. uint8_t a_frac = a.fractional;
  91. uint8_t b_frac = b.fractional;
  92. uint24_t result;
  93. asm(
  94. "sub %0, %4" "\n\t"
  95. "sbc %A1, %A5" "\n\t"
  96. "sbc %B1, %B5" "\n\t"
  97. : "=r" (a_frac), "=r" (a_int)
  98. : "0" (a_frac), "1" (a_int), "a" (b_frac), "a" (b_int)
  99. );
  100. result.integral = a_int;
  101. result.fractional = a_frac;
  102. return result;
  103. }
  104. static inline uint24_t U24ShiftRight(uint24_t a) {
  105. uint16_t a_int = a.integral;
  106. uint8_t a_frac = a.fractional;
  107. uint24_t result;
  108. asm(
  109. "lsr %B1" "\n\t"
  110. "ror %A1" "\n\t"
  111. "ror %0" "\n\t"
  112. : "=r" (a_frac), "=r" (a_int)
  113. : "0" (a_frac), "1" (a_int)
  114. );
  115. result.integral = a_int;
  116. result.fractional = a_frac;
  117. return result;
  118. }
  119. static inline uint24_t U24ShiftLeft(uint24_t a) {
  120. uint16_t a_int = a.integral;
  121. uint8_t a_frac = a.fractional;
  122. uint24_t result;
  123. asm(
  124. "lsl %0" "\n\t"
  125. "rol %A1" "\n\t"
  126. "rol %B1" "\n\t"
  127. : "=r" (a_frac), "=r" (a_int)
  128. : "0" (a_frac), "1" (a_int)
  129. );
  130. result.integral = a_int;
  131. result.fractional = a_frac;
  132. return result;
  133. }
  134. static inline uint8_t S16ClipU8(int16_t value) {
  135. uint8_t result;
  136. asm(
  137. "mov %0, %A1" "\n\t" // by default, copy the value.
  138. "or %B1, %B1" "\n\t" // load H to set flags.
  139. "brpl .+4" "\n\t" // if positive, skip
  140. "ldi %0, 0" "\n\t" // set to 0.
  141. "rjmp .+4" "\n\t" // and jump.
  142. "breq .+2" "\n\t" // if null, skip
  143. "ldi %0, 255" "\n\t" // set to 255
  144. : "=r" (result)
  145. : "a" (value)
  146. );
  147. return result;
  148. }
  149. static inline int8_t S16ClipS8(int16_t value) {
  150. return S16ClipU8(value + 128) + 128;
  151. }
  152. static inline uint8_t U8Mix(uint8_t a, uint8_t b, uint8_t balance) {
  153. Word sum;
  154. asm(
  155. "mul %3, %2" "\n\t" // b * balance
  156. "movw %A0, r0" "\n\t" // to sum
  157. "com %2" "\n\t" // 255 - balance
  158. "mul %1, %2" "\n\t" // a * (255 - balance)
  159. "com %2" "\n\t" // reset balance to its previous value
  160. "add %A0, r0" "\n\t" // add to sum L
  161. "adc %B0, r1" "\n\t" // add to sum H
  162. "eor r1, r1" "\n\t" // reset r1 after multiplication
  163. : "&=r" (sum)
  164. : "a" (a), "a" (balance), "a" (b)
  165. );
  166. return sum.bytes[1];
  167. }
  168. static inline uint8_t U8Mix(
  169. uint8_t a, uint8_t b,
  170. uint8_t gain_a, uint8_t gain_b) {
  171. Word sum;
  172. asm(
  173. "mul %3, %4" "\n\t" // b * gain_b
  174. "movw %A0, r0" "\n\t" // to sum
  175. "mul %1, %2" "\n\t" // a * gain_a
  176. "add %A0, r0" "\n\t" // add to sum L
  177. "adc %B0, r1" "\n\t" // add to sum H
  178. "eor r1, r1" "\n\t" // reset r1 after multiplication
  179. : "&=r" (sum)
  180. : "a" (a), "a" (gain_a), "a" (b), "a" (gain_b)
  181. );
  182. return sum.bytes[1];
  183. }
  184. static inline int8_t S8Mix(
  185. int8_t a, int8_t b,
  186. uint8_t gain_a, uint8_t gain_b) {
  187. Word sum;
  188. asm(
  189. "mulsu %3, %4" "\n\t" // b * gain_b
  190. "movw %A0, r0" "\n\t" // to sum
  191. "mulsu %1, %2" "\n\t" // a * gain_a
  192. "add %A0, r0" "\n\t" // add to sum L
  193. "adc %B0, r1" "\n\t" // add to sum H
  194. "eor r1, r1" "\n\t" // reset r1 after multiplication
  195. : "&=r" (sum)
  196. : "a" (a), "a" (gain_a), "a" (b), "a" (gain_b)
  197. );
  198. return sum.bytes[1];
  199. }
  200. static inline uint16_t U8MixU16(uint8_t a, uint8_t b, uint8_t balance) {
  201. Word sum;
  202. asm(
  203. "mul %3, %2" "\n\t" // b * balance
  204. "movw %A0, r0" "\n\t" // to sum
  205. "com %2" "\n\t" // 255 - balance
  206. "mul %1, %2" "\n\t" // a * (255 - balance)
  207. "com %2" "\n\t" // reset balance to its previous value
  208. "add %A0, r0" "\n\t" // add to sum L
  209. "adc %B0, r1" "\n\t" // add to sum H
  210. "eor r1, r1" "\n\t" // reset r1 after multiplication
  211. : "&=r" (sum)
  212. : "a" (a), "a" (balance), "a" (b)
  213. );
  214. return sum.value;
  215. }
  216. static inline uint8_t U8U4MixU8(uint8_t a, uint8_t b, uint8_t balance) {
  217. uint16_t sum;
  218. asm(
  219. "mul %2, %1" "\n\t" // b * balance
  220. "movw %A3, r0" "\n\t" // to sum
  221. "com %1" "\n\t" // 255 - balance
  222. "subi %1, 240" "\n\t" // 15 - balance
  223. "mul %0, %1" "\n\t" // a * (15 - balance)
  224. "subi %1, 16" "\n\t"
  225. "com %1" "\n\t" // reset balance to its previous value
  226. "add %A3, r0" "\n\t" // add to sum L
  227. "adc %B3, r1" "\n\t" // add to sum H
  228. "eor r1, r1" "\n\t" // reset r1 after multiplication
  229. "andi %B3, 15" "\n\t" // keep 4 lowest bits of H
  230. "andi %A3, 240" "\n\t" // keep 4 highest bits of L
  231. "or %B3, %A3" "\n\t" // copy 4 high bits of L to H -> LLLLHHHH
  232. "swap %B3" "\n\t" // swap to get HHHHLLLL
  233. "mov %0, %B3" "\n\t" // move to output
  234. : "=r" (a)
  235. : "a" (balance), "a" (b), "a" (sum)
  236. );
  237. return a;
  238. }
  239. static inline uint16_t U8U4MixU12(uint8_t a, uint8_t b, uint8_t balance) {
  240. uint16_t sum;
  241. asm(
  242. "mul %3, %2" "\n\t" // b * balance
  243. "movw %A0, r0" "\n\t" // to sum
  244. "com %2" "\n\t" // 255 - balance
  245. "subi %2, 240" "\n\t" // 15 - balance
  246. "mul %1, %2" "\n\t" // a * (15 - balance)
  247. "subi %2, 16" "\n\t"
  248. "com %2" "\n\t" // reset balance to its previous value
  249. "add %A0, r0" "\n\t" // add to sum L
  250. "adc %B0, r1" "\n\t" // add to sum H
  251. "eor r1, r1" "\n\t" // reset r1 after multiplication
  252. : "&=r" (sum)
  253. : "a" (a), "a" (balance), "a" (b)
  254. );
  255. return sum;
  256. }
  257. static inline uint8_t U8ShiftLeft4(uint8_t a) {
  258. uint8_t result;
  259. asm(
  260. "mov %0, %1" "\n\t"
  261. "swap %0" "\n\t"
  262. "andi %0, 240" "\n\t"
  263. : "=r" (result)
  264. : "a" (a)
  265. );
  266. return result;
  267. }
  268. static inline uint8_t U8Swap4(uint8_t a) {
  269. uint8_t result;
  270. asm(
  271. "mov %0, %1" "\n\t"
  272. "swap %0" "\n\t"
  273. : "=r" (result)
  274. : "a" (a)
  275. );
  276. return result;
  277. }
  278. static inline uint8_t U8ShiftRight4(uint8_t a) {
  279. uint8_t result;
  280. asm(
  281. "mov %0, %1" "\n\t"
  282. "swap %0" "\n\t"
  283. "andi %0, 15" "\n\t"
  284. : "=r" (result)
  285. : "a" (a)
  286. );
  287. return result;
  288. }
  289. static inline uint16_t U16ShiftRight4(uint16_t a) {
  290. uint16_t result;
  291. asm(
  292. "movw %A0, %A1" "\n\t"
  293. "lsr %B0" "\n\t"
  294. "ror %A0" "\n\t"
  295. "lsr %B0" "\n\t"
  296. "ror %A0" "\n\t"
  297. "lsr %B0" "\n\t"
  298. "ror %A0" "\n\t"
  299. "lsr %B0" "\n\t"
  300. "ror %A0" "\n\t"
  301. : "=r" (result)
  302. : "a" (a)
  303. );
  304. return result;
  305. }
  306. static inline uint8_t U8U8MulShift8(uint8_t a, uint8_t b) {
  307. uint8_t result;
  308. asm(
  309. "mul %1, %2" "\n\t"
  310. "mov %0, r1" "\n\t"
  311. "eor r1, r1" "\n\t"
  312. : "=r" (result)
  313. : "a" (a), "a" (b)
  314. );
  315. return result;
  316. }
  317. static inline int8_t S8U8MulShift8(int8_t a, uint8_t b) {
  318. uint8_t result;
  319. asm(
  320. "mulsu %1, %2" "\n\t"
  321. "mov %0, r1" "\n\t"
  322. "eor r1, r1" "\n\t"
  323. : "=r" (result)
  324. : "a" (a), "a" (b)
  325. );
  326. return result;
  327. }
  328. static inline int16_t S8U8Mul(int8_t a, uint8_t b) {
  329. int16_t result;
  330. asm(
  331. "mulsu %1, %2" "\n\t"
  332. "movw %0, r0" "\n\t"
  333. "eor r1, r1" "\n\t"
  334. : "=r" (result)
  335. : "a" (a), "a" (b)
  336. );
  337. return result;
  338. }
  339. static inline int16_t S8S8Mul(int8_t a, int8_t b) {
  340. int16_t result;
  341. asm(
  342. "muls %1, %2" "\n\t"
  343. "movw %0, r0" "\n\t"
  344. "eor r1, r1" "\n\t"
  345. : "=r" (result)
  346. : "a" (a), "a" (b)
  347. );
  348. return result;
  349. }
  350. static inline uint16_t U8U8Mul(uint8_t a, uint8_t b) {
  351. uint16_t result;
  352. asm(
  353. "mul %1, %2" "\n\t"
  354. "movw %0, r0" "\n\t"
  355. "eor r1, r1" "\n\t"
  356. : "=r" (result)
  357. : "a" (a), "a" (b)
  358. );
  359. return result;
  360. }
  361. static inline int8_t S8S8MulShift8(int8_t a, int8_t b) {
  362. uint8_t result;
  363. asm(
  364. "muls %1, %2" "\n\t"
  365. "mov %0, r1" "\n\t"
  366. "eor r1, r1" "\n\t"
  367. : "=r" (result)
  368. : "a" (a), "a" (b)
  369. );
  370. return result;
  371. }
  372. // The code generated by gcc for >> 6 is short but uses a loop. This saves
  373. // a couple of cycles. Note that this solution only works for operands with
  374. // a 14-bits resolution.
  375. static inline uint8_t U14ShiftRight6(uint16_t value) {
  376. uint8_t b = value >> 8;
  377. uint8_t a = value & 0xff;
  378. uint8_t result;
  379. asm(
  380. "add %1, %1" "\n\t"
  381. "adc %2, %2" "\n\t"
  382. "add %1, %1" "\n\t"
  383. "adc %2, %2" "\n\t"
  384. : "=r" (result)
  385. : "a" (a), "0" (b)
  386. );
  387. return result;
  388. }
  389. static inline uint8_t U15ShiftRight7(uint16_t value) {
  390. uint8_t b = value >> 8;
  391. uint8_t a = value & 0xff;
  392. uint8_t result;
  393. asm(
  394. "add %1, %1" "\n\t"
  395. "adc %2, %2" "\n\t"
  396. : "=r" (result)
  397. : "a" (a), "0" (b)
  398. );
  399. return result;
  400. }
  401. static inline int16_t S16U16MulShift16(int16_t a, uint16_t b) {
  402. int16_t result;
  403. int16_t tmp;
  404. asm(
  405. "eor %A1, %A1" "\n\t"
  406. "mul %A2, %A3" "\n\t"
  407. "mov %B1, r1" "\n\t"
  408. "mulsu %B2, %B3" "\n\t"
  409. "movw %A0, r0" "\n\t"
  410. "mul %B3, %A2" "\n\t"
  411. "add %B1, r0" "\n\t"
  412. "adc %A0, r1" "\n\t"
  413. "adc %B0, %A1" "\n\t"
  414. "mulsu %B2, %A3" "\n\t"
  415. "sbc %B0, %A1" "\n\t"
  416. "add %B1, r0" "\n\t"
  417. "adc %A0, r1" "\n\t"
  418. "adc %B0, %A1" "\n\t"
  419. "eor r1, r1" "\n\t"
  420. : "=&r" (result), "=&r" (tmp)
  421. : "a" (a), "a" (b)
  422. );
  423. return result;
  424. }
  425. static inline uint16_t U16U16MulShift16(uint16_t a, uint16_t b) {
  426. uint16_t result;
  427. uint16_t tmp;
  428. asm(
  429. "eor %A1, %A1" "\n\t"
  430. "mul %A2, %A3" "\n\t"
  431. "mov %B1, r1" "\n\t"
  432. "mul %B2, %B3" "\n\t"
  433. "movw %A0, r0" "\n\t"
  434. "mul %B3, %A2" "\n\t"
  435. "add %B1, r0" "\n\t"
  436. "adc %A0, r1" "\n\t"
  437. "adc %B0, %A1" "\n\t"
  438. "mul %B2, %A3" "\n\t"
  439. "add %B1, r0" "\n\t"
  440. "adc %A0, r1" "\n\t"
  441. "adc %B0, %A1" "\n\t"
  442. "eor r1, r1" "\n\t"
  443. : "=&r" (result), "=&r" (tmp)
  444. : "a" (a), "a" (b)
  445. );
  446. return result;
  447. }
  448. static inline int16_t S16U8MulShift8(int16_t a, uint8_t b) {
  449. int16_t result;
  450. asm(
  451. "eor %B0, %B0" "\n\t"
  452. "mul %A1, %A2" "\n\t"
  453. "mov %A0, r1" "\n\t"
  454. "mulsu %B1, %A2" "\n\t"
  455. "add %A0, r0" "\n\t"
  456. "adc %B0, r1" "\n\t"
  457. "eor r1, r1" "\n\t"
  458. : "=&r" (result)
  459. : "a" (a), "a" (b)
  460. );
  461. return result;
  462. }
  463. static inline uint16_t U16U8MulShift8(uint16_t a, uint8_t b) {
  464. uint16_t result;
  465. asm(
  466. "eor %B0, %B0" "\n\t"
  467. "mul %A1, %A2" "\n\t"
  468. "mov %A0, r1" "\n\t"
  469. "mul %B1, %A2" "\n\t"
  470. "add %A0, r0" "\n\t"
  471. "adc %B0, r1" "\n\t"
  472. "eor r1, r1" "\n\t"
  473. : "=&r" (result)
  474. : "a" (a), "a" (b)
  475. );
  476. return result;
  477. }
  478. static inline int16_t S16S8MulShift8(int16_t a, int8_t b) {
  479. int16_t result;
  480. asm(
  481. "eor %B0, %B0" "\n\t"
  482. "muls %A2, %B1" "\n\t"
  483. "movw %A0, r0" "\n\t"
  484. "mulsu %A2, %A1" "\n\t"
  485. "eor r0, r0" "\n\t"
  486. "sbc %B0, r0" "\n\t"
  487. "add %A0, r1" "\n\t"
  488. "adc %B0, r0" "\n\t"
  489. "eor r1, r1" "\n\t"
  490. : "=&r" (result)
  491. : "a" (a), "a" (b)
  492. );
  493. return result;
  494. }
  495. static inline uint8_t InterpolateSample(
  496. const prog_uint8_t* table,
  497. uint16_t phase) __attribute__((always_inline));
  498. static inline uint8_t InterpolateSample(
  499. const prog_uint8_t* table,
  500. uint16_t phase) {
  501. uint8_t result;
  502. uint8_t work;
  503. asm(
  504. "movw r30, %A2" "\n\t" // copy base address to r30:r31
  505. "add r30, %B3" "\n\t" // increment table address by phaseH
  506. "adc r31, r1" "\n\t" // just carry
  507. "mov %1, %A3" "\n\t" // move phaseL to working register
  508. "lpm %0, z+" "\n\t" // load sample[n]
  509. "lpm r1, z+" "\n\t" // load sample[n+1]
  510. "mul %1, r1" "\n\t" // multiply second sample by phaseL
  511. "movw r30, r0" "\n\t" // result to accumulator
  512. "com %1" "\n\t" // 255 - phaseL -> phaseL
  513. "mul %1, %0" "\n\t" // multiply first sample by phaseL
  514. "add r30, r0" "\n\t" // accumulate L
  515. "adc r31, r1" "\n\t" // accumulate H
  516. "eor r1, r1" "\n\t" // reset r1 after multiplication
  517. "mov %0, r31" "\n\t" // use sum H as output
  518. : "=r" (result), "=r" (work)
  519. : "r" (table), "r" (phase)
  520. : "r30", "r31"
  521. );
  522. return result;
  523. }
  524. #else
  525. static inline uint24c_t U24AddC(uint24c_t a, uint24_t b) {
  526. uint24c_t result;
  527. uint32_t av = static_cast<uint32_t>(a.integral) << 8;
  528. av += a.fractional;
  529. uint32_t bv = static_cast<uint32_t>(b.integral) << 8;
  530. bv += b.fractional;
  531. uint32_t sum = av + bv;
  532. result.integral = sum >> 8;
  533. result.fractional = sum & 0xff;
  534. result.carry = (sum & 0xff000000) != 0;
  535. return result;
  536. }
  537. static inline uint24_t U24Add(uint24_t a, uint24_t b) {
  538. uint24_t result;
  539. uint32_t av = static_cast<uint32_t>(a.integral) << 8;
  540. av += a.fractional;
  541. uint32_t bv = static_cast<uint32_t>(b.integral) << 8;
  542. bv += b.fractional;
  543. uint32_t sum = av + bv;
  544. result.integral = sum >> 8;
  545. result.fractional = sum & 0xff;
  546. return result;
  547. }
  548. static inline uint24_t U24Sub(uint24_t a, uint24_t b) {
  549. uint24_t result;
  550. uint32_t av = static_cast<uint32_t>(a.integral) << 8;
  551. av += a.fractional;
  552. uint32_t bv = static_cast<uint32_t>(b.integral) << 8;
  553. bv += b.fractional;
  554. uint32_t difference = av - bv;
  555. result.integral = sum >> 8;
  556. result.fractional = sum & 0xff;
  557. return result;
  558. }
  559. static inline uint24_t U24ShiftRight(uint24_t a) {
  560. uint24_t result;
  561. uint32_t av = static_cast<uint32_t>(a.integral) << 8;
  562. av += a.fractional;
  563. av >>= 1;
  564. result.integral = av >> 8;
  565. result.fractional = av & 0xff;
  566. return result;
  567. }
  568. static inline uint24_t U24ShiftLeft(uint24_t a) {
  569. uint24_t result;
  570. uint32_t av = static_cast<uint32_t>(a.integral) << 8;
  571. av += a.fractional;
  572. av <<= 1;
  573. result.integral = av >> 8;
  574. result.fractional = av & 0xff;
  575. return result;
  576. }
  577. static inline uint8_t S16ClipU8(int16_t value) {
  578. return value < 0 ? 0 : (value > 255 ? 255 : value);
  579. }
  580. static inline int8_t S16ClipS8(int16_t value) {
  581. return value < -128 ? -128 : (value > 127 ? 127 : value);
  582. }
  583. static inline uint8_t U8Mix(uint8_t a, uint8_t b, uint8_t balance) {
  584. return a * (255 - balance) + b * balance >> 8;
  585. }
  586. static inline uint8_t U8Mix(uint8_t a, uint8_t b, uint8_t gain_a, uint8_t gain_b) {
  587. return a * gain_a + b * gain_b >> 8;
  588. }
  589. static inline int8_t S8Mix(
  590. int8_t a, int8_t b,
  591. uint8_t gain_a, uint8_t gain_b) {
  592. return a * gain_a + b * gain_b >> 8;
  593. }
  594. static inline uint16_t U8MixU16(uint8_t a, uint8_t b, uint8_t balance) {
  595. return a * (255 - balance) + b * balance;
  596. }
  597. static inline uint8_t U8U4MixU8(uint8_t a, uint8_t b, uint8_t balance) {
  598. return (a * (15 - balance) + b * balance) >> 4;
  599. }
  600. static inline uint16_t U8U4MixU12(uint8_t a, uint8_t b, uint8_t balance) {
  601. return a * (15 - balance) + b * balance;
  602. }
  603. static inline uint8_t U8ShiftRight4(uint8_t a) {
  604. return a >> 4;
  605. }
  606. static inline uint8_t U8ShiftLeft4(uint8_t a) {
  607. return a << 4;
  608. }
  609. static inline uint8_t U8Swap4(uint8_t a) {
  610. return (a << 4) | (a >> 4);
  611. }
  612. static inline uint8_t U8U8MulShift8(uint8_t a, uint8_t b) {
  613. return a * b >> 8;
  614. }
  615. static inline int8_t S8U8MulShift8(int8_t a, uint8_t b) {
  616. return a * b >> 8;
  617. }
  618. static inline int16_t S8U8Mul(int8_t a, uint8_t b) {
  619. return a * b;
  620. }
  621. static inline int16_t S8S8Mul(int8_t a, int8_t b) {
  622. return a * b;
  623. }
  624. static inline uint16_t U8U8Mul(uint8_t a, uint8_t b) {
  625. return a * b;
  626. }
  627. static inline int8_t S8S8MulShift8(int8_t a, int8_t b) {
  628. return a * b >> 8;
  629. }
  630. static inline uint16_t Mul16Scale8(uint16_t a, uint16_t b) {
  631. return static_cast<uint32_t>(a) * b >> 8;
  632. }
  633. static inline uint8_t U14ShiftRight6(uint16_t value) {
  634. return value >> 6;
  635. }
  636. static inline uint8_t U15ShiftRight7(uint16_t value) {
  637. return value >> 7;
  638. }
  639. static inline uint16_t U16ShiftRight4(uint16_t a) {
  640. return a >> 4;
  641. }
  642. static inline int16_t S16U16MulShift16(int16_t a, uint16_t b) {
  643. return (static_cast<int32_t>(a) * static_cast<uint32_t>(b)) >> 16;
  644. }
  645. static inline int16_t S16U8MulShift8(int16_t a, uint8_t b) {
  646. return (static_cast<int32_t>(a) * static_cast<uint32_t>(b)) >> 8;
  647. }
  648. static inline uint16_t U16U8MulShift8(uint16_t a, uint8_t b) {
  649. return (static_cast<uint32_t>(a) * static_cast<uint32_t>(b)) >> 8;
  650. }
  651. static inline uint8_t InterpolateSample(
  652. const prog_uint8_t* table,
  653. uint16_t phase) {
  654. return U8Mix(
  655. pgm_read_byte(table + (phase >> 8)),
  656. pgm_read_byte(1 + table + (phase >> 8)),
  657. phase & 0xff);
  658. }
  659. #endif // USE_OPTIMIZED_OP
  660. } // namespace avrlib
  661. #endif // AVRLIB_OP_H_