1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2020 Intel Corporation. All rights reserved.
4 //
5 // Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com>
6 
7 /**
8  * \file audio/pcm_converter/pcm_converter.c
9  * \brief PCM converter common functions
10  * \authors Karol Trzcinski <karolx.trzcinski@linux.intel.com>
11  */
12 
13 #include <sof/audio/audio_stream.h>
14 #include <sof/audio/pcm_converter.h>
15 #include <sof/debug/panic.h>
16 
pcm_convert_as_linear(const struct audio_stream * source,uint32_t ioffset,struct audio_stream * sink,uint32_t ooffset,uint32_t samples,pcm_converter_lin_func converter)17 int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset,
18 			  struct audio_stream *sink, uint32_t ooffset,
19 			  uint32_t samples, pcm_converter_lin_func converter)
20 {
21 	const int s_size_in = audio_stream_sample_bytes(source);
22 	const int s_size_out = audio_stream_sample_bytes(sink);
23 	const int log2_s_size_in = ffs(s_size_in) - 1;
24 	const int log2_s_size_out = ffs(s_size_out) - 1;
25 	char *r_ptr = audio_stream_get_frag(source, source->r_ptr, ioffset,
26 					    s_size_in);
27 	char *w_ptr = audio_stream_get_frag(sink, sink->w_ptr, ooffset,
28 					    s_size_out);
29 	int i = 0;
30 	int chunk;
31 	int N1, N2;
32 
33 	/* assert enough avail/free samples in source and sink buffer */
34 	if (audio_stream_get_avail_samples(source) < samples + ioffset)
35 		return -EINVAL;
36 	if (audio_stream_get_free_samples(sink) < samples + ooffset)
37 		return -EINVAL;
38 
39 	while (i < samples) {
40 		/* calculate chunk size */
41 		/* "">> log2_s_size" is equal "/ s_size" here */
42 		N1 = audio_stream_bytes_without_wrap(source, r_ptr) >>
43 			log2_s_size_in;
44 		N2 = audio_stream_bytes_without_wrap(sink, w_ptr) >>
45 			log2_s_size_out;
46 		chunk = MIN(N1, N2);
47 		chunk = MIN(chunk, samples - i);
48 
49 		/* run conversion on linear memory region */
50 		converter(r_ptr, w_ptr, chunk);
51 
52 		/* move pointers */
53 		r_ptr = audio_stream_wrap(source, r_ptr + chunk * s_size_in);
54 		w_ptr = audio_stream_wrap(sink, w_ptr + chunk * s_size_out);
55 		i += chunk;
56 	}
57 
58 	return samples;
59 }
60