xref: /netbsd/sys/dev/audio/linear.c (revision 007c1f91)
1*007c1f91Sskrll /*	$NetBSD: linear.c,v 1.4 2021/07/21 06:35:44 skrll Exp $	*/
2b950503fSisaki 
3b950503fSisaki /*
4b950503fSisaki  * Copyright (C) 2017 Tetsuya Isaki. All rights reserved.
5b950503fSisaki  * Copyright (C) 2017 Y.Sugahara (moveccr). All rights reserved.
6b950503fSisaki  *
7b950503fSisaki  * Redistribution and use in source and binary forms, with or without
8b950503fSisaki  * modification, are permitted provided that the following conditions
9b950503fSisaki  * are met:
10b950503fSisaki  * 1. Redistributions of source code must retain the above copyright
11b950503fSisaki  *    notice, this list of conditions and the following disclaimer.
12b950503fSisaki  * 2. Redistributions in binary form must reproduce the above copyright
13b950503fSisaki  *    notice, this list of conditions and the following disclaimer in the
14b950503fSisaki  *    documentation and/or other materials provided with the distribution.
15b950503fSisaki  *
16b950503fSisaki  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17b950503fSisaki  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18b950503fSisaki  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19b950503fSisaki  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20b950503fSisaki  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21b950503fSisaki  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22b950503fSisaki  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23b950503fSisaki  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24b950503fSisaki  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25b950503fSisaki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26b950503fSisaki  * SUCH DAMAGE.
27b950503fSisaki  */
28b950503fSisaki 
29b950503fSisaki #include <sys/cdefs.h>
30*007c1f91Sskrll __KERNEL_RCSID(0, "$NetBSD: linear.c,v 1.4 2021/07/21 06:35:44 skrll Exp $");
31b950503fSisaki 
32*007c1f91Sskrll #include <sys/param.h>
33b950503fSisaki #include <sys/types.h>
34b950503fSisaki #include <sys/systm.h>
35b950503fSisaki #include <sys/device.h>
36b950503fSisaki #include <dev/audio/audiovar.h>
37b950503fSisaki #include <dev/audio/linear.h>
38b950503fSisaki 
39b950503fSisaki /*
40b950503fSisaki  * audio_linear8_to_internal:
41b950503fSisaki  *	This filter performs conversion from [US]LINEAR8 to internal format.
42b950503fSisaki  */
43b950503fSisaki void
audio_linear8_to_internal(audio_filter_arg_t * arg)44b950503fSisaki audio_linear8_to_internal(audio_filter_arg_t *arg)
45b950503fSisaki {
46b950503fSisaki 	const uint8_t *s;
47b950503fSisaki 	aint_t *d;
48b950503fSisaki 	uint8_t xor;
49b950503fSisaki 	u_int sample_count;
50b950503fSisaki 	u_int i;
51b950503fSisaki 
52b950503fSisaki 	DIAGNOSTIC_filter_arg(arg);
53b950503fSisaki 	KASSERT(audio_format2_is_linear(arg->srcfmt));
54b950503fSisaki 	KASSERT(arg->srcfmt->precision == 8);
55b950503fSisaki 	KASSERT(arg->srcfmt->stride == 8);
56b950503fSisaki 	KASSERT(audio_format2_is_internal(arg->dstfmt));
57b950503fSisaki 	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
58b950503fSisaki 
59b950503fSisaki 	s = arg->src;
60b950503fSisaki 	d = arg->dst;
61b950503fSisaki 	sample_count = arg->count * arg->srcfmt->channels;
62b950503fSisaki 	xor = audio_format2_is_signed(arg->srcfmt) ? 0 : 0x80;
63b950503fSisaki 
64b950503fSisaki 	for (i = 0; i < sample_count; i++) {
65b950503fSisaki 		uint8_t val;
66b950503fSisaki 		val = *s++;
67b950503fSisaki 		val ^= xor;
68b950503fSisaki 		*d++ = (auint_t)val << (AUDIO_INTERNAL_BITS - 8);
69b950503fSisaki 	}
70b950503fSisaki }
71b950503fSisaki 
72b950503fSisaki /*
73b950503fSisaki  * audio_internal_to_linear8:
74b950503fSisaki  *	This filter performs conversion from internal format to [US]LINEAR8.
75b950503fSisaki  */
76b950503fSisaki void
audio_internal_to_linear8(audio_filter_arg_t * arg)77b950503fSisaki audio_internal_to_linear8(audio_filter_arg_t *arg)
78b950503fSisaki {
79b950503fSisaki 	const aint_t *s;
80b950503fSisaki 	uint8_t *d;
81b950503fSisaki 	uint8_t xor;
82b950503fSisaki 	u_int sample_count;
83b950503fSisaki 	u_int i;
84b950503fSisaki 
85b950503fSisaki 	DIAGNOSTIC_filter_arg(arg);
86b950503fSisaki 	KASSERT(audio_format2_is_linear(arg->dstfmt));
87b950503fSisaki 	KASSERT(arg->dstfmt->precision == 8);
88b950503fSisaki 	KASSERT(arg->dstfmt->stride == 8);
89b950503fSisaki 	KASSERT(audio_format2_is_internal(arg->srcfmt));
90b950503fSisaki 	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
91b950503fSisaki 
92b950503fSisaki 	s = arg->src;
93b950503fSisaki 	d = arg->dst;
94b950503fSisaki 	sample_count = arg->count * arg->srcfmt->channels;
95b950503fSisaki 	xor = audio_format2_is_signed(arg->dstfmt) ? 0 : 0x80;
96b950503fSisaki 
97b950503fSisaki 	for (i = 0; i < sample_count; i++) {
98b950503fSisaki 		uint8_t val;
99b950503fSisaki 		val = (*s++) >> (AUDIO_INTERNAL_BITS - 8);
100b950503fSisaki 		val ^= xor;
101b950503fSisaki 		*d++ = val;
102b950503fSisaki 	}
103b950503fSisaki }
104b950503fSisaki 
105b950503fSisaki /*
106b950503fSisaki  * audio_linear16_to_internal:
107b950503fSisaki  *	This filter performs conversion from [US]LINEAR16{LE,BE} to internal
108b950503fSisaki  *	format.
109b950503fSisaki  */
110b950503fSisaki void
audio_linear16_to_internal(audio_filter_arg_t * arg)111b950503fSisaki audio_linear16_to_internal(audio_filter_arg_t *arg)
112b950503fSisaki {
113b950503fSisaki 	const uint16_t *s;
114b950503fSisaki 	aint_t *d;
115b950503fSisaki 	uint16_t xor;
116b950503fSisaki 	u_int sample_count;
117b950503fSisaki 	u_int shift;
118b950503fSisaki 	u_int i;
119b950503fSisaki 	bool is_src_NE;
120b950503fSisaki 
121b950503fSisaki 	DIAGNOSTIC_filter_arg(arg);
122b950503fSisaki 	KASSERT(audio_format2_is_linear(arg->srcfmt));
123b950503fSisaki 	KASSERT(arg->srcfmt->precision == 16);
124b950503fSisaki 	KASSERT(arg->srcfmt->stride == 16);
125b950503fSisaki 	KASSERT(audio_format2_is_internal(arg->dstfmt));
126b950503fSisaki 	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
127b950503fSisaki 
128b950503fSisaki 	s = arg->src;
129b950503fSisaki 	d = arg->dst;
130b950503fSisaki 	sample_count = arg->count * arg->srcfmt->channels;
131b950503fSisaki 
132b950503fSisaki 	shift = AUDIO_INTERNAL_BITS - 16;
133b950503fSisaki 	xor = audio_format2_is_signed(arg->srcfmt) ? 0 : 0x8000;
134b950503fSisaki 	is_src_NE = (audio_format2_endian(arg->srcfmt) == BYTE_ORDER);
135b950503fSisaki 
136b950503fSisaki 	/*
137b950503fSisaki 	 * Since slinear16_OppositeEndian to slinear_NativeEndian is used
138b950503fSisaki 	 * so much especially on big endian machines, so it's expanded.
139b950503fSisaki 	 * Other conversions are rarely used, so they are compressed.
140b950503fSisaki 	 */
141b950503fSisaki 	if (__predict_true(xor == 0) && is_src_NE == false) {
142b950503fSisaki 		/* slinear16_OE to slinear<AI>_NE */
143b950503fSisaki 		for (i = 0; i < sample_count; i++) {
144b950503fSisaki 			uint16_t val;
145b950503fSisaki 			val = *s++;
146b950503fSisaki 			val = bswap16(val);
147b950503fSisaki 			*d++ = (auint_t)val << shift;
148b950503fSisaki 		}
149b950503fSisaki 	} else {
150b950503fSisaki 		/* slinear16_NE      to slinear<AI>_NE */
151b950503fSisaki 		/* ulinear16_{NE,OE} to slinear<AI>_NE */
152b950503fSisaki 		for (i = 0; i < sample_count; i++) {
153b950503fSisaki 			uint16_t val;
154b950503fSisaki 			val = *s++;
155b950503fSisaki 			if (!is_src_NE)
156b950503fSisaki 				val = bswap16(val);
157b950503fSisaki 			val ^= xor;
158b950503fSisaki 			*d++ = (auint_t)val << shift;
159b950503fSisaki 		}
160b950503fSisaki 	}
161b950503fSisaki }
162b950503fSisaki 
163b950503fSisaki /*
164b950503fSisaki  * audio_internal_to_linear16:
165b950503fSisaki  *	This filter performs conversion from internal format to
166b950503fSisaki  *	[US]LINEAR16{LE,BE}.
167b950503fSisaki  */
168b950503fSisaki void
audio_internal_to_linear16(audio_filter_arg_t * arg)169b950503fSisaki audio_internal_to_linear16(audio_filter_arg_t *arg)
170b950503fSisaki {
171b950503fSisaki 	const aint_t *s;
172b950503fSisaki 	uint16_t *d;
173b950503fSisaki 	uint16_t xor;
174b950503fSisaki 	u_int sample_count;
175b950503fSisaki 	u_int shift;
176b950503fSisaki 	u_int i;
177b950503fSisaki 	bool is_dst_NE;
178b950503fSisaki 
179b950503fSisaki 	DIAGNOSTIC_filter_arg(arg);
180b950503fSisaki 	KASSERT(audio_format2_is_linear(arg->dstfmt));
181b950503fSisaki 	KASSERT(arg->dstfmt->precision == 16);
182b950503fSisaki 	KASSERT(arg->dstfmt->stride == 16);
183b950503fSisaki 	KASSERT(audio_format2_is_internal(arg->srcfmt));
184b950503fSisaki 	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
185b950503fSisaki 
186b950503fSisaki 	s = arg->src;
187b950503fSisaki 	d = arg->dst;
188b950503fSisaki 	sample_count = arg->count * arg->srcfmt->channels;
189b950503fSisaki 
190b950503fSisaki 	shift = AUDIO_INTERNAL_BITS - 16;
191b950503fSisaki 	xor = audio_format2_is_signed(arg->dstfmt) ? 0 : 0x8000;
192b950503fSisaki 	is_dst_NE = (audio_format2_endian(arg->dstfmt) == BYTE_ORDER);
193b950503fSisaki 
194b950503fSisaki 	/*
195b950503fSisaki 	 * Since slinear_NativeEndian to slinear16_OppositeEndian is used
196b950503fSisaki 	 * so much especially on big endian machines, so it's expanded.
197b950503fSisaki 	 * Other conversions are rarely used, so they are compressed.
198b950503fSisaki 	 */
199b950503fSisaki 	if (__predict_true(xor == 0) && is_dst_NE == false) {
200b950503fSisaki 		/* slinear<AI>_NE -> slinear16_OE */
201b950503fSisaki 		for (i = 0; i < sample_count; i++) {
202b950503fSisaki 			uint16_t val;
203b950503fSisaki 			val = (*s++) >> shift;
204b950503fSisaki 			val = bswap16(val);
205b950503fSisaki 			*d++ = val;
206b950503fSisaki 		}
207b950503fSisaki 	} else {
208b950503fSisaki 		/* slinear<AI>_NE -> slinear16_NE */
209b950503fSisaki 		/* slinear<AI>_NE -> ulinear16_{NE,OE} */
210b950503fSisaki 		for (i = 0; i < sample_count; i++) {
211b950503fSisaki 			uint16_t val;
212b950503fSisaki 			val = (*s++) >> shift;
213b950503fSisaki 			val ^= xor;
214b950503fSisaki 			if (!is_dst_NE)
215b950503fSisaki 				val = bswap16(val);
216b950503fSisaki 			*d++ = val;
217b950503fSisaki 		}
218b950503fSisaki 	}
219b950503fSisaki }
220b950503fSisaki 
221b950503fSisaki #if defined(AUDIO_SUPPORT_LINEAR24)
222b950503fSisaki /*
223b950503fSisaki  * audio_linear24_to_internal:
224b950503fSisaki  *	This filter performs conversion from [US]LINEAR24/24{LE,BE} to
225b950503fSisaki  *	internal format.  Since it's rerely used, it's size optimized.
226b950503fSisaki  */
227b950503fSisaki void
audio_linear24_to_internal(audio_filter_arg_t * arg)228b950503fSisaki audio_linear24_to_internal(audio_filter_arg_t *arg)
229b950503fSisaki {
230b950503fSisaki 	const uint8_t *s;
231b950503fSisaki 	aint_t *d;
232b950503fSisaki 	auint_t xor;
233b950503fSisaki 	u_int sample_count;
234b950503fSisaki 	u_int i;
235b950503fSisaki 	bool is_src_LE;
236b950503fSisaki 
237b950503fSisaki 	DIAGNOSTIC_filter_arg(arg);
238b950503fSisaki 	KASSERT(audio_format2_is_linear(arg->srcfmt));
239b950503fSisaki 	KASSERT(arg->srcfmt->precision == 24);
240b950503fSisaki 	KASSERT(arg->srcfmt->stride == 24);
241b950503fSisaki 	KASSERT(audio_format2_is_internal(arg->dstfmt));
242b950503fSisaki 	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
243b950503fSisaki 
244b950503fSisaki 	s = arg->src;
245b950503fSisaki 	d = arg->dst;
246b950503fSisaki 	sample_count = arg->count * arg->srcfmt->channels;
247b950503fSisaki 	xor = audio_format2_is_signed(arg->srcfmt)
248b950503fSisaki 	    ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
249b950503fSisaki 	is_src_LE = (audio_format2_endian(arg->srcfmt) == LITTLE_ENDIAN);
250b950503fSisaki 
251b950503fSisaki 	for (i = 0; i < sample_count; i++) {
252b950503fSisaki 		uint32_t val;
253b950503fSisaki 		if (is_src_LE) {
254b950503fSisaki 			val = s[0] | (s[1] << 8) | (s[2] << 16);
255b950503fSisaki 		} else {
256b950503fSisaki 			val = (s[0] << 16) | (s[1] << 8) | s[2];
257b950503fSisaki 		}
258b950503fSisaki 		s += 3;
259b950503fSisaki 
260b950503fSisaki #if AUDIO_INTERNAL_BITS < 24
261b950503fSisaki 		val >>= 24 - AUDIO_INTERNAL_BITS;
262b950503fSisaki #else
263b950503fSisaki 		val <<= AUDIO_INTERNAL_BITS - 24;
264b950503fSisaki #endif
265b950503fSisaki 		val ^= xor;
266b950503fSisaki 		*d++ = val;
267b950503fSisaki 	}
268b950503fSisaki }
269b950503fSisaki 
270b950503fSisaki /*
271b950503fSisaki  * audio_internal_to_linear24:
272b950503fSisaki  *	This filter performs conversion from internal format to
273b950503fSisaki  *	[US]LINEAR24/24{LE,BE}.  Since it's rarely used, it's size optimized.
274b950503fSisaki  */
275b950503fSisaki void
audio_internal_to_linear24(audio_filter_arg_t * arg)276b950503fSisaki audio_internal_to_linear24(audio_filter_arg_t *arg)
277b950503fSisaki {
278b950503fSisaki 	const aint_t *s;
279b950503fSisaki 	uint8_t *d;
280b950503fSisaki 	auint_t xor;
281b950503fSisaki 	u_int sample_count;
282b950503fSisaki 	u_int i;
283b950503fSisaki 	bool is_dst_LE;
284b950503fSisaki 
285b950503fSisaki 	DIAGNOSTIC_filter_arg(arg);
286b950503fSisaki 	KASSERT(audio_format2_is_linear(arg->dstfmt));
287b950503fSisaki 	KASSERT(arg->dstfmt->precision == 24);
288b950503fSisaki 	KASSERT(arg->dstfmt->stride == 24);
289b950503fSisaki 	KASSERT(audio_format2_is_internal(arg->srcfmt));
290b950503fSisaki 	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
291b950503fSisaki 
292b950503fSisaki 	s = arg->src;
293b950503fSisaki 	d = arg->dst;
294b950503fSisaki 	sample_count = arg->count * arg->srcfmt->channels;
295b950503fSisaki 	xor = audio_format2_is_signed(arg->dstfmt)
296b950503fSisaki 	    ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
297b950503fSisaki 	is_dst_LE = (audio_format2_endian(arg->dstfmt) == LITTLE_ENDIAN);
298b950503fSisaki 
299b950503fSisaki 	for (i = 0; i < sample_count; i++) {
300b950503fSisaki 		uint32_t val;
301b950503fSisaki 		val = *s++;
302b950503fSisaki 		val ^= xor;
303b950503fSisaki #if AUDIO_INTERNAL_BITS < 24
304b950503fSisaki 		val <<= 24 - AUDIO_INTERNAL_BITS;
305b950503fSisaki #else
306b950503fSisaki 		val >>= AUDIO_INTERNAL_BITS - 24;
307b950503fSisaki #endif
308b950503fSisaki 		if (is_dst_LE) {
309b950503fSisaki 			d[0] = val & 0xff;
310b950503fSisaki 			d[1] = (val >> 8) & 0xff;
311b950503fSisaki 			d[2] = (val >> 16) & 0xff;
312b950503fSisaki 		} else {
313b950503fSisaki 			d[0] = (val >> 16) & 0xff;
314b950503fSisaki 			d[1] = (val >> 8) & 0xff;
315b950503fSisaki 			d[2] = val & 0xff;
316b950503fSisaki 		}
317b950503fSisaki 		d += 3;
318b950503fSisaki 	}
319b950503fSisaki }
320b950503fSisaki #endif /* AUDIO_SUPPORT_LINEAR24 */
321b950503fSisaki 
322b950503fSisaki /*
323b950503fSisaki  * audio_linear32_to_internal:
324b950503fSisaki  *	This filter performs conversion from [US]LINEAR32{LE,BE} to internal
325b950503fSisaki  *	format.  Since it's rarely used, it's size optimized.
326b950503fSisaki  */
327b950503fSisaki void
audio_linear32_to_internal(audio_filter_arg_t * arg)328b950503fSisaki audio_linear32_to_internal(audio_filter_arg_t *arg)
329b950503fSisaki {
330b950503fSisaki 	const uint32_t *s;
331b950503fSisaki 	aint_t *d;
332b950503fSisaki 	auint_t xor;
333b950503fSisaki 	u_int sample_count;
334b950503fSisaki 	u_int i;
335b950503fSisaki 	bool is_src_NE;
336b950503fSisaki 
337b950503fSisaki 	DIAGNOSTIC_filter_arg(arg);
338b950503fSisaki 	KASSERT(audio_format2_is_linear(arg->srcfmt));
339b950503fSisaki 	KASSERT(arg->srcfmt->precision == 32);
340b950503fSisaki 	KASSERT(arg->srcfmt->stride == 32);
341b950503fSisaki 	KASSERT(audio_format2_is_internal(arg->dstfmt));
342b950503fSisaki 	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
343b950503fSisaki 
344b950503fSisaki 	s = arg->src;
345b950503fSisaki 	d = arg->dst;
346b950503fSisaki 	sample_count = arg->count * arg->srcfmt->channels;
347b950503fSisaki 	xor = audio_format2_is_signed(arg->srcfmt)
348b950503fSisaki 	    ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
349b950503fSisaki 	is_src_NE = (audio_format2_endian(arg->srcfmt) == BYTE_ORDER);
350b950503fSisaki 
351b950503fSisaki 	for (i = 0; i < sample_count; i++) {
352b950503fSisaki 		uint32_t val;
353b950503fSisaki 		val = *s++;
354b950503fSisaki 		if (!is_src_NE)
355b950503fSisaki 			val = bswap32(val);
356b950503fSisaki 		val >>= 32 - AUDIO_INTERNAL_BITS;
357b950503fSisaki 		val ^= xor;
358b950503fSisaki 		*d++ = val;
359b950503fSisaki 	}
360b950503fSisaki }
361b950503fSisaki 
362b950503fSisaki /*
363b950503fSisaki  * audio_internal_to_linear32:
364b950503fSisaki  *	This filter performs conversion from internal format to
365b950503fSisaki  *	[US]LINEAR32{LE,BE}.  Since it's rarely used, it's size optimized.
366b950503fSisaki  */
367b950503fSisaki void
audio_internal_to_linear32(audio_filter_arg_t * arg)368b950503fSisaki audio_internal_to_linear32(audio_filter_arg_t *arg)
369b950503fSisaki {
370b950503fSisaki 	const aint_t *s;
371b950503fSisaki 	uint32_t *d;
372b950503fSisaki 	auint_t xor;
373b950503fSisaki 	u_int sample_count;
374b950503fSisaki 	u_int i;
375b950503fSisaki 	bool is_dst_NE;
376b950503fSisaki 
377b950503fSisaki 	DIAGNOSTIC_filter_arg(arg);
378b950503fSisaki 	KASSERT(audio_format2_is_linear(arg->dstfmt));
379b950503fSisaki 	KASSERT(arg->dstfmt->precision == 32);
380b950503fSisaki 	KASSERT(arg->dstfmt->stride == 32);
381b950503fSisaki 	KASSERT(audio_format2_is_internal(arg->srcfmt));
382b950503fSisaki 	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
383b950503fSisaki 
384b950503fSisaki 	s = arg->src;
385b950503fSisaki 	d = arg->dst;
386b950503fSisaki 	sample_count = arg->count * arg->srcfmt->channels;
387b950503fSisaki 	xor = audio_format2_is_signed(arg->dstfmt)
388b950503fSisaki 	    ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
389b950503fSisaki 	is_dst_NE = (audio_format2_endian(arg->dstfmt) == BYTE_ORDER);
390b950503fSisaki 
391b950503fSisaki 	for (i = 0; i < sample_count; i++) {
392b950503fSisaki 		uint32_t val;
393b950503fSisaki 		val = *s++;
394b950503fSisaki 		val ^= xor;
395b950503fSisaki 		val <<= 32 - AUDIO_INTERNAL_BITS;
396b950503fSisaki 		if (!is_dst_NE)
397b950503fSisaki 			val = bswap32(val);
398b950503fSisaki 		*d++ = val;
399b950503fSisaki 	}
400b950503fSisaki }
401