123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- /*
- * Squeezelite - lightweight headless squeezebox emulator
- *
- * (c) Adrian Smith 2012-2015, triode1@btinternet.com
- * Ralph Irving 2015-2017, ralph_irving@hotmail.com
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- // Scale and pack functions
- #include "squeezelite.h"
- #define MAX_SCALESAMPLE 0x7fffffffffffLL
- #define MIN_SCALESAMPLE -MAX_SCALESAMPLE
- // inlining these on windows prevents them being linkable...
- #if !WIN
- inline
- #endif
- s32_t gain(s32_t gain, s32_t sample) {
- s64_t res = (s64_t)gain * (s64_t)sample;
- if (res > MAX_SCALESAMPLE) res = MAX_SCALESAMPLE;
- if (res < MIN_SCALESAMPLE) res = MIN_SCALESAMPLE;
- return (s32_t) (res >> 16);
- }
- #if !WIN
- inline
- #endif
- s32_t to_gain(float f) {
- return (s32_t)(f * 65536.0F);
- }
- void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, u8_t flags, output_format format) {
- // in-place copy input samples if mono/combined is used (never happens with DSD active)
- if ((flags & MONO_LEFT) && (flags & MONO_RIGHT)) {
- s32_t *ptr = inputptr;
- frames_t count = cnt;
- while (count--) {
- // use 64 bits integer for purists but should really not care
- *ptr = *(ptr + 1) = ((s64_t) *ptr + (s64_t) *(ptr + 1)) / 2;
- ptr += 2;
- }
- } else if (flags & MONO_RIGHT) {
- s32_t *ptr = inputptr + 1;
- frames_t count = cnt;
- while (count--) {
- *(ptr - 1) = *ptr;
- ptr += 2;
- }
- } else if (flags & MONO_LEFT) {
- s32_t *ptr = inputptr;
- frames_t count = cnt;
- while (count--) {
- *(ptr + 1) = *ptr;
- ptr += 2;
- }
- }
-
- switch(format) {
- #if DSD
- case U32_LE:
- {
- #if SL_LITTLE_ENDIAN
- memcpy(outputptr, inputptr, cnt * BYTES_PER_FRAME);
- #else
- u32_t *optr = (u32_t *)(void *)outputptr;
- while (cnt--) {
- s32_t lsample = *(inputptr++);
- s32_t rsample = *(inputptr++);
- *(optr++) =
- (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
- (lsample & 0x0000ff00) << 8 | (lsample & 0x000000ff) << 24;
- *(optr++) =
- (rsample & 0xff000000) >> 24 | (rsample & 0x00ff0000) >> 8 |
- (rsample & 0x0000ff00) << 8 | (rsample & 0x000000ff) << 24;
- }
- #endif
- }
- break;
- case U32_BE:
- {
- #if SL_LITTLE_ENDIAN
- u32_t *optr = (u32_t *)(void *)outputptr;
- while (cnt--) {
- s32_t lsample = *(inputptr++);
- s32_t rsample = *(inputptr++);
- *(optr++) =
- (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
- (lsample & 0x0000ff00) << 8 | (lsample & 0x000000ff) << 24;
- *(optr++) =
- (rsample & 0xff000000) >> 24 | (rsample & 0x00ff0000) >> 8 |
- (rsample & 0x0000ff00) << 8 | (rsample & 0x000000ff) << 24;
- }
- #else
- memcpy(outputptr, inputptr, cnt * BYTES_PER_FRAME);
- #endif
- }
- break;
- case U16_LE:
- {
- u32_t *optr = (u32_t *)(void *)outputptr;
- #if SL_LITTLE_ENDIAN
- while (cnt--) {
- *(optr++) = (*(inputptr) >> 16 & 0x0000ffff) | (*(inputptr + 1) & 0xffff0000);
- inputptr += 2;
- }
- #else
- while (cnt--) {
- s32_t lsample = *(inputptr++);
- s32_t rsample = *(inputptr++);
- *(optr++) =
- (lsample & 0x00ff0000) << 8 | (lsample & 0xff000000) >> 8 |
- (rsample & 0x00ff0000) >> 8 | (rsample & 0xff000000) >> 24;
- }
- #endif
- }
- break;
- case U16_BE:
- {
- u32_t *optr = (u32_t *)(void *)outputptr;
- #if SL_LITTLE_ENDIAN
- while (cnt--) {
- s32_t lsample = *(inputptr++);
- s32_t rsample = *(inputptr++);
- *(optr++) =
- (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
- (rsample & 0xff000000) >> 8 | (rsample & 0x00ff0000) << 8;
- }
- #else
- while (cnt--) {
- *(optr++) = (*(inputptr) & 0xffff0000) | (*(inputptr + 1) >> 16 & 0x0000ffff);
- inputptr += 2;
- }
- #endif
- }
- break;
- case U8:
- {
- u16_t *optr = (u16_t *)(void *)outputptr;
- #if SL_LITTLE_ENDIAN
- while (cnt--) {
- *(optr++) = (u16_t)((*(inputptr) >> 24 & 0x000000ff) | (*(inputptr + 1) >> 16 & 0x0000ff00));
- inputptr += 2;
- }
- #else
- while (cnt--) {
- *(optr++) = (u16_t)((*(inputptr) >> 16 & 0x0000ff00) | (*(inputptr + 1) >> 24 & 0x000000ff));
- inputptr += 2;
- }
- #endif
- }
- break;
- #endif
- case S16_LE:
- {
- u32_t *optr = (u32_t *)(void *)outputptr;
- #if SL_LITTLE_ENDIAN
- if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
- while (cnt--) {
- *(optr++) = (*(inputptr) >> 16 & 0x0000ffff) | (*(inputptr + 1) & 0xffff0000);
- inputptr += 2;
- }
- } else {
- while (cnt--) {
- *(optr++) = (gain(gainL, *(inputptr)) >> 16 & 0x0000ffff) | (gain(gainR, *(inputptr+1)) & 0xffff0000);
- inputptr += 2;
- }
- }
- #else
- if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
- while (cnt--) {
- s32_t lsample = *(inputptr++);
- s32_t rsample = *(inputptr++);
- *(optr++) =
- (lsample & 0x00ff0000) << 8 | (lsample & 0xff000000) >> 8 |
- (rsample & 0x00ff0000) >> 8 | (rsample & 0xff000000) >> 24;
- }
- } else {
- while (cnt--) {
- s32_t lsample = gain(gainL, *(inputptr++));
- s32_t rsample = gain(gainR, *(inputptr++));
- *(optr++) =
- (lsample & 0x00ff0000) << 8 | (lsample & 0xff000000) >> 8 |
- (rsample & 0x00ff0000) >> 8 | (rsample & 0xff000000) >> 24;
- }
- }
- #endif
- }
- break;
- case S24_LE:
- {
- u32_t *optr = (u32_t *)(void *)outputptr;
- #if SL_LITTLE_ENDIAN
- if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
- while (cnt--) {
- *(optr++) = *(inputptr++) >> 8;
- *(optr++) = *(inputptr++) >> 8;
- }
- } else {
- while (cnt--) {
- *(optr++) = gain(gainL, *(inputptr++)) >> 8;
- *(optr++) = gain(gainR, *(inputptr++)) >> 8;
- }
- }
- #else
- if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
- while (cnt--) {
- s32_t lsample = *(inputptr++);
- s32_t rsample = *(inputptr++);
- *(optr++) =
- (lsample & 0xff000000) >> 16 | (lsample & 0x00ff0000) | (lsample & 0x0000ff00 << 16);
- *(optr++) =
- (rsample & 0xff000000) >> 16 | (rsample & 0x00ff0000) | (rsample & 0x0000ff00 << 16);
- }
- } else {
- while (cnt--) {
- s32_t lsample = gain(gainL, *(inputptr++));
- s32_t rsample = gain(gainR, *(inputptr++));
- *(optr++) =
- (lsample & 0xff000000) >> 16 | (lsample & 0x00ff0000) | (lsample & 0x0000ff00 << 16);
- *(optr++) =
- (rsample & 0xff000000) >> 16 | (rsample & 0x00ff0000) | (rsample & 0x0000ff00 << 16);
- }
- }
- #endif
- }
- break;
- case S24_3LE:
- {
- u8_t *optr = (u8_t *)(void *)outputptr;
- if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
- while (cnt) {
- // attempt to do 32 bit memory accesses - move 2 frames at once: 16 bytes -> 12 bytes
- // falls through to exception case when not aligned or if less than 2 frames to move
- if (((uintptr_t)optr & 0x3) == 0 && cnt >= 2) {
- u32_t *o_ptr = (u32_t *)(void *)optr;
- while (cnt >= 2) {
- s32_t l1 = *(inputptr++); s32_t r1 = *(inputptr++);
- s32_t l2 = *(inputptr++); s32_t r2 = *(inputptr++);
- #if SL_LITTLE_ENDIAN
- *(o_ptr++) = (l1 & 0xffffff00) >> 8 | (r1 & 0x0000ff00) << 16;
- *(o_ptr++) = (r1 & 0xffff0000) >> 16 | (l2 & 0x00ffff00) << 8;
- *(o_ptr++) = (l2 & 0xff000000) >> 24 | (r2 & 0xffffff00);
- #else
- *(o_ptr++) = (l1 & 0x0000ff00) << 16 | (l1 & 0x00ff0000) | (l1 & 0xff000000) >> 16 |
- (r1 & 0x0000ff00) >> 8;
- *(o_ptr++) = (r1 & 0x00ff0000) << 8 | (r1 & 0xff000000) >> 8 | (l2 & 0x0000ff00) |
- (l2 & 0x00ff0000) >> 16;
- *(o_ptr++) = (l2 & 0xff000000) | (r2 & 0x0000ff00) << 8 | (r2 & 0x00ff0000) >> 8 |
- (r2 & 0xff000000) >> 24;
- #endif
- optr += 12;
- cnt -= 2;
- }
- } else {
- s32_t lsample = *(inputptr++);
- s32_t rsample = *(inputptr++);
- *(optr++) = (lsample & 0x0000ff00) >> 8;
- *(optr++) = (lsample & 0x00ff0000) >> 16;
- *(optr++) = (lsample & 0xff000000) >> 24;
- *(optr++) = (rsample & 0x0000ff00) >> 8;
- *(optr++) = (rsample & 0x00ff0000) >> 16;
- *(optr++) = (rsample & 0xff000000) >> 24;
- cnt--;
- }
- }
- } else {
- while (cnt) {
- // attempt to do 32 bit memory accesses - move 2 frames at once: 16 bytes -> 12 bytes
- // falls through to exception case when not aligned or if less than 2 frames to move
- if (((uintptr_t)optr & 0x3) == 0 && cnt >= 2) {
- u32_t *o_ptr = (u32_t *)(void *)optr;
- while (cnt >= 2) {
- s32_t l1 = gain(gainL, *(inputptr++)); s32_t r1 = gain(gainR, *(inputptr++));
- s32_t l2 = gain(gainL, *(inputptr++)); s32_t r2 = gain(gainR, *(inputptr++));
- #if SL_LITTLE_ENDIAN
- *(o_ptr++) = (l1 & 0xffffff00) >> 8 | (r1 & 0x0000ff00) << 16;
- *(o_ptr++) = (r1 & 0xffff0000) >> 16 | (l2 & 0x00ffff00) << 8;
- *(o_ptr++) = (l2 & 0xff000000) >> 24 | (r2 & 0xffffff00);
- #else
- *(o_ptr++) = (l1 & 0x0000ff00) << 16 | (l1 & 0x00ff0000) | (l1 & 0xff000000) >> 16 |
- (r1 & 0x0000ff00) >> 8;
- *(o_ptr++) = (r1 & 0x00ff0000) << 8 | (r1 & 0xff000000) >> 8 | (l2 & 0x0000ff00) |
- (l2 & 0x00ff0000) >> 16;
- *(o_ptr++) = (l2 & 0xff000000) | (r2 & 0x0000ff00) << 8 | (r2 & 0x00ff0000) >> 8 |
- (r2 & 0xff000000) >> 24;
- #endif
- optr += 12;
- cnt -= 2;
- }
- } else {
- s32_t lsample = gain(gainL, *(inputptr++));
- s32_t rsample = gain(gainR, *(inputptr++));
- *(optr++) = (lsample & 0x0000ff00) >> 8;
- *(optr++) = (lsample & 0x00ff0000) >> 16;
- *(optr++) = (lsample & 0xff000000) >> 24;
- *(optr++) = (rsample & 0x0000ff00) >> 8;
- *(optr++) = (rsample & 0x00ff0000) >> 16;
- *(optr++) = (rsample & 0xff000000) >> 24;
- cnt--;
- }
- }
- }
- }
- break;
- case S32_LE:
- {
- u32_t *optr = (u32_t *)(void *)outputptr;
- #if SL_LITTLE_ENDIAN
- if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
- memcpy(outputptr, inputptr, cnt * BYTES_PER_FRAME);
- } else {
- while (cnt--) {
- *(optr++) = gain(gainL, *(inputptr++));
- *(optr++) = gain(gainR, *(inputptr++));
- }
- }
- #else
- if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
- while (cnt--) {
- s32_t lsample = *(inputptr++);
- s32_t rsample = *(inputptr++);
- *(optr++) =
- (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
- (lsample & 0x0000ff00) << 8 | (lsample & 0x000000ff) << 24;
- *(optr++) =
- (rsample & 0xff000000) >> 24 | (rsample & 0x00ff0000) >> 8 |
- (rsample & 0x0000ff00) << 8 | (rsample & 0x000000ff) << 24;
- }
- } else {
- while (cnt--) {
- s32_t lsample = gain(gainL, *(inputptr++));
- s32_t rsample = gain(gainR, *(inputptr++));
- *(optr++) =
- (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
- (lsample & 0x0000ff00) << 8 | (lsample & 0x000000ff) << 24;
- *(optr++) =
- (rsample & 0xff000000) >> 24 | (rsample & 0x00ff0000) >> 8 |
- (rsample & 0x0000ff00) << 8 | (rsample & 0x000000ff) << 24;
- }
- }
- #endif
- }
- break;
- default:
- break;
- }
- }
- #if !WIN
- inline
- #endif
- void _apply_cross(struct buffer *outputbuf, frames_t out_frames, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr) {
- ISAMPLE_T *ptr = (ISAMPLE_T *)(void *)outputbuf->readp;
- frames_t count = out_frames * 2;
- while (count--) {
- if (*cross_ptr > (ISAMPLE_T *)outputbuf->wrap) {
- *cross_ptr -= outputbuf->size / BYTES_PER_FRAME * 2;
- }
- *ptr = gain(cross_gain_out, *ptr) + gain(cross_gain_in, **cross_ptr);
- ptr++; (*cross_ptr)++;
- }
- }
- #if !WIN
- inline
- #endif
- void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR, u8_t flags) {
- if (gainL == FIXED_ONE && gainR == FIXED_ONE && !(flags & (MONO_LEFT | MONO_RIGHT))) {
- return;
- } else if ((flags & MONO_LEFT) && (flags & MONO_RIGHT)) {
- ISAMPLE_T *ptrL = (ISAMPLE_T *)(void *)outputbuf->readp;
- ISAMPLE_T *ptrR = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
- while (count--) {
- *ptrL = *ptrR = (gain(gainL, *ptrL) + gain(gainR, *ptrR)) / 2;
- ptrL += 2; ptrR += 2;
- }
- } else if (flags & MONO_RIGHT) {
- ISAMPLE_T *ptr = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
- while (count--) {
- *(ptr - 1) = *ptr = gain(gainR, *ptr);
- ptr += 2;
- }
- } else if (flags & MONO_LEFT) {
- ISAMPLE_T *ptr = (ISAMPLE_T *)(void *)outputbuf->readp;
- while (count--) {
- *(ptr + 1) = *ptr = gain(gainL, *ptr);
- ptr += 2;
- }
- } else {
- ISAMPLE_T *ptrL = (ISAMPLE_T *)(void *)outputbuf->readp;
- ISAMPLE_T *ptrR = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
- while (count--) {
- *ptrL = gain(gainL, *ptrL);
- *ptrR = gain(gainR, *ptrR);
- ptrL += 2; ptrR += 2;
- }
- }
- }
|