]>
code.delx.au - pulseaudio/blob - src/pulsecore/sample-util.c
4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 #include <liboil/liboilfuncs.h>
34 #include <liboil/liboil.h>
36 #include <pulsecore/log.h>
37 #include <pulsecore/macro.h>
38 #include <pulsecore/g711.h>
40 #include "sample-util.h"
41 #include "endianmacros.h"
43 #define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
45 pa_memblock
*pa_silence_memblock_new(pa_mempool
*pool
, const pa_sample_spec
*spec
, size_t length
) {
52 length
= PA_MIN(pa_bytes_per_second(spec
)/20, /* 50 ms */
53 pa_mempool_block_size_max(pool
));
55 if (length
> PA_SILENCE_MAX
)
56 length
= PA_SILENCE_MAX
;
58 length
= pa_frame_align(length
, spec
);
60 b
= pa_silence_memblock(pa_memblock_new(pool
, length
), spec
);
62 pa_memblock_set_is_silence(b
, TRUE
);
67 pa_memblock
*pa_silence_memblock(pa_memblock
* b
, const pa_sample_spec
*spec
) {
73 data
= pa_memblock_acquire(b
);
74 pa_silence_memory(data
, pa_memblock_get_length(b
), spec
);
75 pa_memblock_release(b
);
80 void pa_silence_memchunk(pa_memchunk
*c
, const pa_sample_spec
*spec
) {
84 pa_assert(c
->memblock
);
87 data
= pa_memblock_acquire(c
->memblock
);
88 pa_silence_memory((uint8_t*) data
+c
->index
, c
->length
, spec
);
89 pa_memblock_release(c
->memblock
);
92 void pa_silence_memory(void *p
, size_t length
, const pa_sample_spec
*spec
) {
95 pa_assert(length
> 0);
98 switch (spec
->format
) {
102 case PA_SAMPLE_S16LE
:
103 case PA_SAMPLE_S16BE
:
104 case PA_SAMPLE_S32LE
:
105 case PA_SAMPLE_S32BE
:
106 case PA_SAMPLE_FLOAT32
:
107 case PA_SAMPLE_FLOAT32RE
:
117 pa_assert_not_reached();
120 memset(p
, c
, length
);
123 static void calc_linear_integer_stream_volumes(pa_mix_info streams
[], unsigned nstreams
, const pa_sample_spec
*spec
) {
129 for (k
= 0; k
< nstreams
; k
++) {
132 for (channel
= 0; channel
< spec
->channels
; channel
++) {
133 pa_mix_info
*m
= streams
+ k
;
134 m
->linear
[channel
].i
= (int32_t) (pa_sw_volume_to_linear(m
->volume
.values
[channel
]) * 0x10000);
139 static void calc_linear_integer_volume(int32_t linear
[], const pa_cvolume
*volume
) {
145 for (channel
= 0; channel
< volume
->channels
; channel
++)
146 linear
[channel
] = (int32_t) (pa_sw_volume_to_linear(volume
->values
[channel
]) * 0x10000);
149 static void calc_linear_float_stream_volumes(pa_mix_info streams
[], unsigned nstreams
, const pa_sample_spec
*spec
) {
155 for (k
= 0; k
< nstreams
; k
++) {
158 for (channel
= 0; channel
< spec
->channels
; channel
++) {
159 pa_mix_info
*m
= streams
+ k
;
160 m
->linear
[channel
].f
= pa_sw_volume_to_linear(m
->volume
.values
[channel
]);
165 static void calc_linear_float_volume(float linear
[], const pa_cvolume
*volume
) {
171 for (channel
= 0; channel
< volume
->channels
; channel
++)
172 linear
[channel
] = pa_sw_volume_to_linear(volume
->values
[channel
]);
176 pa_mix_info streams
[],
180 const pa_sample_spec
*spec
,
181 const pa_cvolume
*volume
,
184 pa_cvolume full_volume
;
194 volume
= pa_cvolume_reset(&full_volume
, spec
->channels
);
196 for (k
= 0; k
< nstreams
; k
++)
197 streams
[k
].ptr
= (uint8_t*) pa_memblock_acquire(streams
[k
].chunk
.memblock
) + streams
[k
].chunk
.index
;
199 switch (spec
->format
) {
201 case PA_SAMPLE_S16NE
:{
202 unsigned channel
= 0;
203 int32_t linear
[PA_CHANNELS_MAX
];
205 calc_linear_integer_stream_volumes(streams
, nstreams
, spec
);
206 calc_linear_integer_volume(linear
, volume
);
208 for (d
= 0;; d
+= sizeof(int16_t)) {
212 if (PA_UNLIKELY(d
>= length
))
215 for (i
= 0; i
< nstreams
; i
++) {
216 pa_mix_info
*m
= streams
+ i
;
217 int32_t v
, cv
= m
->linear
[channel
].i
;
219 if (PA_UNLIKELY(d
>= m
->chunk
.length
))
222 if (PA_UNLIKELY(cv
<= 0) || PA_UNLIKELY(!!mute
) || PA_UNLIKELY(linear
[channel
] <= 0))
225 v
= *((int16_t*) m
->ptr
);
226 v
= (v
* cv
) / 0x10000;
230 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(int16_t);
233 sum
= PA_CLAMP_UNLIKELY(sum
, -0x8000, 0x7FFF);
234 sum
= (sum
* linear
[channel
]) / 0x10000;
235 *((int16_t*) data
) = (int16_t) sum
;
237 data
= (uint8_t*) data
+ sizeof(int16_t);
239 if (PA_UNLIKELY(++channel
>= spec
->channels
))
246 case PA_SAMPLE_S16RE
:{
247 unsigned channel
= 0;
248 int32_t linear
[PA_CHANNELS_MAX
];
250 calc_linear_integer_stream_volumes(streams
, nstreams
, spec
);
251 calc_linear_integer_volume(linear
, volume
);
253 for (d
= 0;; d
+= sizeof(int16_t)) {
257 if (PA_UNLIKELY(d
>= length
))
260 for (i
= 0; i
< nstreams
; i
++) {
261 pa_mix_info
*m
= streams
+ i
;
262 int32_t v
, cv
= m
->linear
[channel
].i
;
264 if (PA_UNLIKELY(d
>= m
->chunk
.length
))
267 if (PA_UNLIKELY(cv
<= 0) || PA_UNLIKELY(!!mute
) || PA_UNLIKELY(linear
[channel
] <= 0))
270 v
= PA_INT16_SWAP(*((int16_t*) m
->ptr
));
271 v
= (v
* cv
) / 0x10000;
275 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(int16_t);
278 sum
= PA_CLAMP_UNLIKELY(sum
, -0x8000, 0x7FFF);
279 sum
= (sum
* linear
[channel
]) / 0x10000;
280 *((int16_t*) data
) = PA_INT16_SWAP((int16_t) sum
);
282 data
= (uint8_t*) data
+ sizeof(int16_t);
284 if (PA_UNLIKELY(++channel
>= spec
->channels
))
291 case PA_SAMPLE_S32NE
:{
292 unsigned channel
= 0;
293 int32_t linear
[PA_CHANNELS_MAX
];
295 calc_linear_integer_stream_volumes(streams
, nstreams
, spec
);
296 calc_linear_integer_volume(linear
, volume
);
298 for (d
= 0;; d
+= sizeof(int32_t)) {
302 if (PA_UNLIKELY(d
>= length
))
305 for (i
= 0; i
< nstreams
; i
++) {
306 pa_mix_info
*m
= streams
+ i
;
308 int32_t cv
= m
->linear
[channel
].i
;
310 if (PA_UNLIKELY(d
>= m
->chunk
.length
))
313 if (PA_UNLIKELY(cv
<= 0) || PA_UNLIKELY(!!mute
) || PA_UNLIKELY(linear
[channel
] <= 0))
316 v
= *((int32_t*) m
->ptr
);
317 v
= (v
* cv
) / 0x10000;
321 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(int32_t);
324 sum
= PA_CLAMP_UNLIKELY(sum
, -0x80000000LL
, 0x7FFFFFFFLL
);
325 sum
= (sum
* linear
[channel
]) / 0x10000;
326 *((int32_t*) data
) = (int32_t) sum
;
328 data
= (uint8_t*) data
+ sizeof(int32_t);
330 if (PA_UNLIKELY(++channel
>= spec
->channels
))
337 case PA_SAMPLE_S32RE
:{
338 unsigned channel
= 0;
339 int32_t linear
[PA_CHANNELS_MAX
];
341 calc_linear_integer_stream_volumes(streams
, nstreams
, spec
);
342 calc_linear_integer_volume(linear
, volume
);
344 for (d
= 0;; d
+= sizeof(int32_t)) {
348 if (PA_UNLIKELY(d
>= length
))
351 for (i
= 0; i
< nstreams
; i
++) {
352 pa_mix_info
*m
= streams
+ i
;
354 int32_t cv
= m
->linear
[channel
].i
;
356 if (PA_UNLIKELY(d
>= m
->chunk
.length
))
359 if (PA_UNLIKELY(cv
<= 0) || PA_UNLIKELY(!!mute
) || PA_UNLIKELY(linear
[channel
] <= 0))
362 v
= PA_INT32_SWAP(*((int32_t*) m
->ptr
));
363 v
= (v
* cv
) / 0x10000;
367 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(int32_t);
370 sum
= PA_CLAMP_UNLIKELY(sum
, -0x80000000LL
, 0x7FFFFFFFLL
);
371 sum
= (sum
* linear
[channel
]) / 0x10000;
372 *((int32_t*) data
) = PA_INT32_SWAP((int32_t) sum
);
374 data
= (uint8_t*) data
+ sizeof(int32_t);
376 if (PA_UNLIKELY(++channel
>= spec
->channels
))
384 unsigned channel
= 0;
385 int32_t linear
[PA_CHANNELS_MAX
];
387 calc_linear_integer_stream_volumes(streams
, nstreams
, spec
);
388 calc_linear_integer_volume(linear
, volume
);
394 if (PA_UNLIKELY(d
>= length
))
397 for (i
= 0; i
< nstreams
; i
++) {
398 pa_mix_info
*m
= streams
+ i
;
399 int32_t v
, cv
= m
->linear
[channel
].i
;
401 if (PA_UNLIKELY(d
>= m
->chunk
.length
))
404 if (PA_UNLIKELY(cv
<= 0) || PA_UNLIKELY(!!mute
) || PA_UNLIKELY(linear
[channel
] <= 0))
407 v
= (int32_t) *((uint8_t*) m
->ptr
) - 0x80;
408 v
= (v
* cv
) / 0x10000;
412 m
->ptr
= (uint8_t*) m
->ptr
+ 1;
415 sum
= (sum
* linear
[channel
]) / 0x10000;
416 sum
= PA_CLAMP_UNLIKELY(sum
, -0x80, 0x7F);
417 *((uint8_t*) data
) = (uint8_t) (sum
+ 0x80);
419 data
= (uint8_t*) data
+ 1;
421 if (PA_UNLIKELY(++channel
>= spec
->channels
))
428 case PA_SAMPLE_ULAW
: {
429 unsigned channel
= 0;
430 int32_t linear
[PA_CHANNELS_MAX
];
432 calc_linear_integer_stream_volumes(streams
, nstreams
, spec
);
433 calc_linear_integer_volume(linear
, volume
);
439 if (PA_UNLIKELY(d
>= length
))
442 for (i
= 0; i
< nstreams
; i
++) {
443 pa_mix_info
*m
= streams
+ i
;
444 int32_t v
, cv
= m
->linear
[channel
].i
;
446 if (PA_UNLIKELY(d
>= m
->chunk
.length
))
449 if (PA_UNLIKELY(cv
<= 0) || PA_UNLIKELY(!!mute
) || PA_UNLIKELY(linear
[channel
] <= 0))
452 v
= (int32_t) st_ulaw2linear16(*((uint8_t*) m
->ptr
));
453 v
= (v
* cv
) / 0x10000;
457 m
->ptr
= (uint8_t*) m
->ptr
+ 1;
460 sum
= PA_CLAMP_UNLIKELY(sum
, -0x8000, 0x7FFF);
461 sum
= (sum
* linear
[channel
]) / 0x10000;
462 *((uint8_t*) data
) = (uint8_t) st_14linear2ulaw(sum
>> 2);
464 data
= (uint8_t*) data
+ 1;
466 if (PA_UNLIKELY(++channel
>= spec
->channels
))
473 case PA_SAMPLE_ALAW
: {
474 unsigned channel
= 0;
475 int32_t linear
[PA_CHANNELS_MAX
];
477 calc_linear_integer_stream_volumes(streams
, nstreams
, spec
);
478 calc_linear_integer_volume(linear
, volume
);
484 if (PA_UNLIKELY(d
>= length
))
487 for (i
= 0; i
< nstreams
; i
++) {
488 pa_mix_info
*m
= streams
+ i
;
489 int32_t v
, cv
= m
->linear
[channel
].i
;
491 if (PA_UNLIKELY(d
>= m
->chunk
.length
))
494 if (PA_UNLIKELY(cv
<= 0) || PA_UNLIKELY(!!mute
) || PA_UNLIKELY(linear
[channel
] <= 0))
497 v
= (int32_t) st_alaw2linear16(*((uint8_t*) m
->ptr
));
498 v
= (v
* cv
) / 0x10000;
502 m
->ptr
= (uint8_t*) m
->ptr
+ 1;
505 sum
= PA_CLAMP_UNLIKELY(sum
, -0x8000, 0x7FFF);
506 sum
= (sum
* linear
[channel
]) / 0x10000;
507 *((uint8_t*) data
) = (uint8_t) st_13linear2alaw(sum
>> 3);
509 data
= (uint8_t*) data
+ 1;
511 if (PA_UNLIKELY(++channel
>= spec
->channels
))
518 case PA_SAMPLE_FLOAT32NE
: {
519 unsigned channel
= 0;
520 float linear
[PA_CHANNELS_MAX
];
522 calc_linear_float_stream_volumes(streams
, nstreams
, spec
);
523 calc_linear_float_volume(linear
, volume
);
525 for (d
= 0;; d
+= sizeof(float)) {
529 if (PA_UNLIKELY(d
>= length
))
532 for (i
= 0; i
< nstreams
; i
++) {
533 pa_mix_info
*m
= streams
+ i
;
534 float v
, cv
= m
->linear
[channel
].f
;
536 if (PA_UNLIKELY(d
>= m
->chunk
.length
))
539 if (PA_UNLIKELY(cv
<= 0) || PA_UNLIKELY(!!mute
) || PA_UNLIKELY(linear
[channel
] <= 0))
542 v
= *((float*) m
->ptr
);
547 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(float);
550 sum
*= linear
[channel
];
551 *((float*) data
) = sum
;
553 data
= (uint8_t*) data
+ sizeof(float);
555 if (PA_UNLIKELY(++channel
>= spec
->channels
))
562 case PA_SAMPLE_FLOAT32RE
: {
563 unsigned channel
= 0;
564 float linear
[PA_CHANNELS_MAX
];
566 calc_linear_float_stream_volumes(streams
, nstreams
, spec
);
567 calc_linear_float_volume(linear
, volume
);
569 for (d
= 0;; d
+= sizeof(float)) {
573 if (PA_UNLIKELY(d
>= length
))
576 for (i
= 0; i
< nstreams
; i
++) {
577 pa_mix_info
*m
= streams
+ i
;
578 float v
, cv
= m
->linear
[channel
].f
;
580 if (PA_UNLIKELY(d
>= m
->chunk
.length
))
583 if (PA_UNLIKELY(cv
<= 0) || PA_UNLIKELY(!!mute
) || PA_UNLIKELY(linear
[channel
] <= 0))
586 uint32_t z
= *(uint32_t*) m
->ptr
;
587 z
= PA_UINT32_SWAP(z
);
593 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(float);
596 sum
*= linear
[channel
];
597 *((uint32_t*) data
) = PA_UINT32_SWAP(*(uint32_t*) &sum
);
599 data
= (uint8_t*) data
+ sizeof(float);
601 if (PA_UNLIKELY(++channel
>= spec
->channels
))
609 pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec
->format
));
610 pa_assert_not_reached();
615 for (k
= 0; k
< nstreams
; k
++)
616 pa_memblock_release(streams
[k
].chunk
.memblock
);
622 void pa_volume_memchunk(
624 const pa_sample_spec
*spec
,
625 const pa_cvolume
*volume
) {
631 pa_assert(c
->length
% pa_frame_size(spec
) == 0);
634 if (pa_memblock_is_silence(c
->memblock
))
637 if (pa_cvolume_channels_equal_to(volume
, PA_VOLUME_NORM
))
640 if (pa_cvolume_channels_equal_to(volume
, PA_VOLUME_MUTED
)) {
641 pa_silence_memchunk(c
, spec
);
645 ptr
= (uint8_t*) pa_memblock_acquire(c
->memblock
) + c
->index
;
647 switch (spec
->format
) {
649 case PA_SAMPLE_S16NE
: {
653 int32_t linear
[PA_CHANNELS_MAX
];
655 calc_linear_integer_volume(linear
, volume
);
657 for (channel
= 0, d
= ptr
, n
= c
->length
/sizeof(int16_t); n
> 0; d
++, n
--) {
661 t
= (t
* linear
[channel
]) / 0x10000;
662 t
= PA_CLAMP_UNLIKELY(t
, -0x8000, 0x7FFF);
665 if (PA_UNLIKELY(++channel
>= spec
->channels
))
671 case PA_SAMPLE_S16RE
: {
675 int32_t linear
[PA_CHANNELS_MAX
];
677 calc_linear_integer_volume(linear
, volume
);
679 for (channel
= 0, d
= ptr
, n
= c
->length
/sizeof(int16_t); n
> 0; d
++, n
--) {
682 t
= (int32_t)(PA_INT16_SWAP(*d
));
683 t
= (t
* linear
[channel
]) / 0x10000;
684 t
= PA_CLAMP_UNLIKELY(t
, -0x8000, 0x7FFF);
685 *d
= PA_INT16_SWAP((int16_t) t
);
687 if (PA_UNLIKELY(++channel
>= spec
->channels
))
694 case PA_SAMPLE_S32NE
: {
698 int32_t linear
[PA_CHANNELS_MAX
];
700 calc_linear_integer_volume(linear
, volume
);
702 for (channel
= 0, d
= ptr
, n
= c
->length
/sizeof(int32_t); n
> 0; d
++, n
--) {
706 t
= (t
* linear
[channel
]) / 0x10000;
707 t
= PA_CLAMP_UNLIKELY(t
, -0x80000000LL
, 0x7FFFFFFFLL
);
710 if (PA_UNLIKELY(++channel
>= spec
->channels
))
716 case PA_SAMPLE_S32RE
: {
720 int32_t linear
[PA_CHANNELS_MAX
];
722 calc_linear_integer_volume(linear
, volume
);
724 for (channel
= 0, d
= ptr
, n
= c
->length
/sizeof(int32_t); n
> 0; d
++, n
--) {
727 t
= (int64_t)(PA_INT32_SWAP(*d
));
728 t
= (t
* linear
[channel
]) / 0x10000;
729 t
= PA_CLAMP_UNLIKELY(t
, -0x80000000LL
, 0x7FFFFFFFLL
);
730 *d
= PA_INT32_SWAP((int32_t) t
);
732 if (PA_UNLIKELY(++channel
>= spec
->channels
))
743 int32_t linear
[PA_CHANNELS_MAX
];
745 calc_linear_integer_volume(linear
, volume
);
747 for (channel
= 0, d
= ptr
, n
= c
->length
; n
> 0; d
++, n
--) {
750 t
= (int32_t) *d
- 0x80;
751 t
= (t
* linear
[channel
]) / 0x10000;
752 t
= PA_CLAMP_UNLIKELY(t
, -0x80, 0x7F);
753 *d
= (uint8_t) (t
+ 0x80);
755 if (PA_UNLIKELY(++channel
>= spec
->channels
))
761 case PA_SAMPLE_ULAW
: {
765 int32_t linear
[PA_CHANNELS_MAX
];
767 calc_linear_integer_volume(linear
, volume
);
769 for (channel
= 0, d
= ptr
, n
= c
->length
; n
> 0; d
++, n
--) {
772 t
= (int32_t) st_ulaw2linear16(*d
);
773 t
= (t
* linear
[channel
]) / 0x10000;
774 t
= PA_CLAMP_UNLIKELY(t
, -0x8000, 0x7FFF);
775 *d
= (uint8_t) st_14linear2ulaw(t
>> 2);
777 if (PA_UNLIKELY(++channel
>= spec
->channels
))
783 case PA_SAMPLE_ALAW
: {
787 int32_t linear
[PA_CHANNELS_MAX
];
789 calc_linear_integer_volume(linear
, volume
);
791 for (channel
= 0, d
= ptr
, n
= c
->length
; n
> 0; d
++, n
--) {
794 t
= (int32_t) st_alaw2linear16(*d
);
795 t
= (t
* linear
[channel
]) / 0x10000;
796 t
= PA_CLAMP_UNLIKELY(t
, -0x8000, 0x7FFF);
797 *d
= (uint8_t) st_13linear2alaw(t
>> 3);
799 if (PA_UNLIKELY(++channel
>= spec
->channels
))
805 case PA_SAMPLE_FLOAT32NE
: {
812 skip
= spec
->channels
* sizeof(float);
813 n
= c
->length
/sizeof(float)/spec
->channels
;
815 for (channel
= 0; channel
< spec
->channels
; channel
++) {
818 if (PA_UNLIKELY(volume
->values
[channel
] == PA_VOLUME_NORM
))
821 v
= (float) pa_sw_volume_to_linear(volume
->values
[channel
]);
823 oil_scalarmult_f32(t
, skip
, t
, skip
, &v
, n
);
828 case PA_SAMPLE_FLOAT32RE
: {
832 float linear
[PA_CHANNELS_MAX
];
834 calc_linear_float_volume(linear
, volume
);
836 for (channel
= 0, d
= ptr
, n
= c
->length
/sizeof(float); n
> 0; d
++, n
--) {
840 z
= PA_UINT32_SWAP(*d
);
842 t
*= linear
[channel
];
844 *d
= PA_UINT32_SWAP(z
);
846 if (PA_UNLIKELY(++channel
>= spec
->channels
))
855 pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec
->format
));
856 /* If we cannot change the volume, we just don't do it */
859 pa_memblock_release(c
->memblock
);
862 size_t pa_frame_align(size_t l
, const pa_sample_spec
*ss
) {
867 fs
= pa_frame_size(ss
);
872 int pa_frame_aligned(size_t l
, const pa_sample_spec
*ss
) {
877 fs
= pa_frame_size(ss
);
882 void pa_interleave(const void *src
[], unsigned channels
, void *dst
, size_t ss
, unsigned n
) {
887 pa_assert(channels
> 0);
894 for (c
= 0; c
< channels
; c
++) {
900 d
= (uint8_t*) dst
+ c
* ss
;
902 for (j
= 0; j
< n
; j
++) {
903 oil_memcpy(d
, s
, ss
);
904 s
= (uint8_t*) s
+ ss
;
905 d
= (uint8_t*) d
+ fs
;
910 void pa_deinterleave(const void *src
, void *dst
[], unsigned channels
, size_t ss
, unsigned n
) {
916 pa_assert(channels
> 0);
922 for (c
= 0; c
< channels
; c
++) {
927 s
= (uint8_t*) src
+ c
* ss
;
930 for (j
= 0; j
< n
; j
++) {
931 oil_memcpy(d
, s
, ss
);
932 s
= (uint8_t*) s
+ fs
;
933 d
= (uint8_t*) d
+ ss
;