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.

784 lines
20KB

  1. // Copyright 2011 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 AVRLIBX_UTILS_OP_H_
  21. #define AVRLIBX_UTILS_OP_H_
  22. #define USE_OPTIMIZED_OP
  23. #include <avr/pgmspace.h>
  24. #include "avrlibx/avrlibx.h"
  25. namespace avrlibx {
  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 int16_t S16U12MulShift12(int16_t a, uint16_t b) {
  426. int16_t result;
  427. int16_t tmp;
  428. asm(
  429. "add %A3, %A3" "\n\t"
  430. "adc %B3, %B3" "\n\t"
  431. "add %A3, %A3" "\n\t"
  432. "adc %B3, %B3" "\n\t"
  433. "add %A3, %A3" "\n\t"
  434. "adc %B3, %B3" "\n\t"
  435. "add %A3, %A3" "\n\t"
  436. "adc %B3, %B3" "\n\t"
  437. "eor %A1, %A1" "\n\t"
  438. "mul %A2, %A3" "\n\t"
  439. "mov %B1, r1" "\n\t"
  440. "mulsu %B2, %B3" "\n\t"
  441. "movw %A0, r0" "\n\t"
  442. "mul %B3, %A2" "\n\t"
  443. "add %B1, r0" "\n\t"
  444. "adc %A0, r1" "\n\t"
  445. "adc %B0, %A1" "\n\t"
  446. "mulsu %B2, %A3" "\n\t"
  447. "sbc %B0, %A1" "\n\t"
  448. "add %B1, r0" "\n\t"
  449. "adc %A0, r1" "\n\t"
  450. "adc %B0, %A1" "\n\t"
  451. "eor r1, r1" "\n\t"
  452. : "=&r" (result), "=&r" (tmp)
  453. : "a" (a), "a" (b)
  454. );
  455. return result;
  456. }
  457. static inline uint16_t U16U16MulShift16(uint16_t a, uint16_t b) {
  458. uint16_t result;
  459. uint16_t tmp;
  460. asm(
  461. "eor %A1, %A1" "\n\t"
  462. "mul %A2, %A3" "\n\t"
  463. "mov %B1, r1" "\n\t"
  464. "mul %B2, %B3" "\n\t"
  465. "movw %A0, r0" "\n\t"
  466. "mul %B3, %A2" "\n\t"
  467. "add %B1, r0" "\n\t"
  468. "adc %A0, r1" "\n\t"
  469. "adc %B0, %A1" "\n\t"
  470. "mul %B2, %A3" "\n\t"
  471. "add %B1, r0" "\n\t"
  472. "adc %A0, r1" "\n\t"
  473. "adc %B0, %A1" "\n\t"
  474. "eor r1, r1" "\n\t"
  475. : "=&r" (result), "=&r" (tmp)
  476. : "a" (a), "a" (b)
  477. );
  478. return result;
  479. }
  480. static inline int16_t S16U8MulShift8(int16_t a, uint8_t b) {
  481. int16_t result;
  482. asm(
  483. "eor %B0, %B0" "\n\t"
  484. "mul %A1, %A2" "\n\t"
  485. "mov %A0, r1" "\n\t"
  486. "mulsu %B1, %A2" "\n\t"
  487. "add %A0, r0" "\n\t"
  488. "adc %B0, r1" "\n\t"
  489. "eor r1, r1" "\n\t"
  490. : "=&r" (result)
  491. : "a" (a), "a" (b)
  492. );
  493. return result;
  494. }
  495. static inline uint16_t U16U8MulShift8(uint16_t a, uint8_t b) {
  496. uint16_t result;
  497. asm(
  498. "eor %B0, %B0" "\n\t"
  499. "mul %A1, %A2" "\n\t"
  500. "mov %A0, r1" "\n\t"
  501. "mul %B1, %A2" "\n\t"
  502. "add %A0, r0" "\n\t"
  503. "adc %B0, r1" "\n\t"
  504. "eor r1, r1" "\n\t"
  505. : "=&r" (result)
  506. : "a" (a), "a" (b)
  507. );
  508. return result;
  509. }
  510. static inline int16_t S16S8MulShift8(int16_t a, int8_t b) {
  511. int16_t result;
  512. asm(
  513. "eor %B0, %B0" "\n\t"
  514. "muls %A2, %B1" "\n\t"
  515. "movw %A0, r0" "\n\t"
  516. "mulsu %A2, %A1" "\n\t"
  517. "eor r0, r0" "\n\t"
  518. "sbc %B0, r0" "\n\t"
  519. "add %A0, r1" "\n\t"
  520. "adc %B0, r0" "\n\t"
  521. "eor r1, r1" "\n\t"
  522. : "=&r" (result)
  523. : "a" (a), "a" (b)
  524. );
  525. return result;
  526. }
  527. static inline uint8_t InterpolateSample(
  528. const prog_uint8_t* table,
  529. uint16_t phase) __attribute__((always_inline));
  530. static inline uint8_t InterpolateSample(
  531. const prog_uint8_t* table,
  532. uint16_t phase) {
  533. uint8_t result;
  534. uint8_t work;
  535. asm(
  536. "movw r30, %A2" "\n\t" // copy base address to r30:r31
  537. "add r30, %B3" "\n\t" // increment table address by phaseH
  538. "adc r31, r1" "\n\t" // just carry
  539. "mov %1, %A3" "\n\t" // move phaseL to working register
  540. "lpm %0, z+" "\n\t" // load sample[n]
  541. "lpm r1, z+" "\n\t" // load sample[n+1]
  542. "mul %1, r1" "\n\t" // multiply second sample by phaseL
  543. "movw r30, r0" "\n\t" // result to accumulator
  544. "com %1" "\n\t" // 255 - phaseL -> phaseL
  545. "mul %1, %0" "\n\t" // multiply first sample by phaseL
  546. "add r30, r0" "\n\t" // accumulate L
  547. "adc r31, r1" "\n\t" // accumulate H
  548. "eor r1, r1" "\n\t" // reset r1 after multiplication
  549. "mov %0, r31" "\n\t" // use sum H as output
  550. : "=r" (result), "=r" (work)
  551. : "r" (table), "r" (phase)
  552. : "r30", "r31"
  553. );
  554. return result;
  555. }
  556. #else
  557. static inline uint24c_t U24AddC(uint24c_t a, uint24_t b) {
  558. uint24c_t result;
  559. uint32_t av = static_cast<uint32_t>(a.integral) << 8;
  560. av += a.fractional;
  561. uint32_t bv = static_cast<uint32_t>(b.integral) << 8;
  562. bv += b.fractional;
  563. uint32_t sum = av + bv;
  564. result.integral = sum >> 8;
  565. result.fractional = sum & 0xff;
  566. result.carry = (sum & 0xff000000) != 0;
  567. return result;
  568. }
  569. static inline uint24_t U24Add(uint24_t a, uint24_t b) {
  570. uint24_t result;
  571. uint32_t av = static_cast<uint32_t>(a.integral) << 8;
  572. av += a.fractional;
  573. uint32_t bv = static_cast<uint32_t>(b.integral) << 8;
  574. bv += b.fractional;
  575. uint32_t sum = av + bv;
  576. result.integral = sum >> 8;
  577. result.fractional = sum & 0xff;
  578. return result;
  579. }
  580. static inline uint24_t U24Sub(uint24_t a, uint24_t b) {
  581. uint24_t result;
  582. uint32_t av = static_cast<uint32_t>(a.integral) << 8;
  583. av += a.fractional;
  584. uint32_t bv = static_cast<uint32_t>(b.integral) << 8;
  585. bv += b.fractional;
  586. uint32_t difference = av - bv;
  587. result.integral = sum >> 8;
  588. result.fractional = sum & 0xff;
  589. return result;
  590. }
  591. static inline uint24_t U24ShiftRight(uint24_t a) {
  592. uint24_t result;
  593. uint32_t av = static_cast<uint32_t>(a.integral) << 8;
  594. av += a.fractional;
  595. av >>= 1;
  596. result.integral = av >> 8;
  597. result.fractional = av & 0xff;
  598. return result;
  599. }
  600. static inline uint24_t U24ShiftLeft(uint24_t a) {
  601. uint24_t result;
  602. uint32_t av = static_cast<uint32_t>(a.integral) << 8;
  603. av += a.fractional;
  604. av <<= 1;
  605. result.integral = av >> 8;
  606. result.fractional = av & 0xff;
  607. return result;
  608. }
  609. static inline uint8_t S16ClipU8(int16_t value) {
  610. return value < 0 ? 0 : (value > 255 ? 255 : value);
  611. }
  612. static inline int8_t S16ClipS8(int16_t value) {
  613. return value < -128 ? -128 : (value > 127 ? 127 : value);
  614. }
  615. static inline uint8_t U8Mix(uint8_t a, uint8_t b, uint8_t balance) {
  616. return a * (255 - balance) + b * balance >> 8;
  617. }
  618. static inline uint8_t U8Mix(uint8_t a, uint8_t b, uint8_t gain_a, uint8_t gain_b) {
  619. return a * gain_a + b * gain_b >> 8;
  620. }
  621. static inline int8_t S8Mix(
  622. int8_t a, int8_t b,
  623. uint8_t gain_a, uint8_t gain_b) {
  624. return a * gain_a + b * gain_b >> 8;
  625. }
  626. static inline uint16_t U8MixU16(uint8_t a, uint8_t b, uint8_t balance) {
  627. return a * (255 - balance) + b * balance;
  628. }
  629. static inline uint8_t U8U4MixU8(uint8_t a, uint8_t b, uint8_t balance) {
  630. return (a * (15 - balance) + b * balance) >> 4;
  631. }
  632. static inline uint16_t U8U4MixU12(uint8_t a, uint8_t b, uint8_t balance) {
  633. return a * (15 - balance) + b * balance;
  634. }
  635. static inline uint8_t U8ShiftRight4(uint8_t a) {
  636. return a >> 4;
  637. }
  638. static inline uint8_t U8ShiftLeft4(uint8_t a) {
  639. return a << 4;
  640. }
  641. static inline uint8_t U8Swap4(uint8_t a) {
  642. return (a << 4) | (a >> 4);
  643. }
  644. static inline uint8_t U8U8MulShift8(uint8_t a, uint8_t b) {
  645. return a * b >> 8;
  646. }
  647. static inline int8_t S8U8MulShift8(int8_t a, uint8_t b) {
  648. return a * b >> 8;
  649. }
  650. static inline int16_t S8U8Mul(int8_t a, uint8_t b) {
  651. return a * b;
  652. }
  653. static inline int16_t S8S8Mul(int8_t a, int8_t b) {
  654. return a * b;
  655. }
  656. static inline uint16_t U8U8Mul(uint8_t a, uint8_t b) {
  657. return a * b;
  658. }
  659. static inline int8_t S8S8MulShift8(int8_t a, int8_t b) {
  660. return a * b >> 8;
  661. }
  662. static inline uint16_t Mul16Scale8(uint16_t a, uint16_t b) {
  663. return static_cast<uint32_t>(a) * b >> 8;
  664. }
  665. static inline uint8_t U14ShiftRight6(uint16_t value) {
  666. return value >> 6;
  667. }
  668. static inline uint8_t U15ShiftRight7(uint16_t value) {
  669. return value >> 7;
  670. }
  671. static inline uint16_t U16ShiftRight4(uint16_t a) {
  672. return a >> 4;
  673. }
  674. static inline int16_t S16U16MulShift16(int16_t a, uint16_t b) {
  675. return (static_cast<int32_t>(a) * static_cast<uint32_t>(b)) >> 16;
  676. }
  677. static inline int12_t S16U12MulShift12(int16_t a, uint16_t b) {
  678. return (static_cast<int32_t>(a) * static_cast<uint32_t>(b)) >> 12;
  679. }
  680. static inline int16_t S16U8MulShift8(int16_t a, uint8_t b) {
  681. return (static_cast<int32_t>(a) * static_cast<uint32_t>(b)) >> 8;
  682. }
  683. static inline uint16_t U16U8MulShift8(uint16_t a, uint8_t b) {
  684. return (static_cast<uint32_t>(a) * static_cast<uint32_t>(b)) >> 8;
  685. }
  686. static inline uint8_t InterpolateSample(
  687. const prog_uint8_t* table,
  688. uint16_t phase) {
  689. return U8Mix(
  690. pgm_read_byte(table + (phase >> 8)),
  691. pgm_read_byte(1 + table + (phase >> 8)),
  692. phase & 0xff);
  693. }
  694. #endif // USE_OPTIMIZED_OP
  695. } // namespace avrlibx
  696. #endif // AVRLIBX_UTILS_OP_H_