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