1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2018 Intel Corporation. All rights reserved.
4 //
5 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6 //         Keyon Jie <yang.jie@linux.intel.com>
7 //         Tomasz Lauda <tomasz.lauda@linux.intel.com>
8 
9 /**
10  * \file
11  * \brief Volume generic processing implementation
12  * \authors Liam Girdwood <liam.r.girdwood@linux.intel.com>\n
13  *          Keyon Jie <yang.jie@linux.intel.com>\n
14  *          Tomasz Lauda <tomasz.lauda@linux.intel.com>
15  */
16 
17 #include <sof/audio/volume.h>
18 
19 #ifdef CONFIG_GENERIC
20 
21 #include <sof/audio/buffer.h>
22 #include <sof/audio/component.h>
23 #include <sof/audio/format.h>
24 #include <sof/common.h>
25 #include <ipc/stream.h>
26 #include <stddef.h>
27 #include <stdint.h>
28 
29 #if CONFIG_FORMAT_S24LE
30 /**
31  * \brief Volume s24 to s24 multiply function
32  * \param[in] x   input sample.
33  * \param[in] vol gain.
34  * \return output sample.
35  *
36  * Volume multiply for 24 bit input and 24 bit bit output.
37  */
vol_mult_s24_to_s24(int32_t x,int32_t vol)38 static inline int32_t vol_mult_s24_to_s24(int32_t x, int32_t vol)
39 {
40 	return q_multsr_sat_32x32_24(sign_extend_s24(x), vol,
41 				     Q_SHIFT_BITS_64(23, 16, 23));
42 }
43 
44 /**
45  * \brief Volume processing from 24/32 bit to 24/32 bit.
46  * \param[in,out] dev Volume base component device.
47  * \param[in,out] sink Destination buffer.
48  * \param[in,out] source Source buffer.
49  * \param[in] frames Number of frames to process.
50  *
51  * Copy and scale volume from 24/32 bit source buffer
52  * to 24/32 bit destination buffer.
53  */
vol_s24_to_s24(struct comp_dev * dev,struct audio_stream * sink,const struct audio_stream * source,uint32_t frames)54 static void vol_s24_to_s24(struct comp_dev *dev, struct audio_stream *sink,
55 			   const struct audio_stream *source, uint32_t frames)
56 {
57 	struct vol_data *cd = comp_get_drvdata(dev);
58 	int32_t *src;
59 	int32_t *dest;
60 	int32_t i;
61 	uint32_t channel;
62 	uint32_t buff_frag = 0;
63 
64 	/* Samples are Q1.23 --> Q1.23 and volume is Q8.16 */
65 	for (i = 0; i < frames; i++) {
66 		for (channel = 0; channel < sink->channels; channel++) {
67 			src = audio_stream_read_frag_s32(source, buff_frag);
68 			dest = audio_stream_write_frag_s32(sink, buff_frag);
69 
70 			*dest = vol_mult_s24_to_s24(*src, cd->volume[channel]);
71 
72 			buff_frag++;
73 		}
74 	}
75 }
76 #endif /* CONFIG_FORMAT_S24LE */
77 
78 #if CONFIG_FORMAT_S32LE
79 /**
80  * \brief Volume processing from 32 bit to 32 bit.
81  * \param[in,out] dev Volume base component device.
82  * \param[in,out] sink Destination buffer.
83  * \param[in,out] source Source buffer.
84  * \param[in] frames Number of frames to process.
85  *
86  * Copy and scale volume from 32 bit source buffer
87  * to 32 bit destination buffer.
88  */
vol_s32_to_s32(struct comp_dev * dev,struct audio_stream * sink,const struct audio_stream * source,uint32_t frames)89 static void vol_s32_to_s32(struct comp_dev *dev, struct audio_stream *sink,
90 			   const struct audio_stream *source, uint32_t frames)
91 {
92 	struct vol_data *cd = comp_get_drvdata(dev);
93 	int32_t *src;
94 	int32_t *dest;
95 	int32_t i;
96 	uint32_t channel;
97 	uint32_t buff_frag = 0;
98 
99 	/* Samples are Q1.31 --> Q1.31 and volume is Q8.16 */
100 	for (i = 0; i < frames; i++) {
101 		for (channel = 0; channel < sink->channels; channel++) {
102 			src = audio_stream_read_frag_s32(source, buff_frag);
103 			dest = audio_stream_write_frag_s32(sink, buff_frag);
104 
105 			*dest = q_multsr_sat_32x32
106 				(*src, cd->volume[channel],
107 				 Q_SHIFT_BITS_64(31, 16, 31));
108 
109 			buff_frag++;
110 		}
111 	}
112 }
113 #endif /* CONFIG_FORMAT_S32LE */
114 
115 #if CONFIG_FORMAT_S16LE
116 /**
117  * \brief Volume processing from 16 bit to 16 bit.
118  * \param[in,out] dev Volume base component device.
119  * \param[in,out] sink Destination buffer.
120  * \param[in,out] source Source buffer.
121  * \param[in] frames Number of frames to process.
122  *
123  * Copy and scale volume from 16 bit source buffer
124  * to 16 bit destination buffer.
125  */
vol_s16_to_s16(struct comp_dev * dev,struct audio_stream * sink,const struct audio_stream * source,uint32_t frames)126 static void vol_s16_to_s16(struct comp_dev *dev, struct audio_stream *sink,
127 			   const struct audio_stream *source, uint32_t frames)
128 {
129 	struct vol_data *cd = comp_get_drvdata(dev);
130 	int16_t *src;
131 	int16_t *dest;
132 	int32_t i;
133 	uint32_t channel;
134 	uint32_t buff_frag = 0;
135 
136 	/* Samples are Q1.15 --> Q1.15 and volume is Q8.16 */
137 	for (i = 0; i < frames; i++) {
138 		for (channel = 0; channel < sink->channels; channel++) {
139 			src = audio_stream_read_frag_s16(source, buff_frag);
140 			dest = audio_stream_write_frag_s16(sink, buff_frag);
141 
142 			*dest = q_multsr_sat_32x32_16
143 				(*src, cd->volume[channel],
144 				 Q_SHIFT_BITS_32(15, 16, 15));
145 
146 			buff_frag++;
147 		}
148 	}
149 }
150 #endif /* CONFIG_FORMAT_S16LE */
151 
152 const struct comp_func_map func_map[] = {
153 #if CONFIG_FORMAT_S16LE
154 	{ SOF_IPC_FRAME_S16_LE, vol_s16_to_s16 },
155 #endif /* CONFIG_FORMAT_S16LE */
156 #if CONFIG_FORMAT_S24LE
157 	{ SOF_IPC_FRAME_S24_4LE, vol_s24_to_s24 },
158 #endif /* CONFIG_FORMAT_S24LE */
159 #if CONFIG_FORMAT_S32LE
160 	{ SOF_IPC_FRAME_S32_LE, vol_s32_to_s32 },
161 #endif /* CONFIG_FORMAT_S32LE */
162 };
163 
164 const size_t func_count = ARRAY_SIZE(func_map);
165 
166 #endif
167