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