1 // license:GPL-2.0+
2 // copyright-holders:Juergen Buchmueller
3 #include "formats/vt_cas.h"
4 
5 #include <cassert>
6 
7 /*********************************************************************
8     vtech 1/2 agnostic
9 *********************************************************************/
10 
11 #define SILENCE 8000
12 
generic_fill_wave(int16_t * buffer,int length,uint8_t * code,int bitsamples,int bytesamples,int lo,int16_t * (* fill_wave_byte)(int16_t * buffer,int byte))13 static int generic_fill_wave(int16_t *buffer, int length, uint8_t *code, int bitsamples, int bytesamples, int lo, int16_t *(*fill_wave_byte)(int16_t *buffer, int byte))
14 {
15 	static int nullbyte;
16 
17 	if( code == CODE_HEADER )
18 	{
19 		int i;
20 
21 		if( length < SILENCE )
22 			return -1;
23 		for( i = 0; i < SILENCE; i++ )
24 			*buffer++ = 0;
25 
26 		nullbyte = 0;
27 
28 		return SILENCE;
29 	}
30 
31 	if( code == CODE_TRAILER )
32 	{
33 		int i;
34 
35 		/* silence at the end */
36 		for( i = 0; i < length; i++ )
37 			*buffer++ = 0;
38 		return length;
39 	}
40 
41 	if( length < bytesamples )
42 		return -1;
43 
44 	buffer = fill_wave_byte(buffer, *code);
45 
46 	if( !nullbyte && *code == 0 )
47 	{
48 		int i;
49 		for( i = 0; i < 2*bitsamples; i++ )
50 			*buffer++ = lo;
51 		nullbyte = 1;
52 		return bytesamples + 2 * bitsamples;
53 	}
54 
55 	return bytesamples;
56 }
57 
58 
59 /*********************************************************************
60     vtech 1
61 *********************************************************************/
62 
63 #define V1_LO   -32768
64 #define V1_HI   +32767
65 
66 #define V1_BITSAMPLES   6
67 #define V1_BYTESAMPLES  8*V1_BITSAMPLES
68 
vtech1_fill_wave_byte(int16_t * buffer,int byte)69 static int16_t *vtech1_fill_wave_byte(int16_t *buffer, int byte)
70 {
71 	int i;
72 
73 	for( i = 7; i >= 0; i-- )
74 	{
75 		*buffer++ = V1_HI;  /* initial cycle */
76 		*buffer++ = V1_LO;
77 		if( (byte >> i) & 1 )
78 		{
79 			*buffer++ = V1_HI; /* two more cycles */
80 			*buffer++ = V1_LO;
81 			*buffer++ = V1_HI;
82 			*buffer++ = V1_LO;
83 		}
84 		else
85 		{
86 			*buffer++ = V1_HI; /* one slow cycle */
87 			*buffer++ = V1_HI;
88 			*buffer++ = V1_LO;
89 			*buffer++ = V1_LO;
90 		}
91 	}
92 	return buffer;
93 }
94 
vtech1_cassette_fill_wave(int16_t * buffer,int length,uint8_t * code)95 static int vtech1_cassette_fill_wave(int16_t *buffer, int length, uint8_t *code)
96 {
97 	return generic_fill_wave(buffer, length, code, V1_BITSAMPLES, V1_BYTESAMPLES, V1_LO, vtech1_fill_wave_byte);
98 }
99 
100 static const cassette_image::LegacyWaveFiller vtech1_legacy_fill_wave =
101 {
102 	vtech1_cassette_fill_wave,  // fill_wave
103 	1,                          // chunk_size
104 	V1_BYTESAMPLES,             // chunk_samples
105 	nullptr,                    // chunk_sample_calc
106 	600*V1_BITSAMPLES,          // sample_frequency
107 	600*V1_BITSAMPLES,          // header_samples
108 	600*V1_BITSAMPLES           // trailer_samples
109 };
110 
vtech1_cas_identify(cassette_image * cassette,cassette_image::Options * opts)111 static cassette_image::error vtech1_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
112 {
113 	return cassette->legacy_identify(opts, &vtech1_legacy_fill_wave);
114 }
115 
vtech1_cas_load(cassette_image * cassette)116 static cassette_image::error vtech1_cas_load(cassette_image *cassette)
117 {
118 	return cassette->legacy_construct(&vtech1_legacy_fill_wave);
119 }
120 
121 static const cassette_image::Format vtech1_cas_format =
122 {
123 	"cas",
124 	vtech1_cas_identify,
125 	vtech1_cas_load,
126 	nullptr
127 };
128 
129 CASSETTE_FORMATLIST_START(vtech1_cassette_formats)
130 	CASSETTE_FORMAT(vtech1_cas_format)
131 CASSETTE_FORMATLIST_END
132 
133 /*********************************************************************
134     vtech 2
135 *********************************************************************/
136 
137 #define VT2_LO  -20000
138 #define VT2_HI  +20000
139 
140 #define VT2_BITSAMPLES  18
141 #define VT2_BYTESAMPLES 8*VT2_BITSAMPLES
142 
143 static const int16_t vtech2_bit0[VT2_BITSAMPLES] =
144 {
145 	/* short cycle, long cycles */
146 	VT2_HI,VT2_HI,VT2_HI,VT2_LO,VT2_LO,VT2_LO,
147 	VT2_HI,VT2_HI,VT2_HI,VT2_HI,VT2_HI,VT2_HI,
148 	VT2_LO,VT2_LO,VT2_LO,VT2_LO,VT2_LO,VT2_LO
149 };
150 
151 static const int16_t vtech2_bit1[VT2_BITSAMPLES] =
152 {
153 	/* three short cycle */
154 	VT2_HI,VT2_HI,VT2_HI,VT2_LO,VT2_LO,VT2_LO,
155 	VT2_HI,VT2_HI,VT2_HI,VT2_LO,VT2_LO,VT2_LO,
156 	VT2_HI,VT2_HI,VT2_HI,VT2_LO,VT2_LO,VT2_LO
157 };
158 
159 
vtech2_fill_wave_bit(int16_t * buffer,int bit)160 static int16_t *vtech2_fill_wave_bit(int16_t *buffer, int bit)
161 {
162 	int i;
163 	if( bit )
164 	{
165 		for( i = 0; i < VT2_BITSAMPLES; i++ )
166 			*buffer++ = vtech2_bit1[i];
167 	}
168 	else
169 	{
170 		for( i = 0; i < VT2_BITSAMPLES; i++ )
171 			*buffer++ = vtech2_bit0[i];
172 	}
173 	return buffer;
174 }
175 
176 
vtech2_fill_wave_byte(int16_t * buffer,int byte)177 static int16_t *vtech2_fill_wave_byte(int16_t *buffer, int byte)
178 {
179 	buffer = vtech2_fill_wave_bit(buffer, (byte >> 7) & 1);
180 	buffer = vtech2_fill_wave_bit(buffer, (byte >> 6) & 1);
181 	buffer = vtech2_fill_wave_bit(buffer, (byte >> 5) & 1);
182 	buffer = vtech2_fill_wave_bit(buffer, (byte >> 4) & 1);
183 	buffer = vtech2_fill_wave_bit(buffer, (byte >> 3) & 1);
184 	buffer = vtech2_fill_wave_bit(buffer, (byte >> 2) & 1);
185 	buffer = vtech2_fill_wave_bit(buffer, (byte >> 1) & 1);
186 	buffer = vtech2_fill_wave_bit(buffer, (byte >> 0) & 1);
187 	return buffer;
188 }
189 
vtech2_cassette_fill_wave(int16_t * buffer,int length,uint8_t * code)190 static int vtech2_cassette_fill_wave(int16_t *buffer, int length, uint8_t *code)
191 {
192 	return generic_fill_wave(buffer, length, code, VT2_BITSAMPLES, VT2_BYTESAMPLES, VT2_LO, vtech2_fill_wave_byte);
193 }
194 
195 static const cassette_image::LegacyWaveFiller vtech2_legacy_fill_wave =
196 {
197 	vtech2_cassette_fill_wave,  /* fill_wave */
198 	1,                          /* chunk_size */
199 	VT2_BYTESAMPLES,            /* chunk_samples */
200 	nullptr,                       /* chunk_sample_calc */
201 	600*VT2_BITSAMPLES,         /* sample_frequency */
202 	600*VT2_BITSAMPLES,         /* header_samples */
203 	600*VT2_BITSAMPLES          /* trailer_samples */
204 };
205 
vtech2_cas_identify(cassette_image * cassette,cassette_image::Options * opts)206 static cassette_image::error vtech2_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
207 {
208 	return cassette->legacy_identify(opts, &vtech2_legacy_fill_wave);
209 }
210 
vtech2_cas_load(cassette_image * cassette)211 static cassette_image::error vtech2_cas_load(cassette_image *cassette)
212 {
213 	return cassette->legacy_construct(&vtech2_legacy_fill_wave);
214 }
215 
216 static const cassette_image::Format vtech2_cas_format =
217 {
218 	"cas",
219 	vtech2_cas_identify,
220 	vtech2_cas_load,
221 	nullptr
222 };
223 
224 CASSETTE_FORMATLIST_START(vtech2_cassette_formats)
225 	CASSETTE_FORMAT(vtech2_cas_format)
226 CASSETTE_FORMATLIST_END
227