xref: /netbsd-src/sys/arch/luna68k/dev/psgpam_enc.c (revision 4b552d31e19902d717589952b1ae158ab04f16fa)
1 /*	$NetBSD: psgpam_enc.c,v 1.3 2023/01/15 05:08:33 tsutsui Exp $	*/
2 
3 /*
4  * Copyright (c) 2018 Yosuke Sugahara. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 /*
29  * PSGPAM, PSGPCM encoders
30  * Function names are PSGPAM, but also used by PSGPCM.
31  *
32  * PSGPAM and PSGPCM internally use the unsigned type auint_t for
33  * intermediate calculations to manage non-linear conversions.
34  */
35 
36 #include <sys/types.h>
37 
38 #if defined(_KERNEL)
39 #include <sys/device.h>
40 #include <sys/audioio.h>
41 #include <dev/audio/audio_if.h>
42 #include <luna68k/dev/psgpam_enc.h>
43 #include <luna68k/dev/psgpam_table.h>
44 #else
45 #include <stdint.h>
46 #include <stdlib.h>
47 #include "audio/userland.h"
48 #include "psgpam_enc.h"
49 #include "psgpam_table.c"
50 #include "psgpam_table.h"
51 #endif
52 
53 void
psgpam_init_context(struct psgpam_codecvar * ctx,u_int sample_rate)54 psgpam_init_context(struct psgpam_codecvar *ctx, u_int sample_rate)
55 {
56 
57 	ctx->offset = 65535;
58 	ctx->sample_rate = sample_rate;
59 	ctx->expire_initial = sample_rate / 10;
60 	ctx->expire = ctx->expire_initial;
61 }
62 
63 static inline auint_t
dynamic_offset(struct psgpam_codecvar * ctx,auint_t v)64 dynamic_offset(struct psgpam_codecvar *ctx, auint_t v)
65 {
66 
67 	/*
68 	 * if (the passed value cannot be handled by current offset) {
69 	 *   update offset to handle the passed value
70 	 * } else {
71 	 *   increment offset
72 	 * }
73 	 */
74 	if (v <= ctx->offset) {
75 		ctx->offset = v;
76 	} else {
77 		if (--ctx->expire < 0) {
78 			ctx->offset += 1;
79 			ctx->expire = ctx->expire_initial;
80 		}
81 	}
82 	return v - ctx->offset;
83 }
84 
85 #define BULK(table) *d++ = table[v]
86 
87 #define W8(table) *d++ = table[v]
88 
89 #define W16(table) do {							\
90 	uint16_t t = (uint16_t)table[v];				\
91 	*d++ = ((t & 0xf0) << 4) | (t & 0x0f);				\
92 } while (0)
93 
94 #define W32(table) do {							\
95 	uint32_t t = (uint32_t)table[v];				\
96 	*d++ = ((t & 0xf000) << 12)					\
97 	     | ((t & 0x0f00) <<  8)					\
98 	     | ((t & 0x00f0) <<  4)					\
99 	     | ((t & 0x000f));						\
100 } while (0)
101 
102 #define SPLIT3(table) do {						\
103 	uint16_t t = (uint16_t)table[v];				\
104 	*d++ = ((t & 0xf000) >> 12);					\
105 	*d++ = ((t & 0x0f00) >>  8);					\
106 	*d++ = ((t & 0x000f));						\
107 } while (0)
108 
109 #define ENCODER_DEFINE(enc, TT, table, writer)				\
110 void									\
111 psgpam_aint_to_##enc(audio_filter_arg_t *arg)				\
112 {									\
113 	const aint_t *s = arg->src;					\
114 	TT *d = arg->dst;						\
115 									\
116 	for (int i = 0; i < arg->count; i++) {				\
117 		auint_t v = (*s++) ^ AINT_T_MIN;			\
118 		v >>= (AUDIO_INTERNAL_BITS - table##_BITS);		\
119 		writer(table);						\
120 	}								\
121 }
122 
123 #define ENCODER_D_DEFINE(enc, TT, table, writer)			\
124 void									\
125 psgpam_aint_to_##enc##_d(audio_filter_arg_t *arg)			\
126 {									\
127 	const aint_t *s = arg->src;					\
128 	TT *d = arg->dst;						\
129 									\
130 	for (int i = 0; i < arg->count; i++) {				\
131 		auint_t v = (*s++) ^ AINT_T_MIN;			\
132 		v >>= (AUDIO_INTERNAL_BITS - table##_BITS);		\
133 		v = dynamic_offset(arg->context, v);			\
134 		writer(table);						\
135 	}								\
136 }
137 
138 ENCODER_DEFINE(pam2a, uint16_t, PAM2A_TABLE, W16)
139 ENCODER_DEFINE(pam2b, uint16_t, PAM2B_TABLE, W16)
140 ENCODER_DEFINE(pam3a, uint32_t, PAM3A_TABLE, W32)
141 ENCODER_DEFINE(pam3b, uint32_t, PAM3B_TABLE, W32)
142 ENCODER_DEFINE(pcm1, uint8_t,  PCM1_TABLE, W8)
143 ENCODER_DEFINE(pcm2, uint16_t, PCM2_TABLE, W16)
144 ENCODER_DEFINE(pcm3, uint8_t,  PCM3_TABLE, SPLIT3)
145 
146 ENCODER_D_DEFINE(pam2a, uint16_t, PAM2A_TABLE, W16)
147 ENCODER_D_DEFINE(pam2b, uint16_t, PAM2B_TABLE, W16)
148 ENCODER_D_DEFINE(pam3a, uint32_t, PAM3A_TABLE, W32)
149 ENCODER_D_DEFINE(pam3b, uint32_t, PAM3B_TABLE, W32)
150 ENCODER_D_DEFINE(pcm1, uint8_t,  PCM1_TABLE, W8)
151 ENCODER_D_DEFINE(pcm2, uint16_t, PCM2_TABLE, W16)
152 ENCODER_D_DEFINE(pcm3, uint8_t,  PCM3_TABLE, SPLIT3)
153