1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the people's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 
33 #include "pcm_local.h"
34 
snd_pcm_format_signed(snd_pcm_format_t format)35 int snd_pcm_format_signed(snd_pcm_format_t format)
36 {
37     switch (format) {
38     case SND_PCM_FORMAT_S8:
39     case SND_PCM_FORMAT_S16_LE:
40     case SND_PCM_FORMAT_S16_BE:
41     case SND_PCM_FORMAT_S24_LE:
42     case SND_PCM_FORMAT_S24_BE:
43     case SND_PCM_FORMAT_S32_LE:
44     case SND_PCM_FORMAT_S32_BE:
45         return 1;
46     case SND_PCM_FORMAT_U8:
47     case SND_PCM_FORMAT_U16_LE:
48     case SND_PCM_FORMAT_U16_BE:
49     case SND_PCM_FORMAT_U24_LE:
50     case SND_PCM_FORMAT_U24_BE:
51     case SND_PCM_FORMAT_U32_LE:
52     case SND_PCM_FORMAT_U32_BE:
53         return 0;
54     default:
55         return -EINVAL;
56     }
57 }
58 
snd_pcm_format_unsigned(snd_pcm_format_t format)59 int snd_pcm_format_unsigned(snd_pcm_format_t format)
60 {
61     int val;
62 
63     val = snd_pcm_format_signed(format);
64     if (val < 0)
65         return val;
66     return !val;
67 }
68 
snd_pcm_format_linear(snd_pcm_format_t format)69 int snd_pcm_format_linear(snd_pcm_format_t format)
70 {
71     return snd_pcm_format_signed(format) >= 0;
72 }
73 
snd_pcm_format_little_endian(snd_pcm_format_t format)74 int snd_pcm_format_little_endian(snd_pcm_format_t format)
75 {
76     switch (format) {
77     case SND_PCM_FORMAT_S16_LE:
78     case SND_PCM_FORMAT_U16_LE:
79     case SND_PCM_FORMAT_S24_LE:
80     case SND_PCM_FORMAT_U24_LE:
81     case SND_PCM_FORMAT_S32_LE:
82     case SND_PCM_FORMAT_U32_LE:
83         return 1;
84     case SND_PCM_FORMAT_S16_BE:
85     case SND_PCM_FORMAT_U16_BE:
86     case SND_PCM_FORMAT_S24_BE:
87     case SND_PCM_FORMAT_U24_BE:
88     case SND_PCM_FORMAT_S32_BE:
89     case SND_PCM_FORMAT_U32_BE:
90         return 0;
91     default:
92         return -EINVAL;
93     }
94 }
95 
snd_pcm_format_big_endian(snd_pcm_format_t format)96 int snd_pcm_format_big_endian(snd_pcm_format_t format)
97 {
98     int val;
99 
100     val = snd_pcm_format_little_endian(format);
101     if (val < 0)
102         return val;
103     return !val;
104 }
105 
snd_pcm_format_width(snd_pcm_format_t format)106 int snd_pcm_format_width(snd_pcm_format_t format)
107 {
108     switch (format) {
109     case SND_PCM_FORMAT_S8:
110     case SND_PCM_FORMAT_U8:
111         return 8;
112     case SND_PCM_FORMAT_S16_LE:
113     case SND_PCM_FORMAT_S16_BE:
114     case SND_PCM_FORMAT_U16_LE:
115     case SND_PCM_FORMAT_U16_BE:
116         return 16;
117     case SND_PCM_FORMAT_S24_LE:
118     case SND_PCM_FORMAT_S24_BE:
119     case SND_PCM_FORMAT_U24_LE:
120     case SND_PCM_FORMAT_U24_BE:
121         return 24;
122     case SND_PCM_FORMAT_S32_LE:
123     case SND_PCM_FORMAT_S32_BE:
124     case SND_PCM_FORMAT_U32_LE:
125     case SND_PCM_FORMAT_U32_BE:
126         return 32;
127     default:
128         return -EINVAL;
129     }
130 }
131 
132 static const int linear_formats[4][2][2] = {
133     { { SND_PCM_FORMAT_S8, SND_PCM_FORMAT_S8 },
134       { SND_PCM_FORMAT_U8, SND_PCM_FORMAT_U8 } },
135     { { SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE },
136       { SND_PCM_FORMAT_U16_LE, SND_PCM_FORMAT_U16_BE } },
137     { { SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_BE },
138       { SND_PCM_FORMAT_U24_LE, SND_PCM_FORMAT_U24_BE } },
139     { { SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_BE },
140       { SND_PCM_FORMAT_U32_LE, SND_PCM_FORMAT_U32_BE } }
141 };
142 
143 /**
144  * \brief Compose a PCM sample linear format
145  * \param width Nominal bits per sample
146  * \param pwidth Physical bit width of the format
147  * \param unsignd Sign: 0 signed, 1 unsigned
148  * \param big_endian Endian: 0 little endian, 1 big endian
149  * \return The matching format type, or #SND_PCM_FORMAT_UNKNOWN if no match
150  */
snd_pcm_build_linear_format(int width,int pwidth,int unsignd,int big_endian)151 snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian)
152 {
153     if (pwidth == 24) {
154 #if 0
155         switch (width) {
156         case 24:
157             width = 0;
158             break;
159         case 20:
160             width = 1;
161             break;
162         case 18:
163             width = 2;
164             break;
165         default:
166             return SND_PCM_FORMAT_UNKNOWN;
167         }
168         return linear24_formats[width][!!unsignd][!!big_endian];
169 #else
170         return SND_PCM_FORMAT_UNKNOWN;
171 #endif
172     } else {
173         switch (width) {
174         case 8:
175             width = 0;
176             break;
177         case 16:
178             width = 1;
179             break;
180         case 24:
181             width = 2;
182             break;
183         case 32:
184             width = 3;
185             break;
186         default:
187             return SND_PCM_FORMAT_UNKNOWN;
188         }
189         return linear_formats[width][!!unsignd][!!big_endian];
190     }
191 }
192