diff options
Diffstat (limited to 'lib/rbcodec')
-rw-r--r-- | lib/rbcodec/SOURCES | 3 | ||||
-rw-r--r-- | lib/rbcodec/codecs/SOURCES | 3 | ||||
-rw-r--r-- | lib/rbcodec/codecs/codecs.make | 3 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libayumi/SOURCES | 5 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libayumi/ayumi.c | 361 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libayumi/ayumi.h | 72 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libayumi/ayumi_render.c | 328 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libayumi/ayumi_render.h | 84 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libayumi/libayumi.make | 18 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libayumi/lzh.c | 420 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libayumi/lzh.h | 6 | ||||
-rw-r--r-- | lib/rbcodec/codecs/vtx.c | 138 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata.c | 40 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata.h | 13 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata_parsers.h | 3 | ||||
-rw-r--r-- | lib/rbcodec/metadata/vtx.c | 150 |
16 files changed, 1625 insertions, 22 deletions
diff --git a/lib/rbcodec/SOURCES b/lib/rbcodec/SOURCES index c288bb6de4..b0efebc989 100644 --- a/lib/rbcodec/SOURCES +++ b/lib/rbcodec/SOURCES | |||
@@ -40,6 +40,9 @@ metadata/asap.c | |||
40 | metadata/asf.c | 40 | metadata/asf.c |
41 | metadata/au.c | 41 | metadata/au.c |
42 | metadata/ay.c | 42 | metadata/ay.c |
43 | #ifdef HAVE_FPU | ||
44 | metadata/vtx.c | ||
45 | #endif | ||
43 | metadata/flac.c | 46 | metadata/flac.c |
44 | metadata/gbs.c | 47 | metadata/gbs.c |
45 | metadata/hes.c | 48 | metadata/hes.c |
diff --git a/lib/rbcodec/codecs/SOURCES b/lib/rbcodec/codecs/SOURCES index f0787d267d..78b7b97498 100644 --- a/lib/rbcodec/codecs/SOURCES +++ b/lib/rbcodec/codecs/SOURCES | |||
@@ -34,6 +34,9 @@ wav64.c | |||
34 | tta.c | 34 | tta.c |
35 | wmapro.c | 35 | wmapro.c |
36 | ay.c | 36 | ay.c |
37 | #ifdef HAVE_FPU | ||
38 | vtx.c | ||
39 | #endif | ||
37 | gbs.c | 40 | gbs.c |
38 | hes.c | 41 | hes.c |
39 | nsf.c | 42 | nsf.c |
diff --git a/lib/rbcodec/codecs/codecs.make b/lib/rbcodec/codecs/codecs.make index 4602a56d2c..d9554a9802 100644 --- a/lib/rbcodec/codecs/codecs.make +++ b/lib/rbcodec/codecs/codecs.make | |||
@@ -39,6 +39,7 @@ include $(RBCODECLIB_DIR)/codecs/liba52/liba52.make | |||
39 | include $(RBCODECLIB_DIR)/codecs/libalac/libalac.make | 39 | include $(RBCODECLIB_DIR)/codecs/libalac/libalac.make |
40 | include $(RBCODECLIB_DIR)/codecs/libasap/libasap.make | 40 | include $(RBCODECLIB_DIR)/codecs/libasap/libasap.make |
41 | include $(RBCODECLIB_DIR)/codecs/libasf/libasf.make | 41 | include $(RBCODECLIB_DIR)/codecs/libasf/libasf.make |
42 | include $(RBCODECLIB_DIR)/codecs/libayumi/libayumi.make | ||
42 | include $(RBCODECLIB_DIR)/codecs/libfaad/libfaad.make | 43 | include $(RBCODECLIB_DIR)/codecs/libfaad/libfaad.make |
43 | include $(RBCODECLIB_DIR)/codecs/libffmpegFLAC/libffmpegFLAC.make | 44 | include $(RBCODECLIB_DIR)/codecs/libffmpegFLAC/libffmpegFLAC.make |
44 | include $(RBCODECLIB_DIR)/codecs/libm4a/libm4a.make | 45 | include $(RBCODECLIB_DIR)/codecs/libm4a/libm4a.make |
@@ -74,6 +75,7 @@ $(ASAPLIB) : CODECFLAGS += -O1 | |||
74 | $(ASFLIB) : CODECFLAGS += -O2 | 75 | $(ASFLIB) : CODECFLAGS += -O2 |
75 | $(ATRACLIB) : CODECFLAGS += -O1 | 76 | $(ATRACLIB) : CODECFLAGS += -O1 |
76 | $(AYLIB) : CODECFLAGS += -O2 | 77 | $(AYLIB) : CODECFLAGS += -O2 |
78 | $(AYUMILIB) : CODECFLAGS += -O3 | ||
77 | $(COOKLIB): CODECFLAGS += -O1 | 79 | $(COOKLIB): CODECFLAGS += -O1 |
78 | $(DEMACLIB) : CODECFLAGS += -O3 | 80 | $(DEMACLIB) : CODECFLAGS += -O3 |
79 | $(FAADLIB) : CODECFLAGS += -O2 | 81 | $(FAADLIB) : CODECFLAGS += -O2 |
@@ -181,6 +183,7 @@ $(CODECDIR)/vox.codec : $(CODECDIR)/libpcm.a | |||
181 | $(CODECDIR)/wav64.codec : $(CODECDIR)/libpcm.a | 183 | $(CODECDIR)/wav64.codec : $(CODECDIR)/libpcm.a |
182 | $(CODECDIR)/tta.codec : $(CODECDIR)/libtta.a | 184 | $(CODECDIR)/tta.codec : $(CODECDIR)/libtta.a |
183 | $(CODECDIR)/ay.codec : $(CODECDIR)/libay.a | 185 | $(CODECDIR)/ay.codec : $(CODECDIR)/libay.a |
186 | $(CODECDIR)/vtx.codec : $(CODECDIR)/libayumi.a | ||
184 | $(CODECDIR)/gbs.codec : $(CODECDIR)/libgbs.a | 187 | $(CODECDIR)/gbs.codec : $(CODECDIR)/libgbs.a |
185 | $(CODECDIR)/hes.codec : $(CODECDIR)/libhes.a | 188 | $(CODECDIR)/hes.codec : $(CODECDIR)/libhes.a |
186 | $(CODECDIR)/nsf.codec : $(CODECDIR)/libnsf.a $(CODECDIR)/libemu2413.a | 189 | $(CODECDIR)/nsf.codec : $(CODECDIR)/libnsf.a $(CODECDIR)/libemu2413.a |
diff --git a/lib/rbcodec/codecs/libayumi/SOURCES b/lib/rbcodec/codecs/libayumi/SOURCES new file mode 100644 index 0000000000..075619bed1 --- /dev/null +++ b/lib/rbcodec/codecs/libayumi/SOURCES | |||
@@ -0,0 +1,5 @@ | |||
1 | #ifdef HAVE_FPU | ||
2 | ayumi_render.c | ||
3 | ayumi.c | ||
4 | lzh.c | ||
5 | #endif | ||
diff --git a/lib/rbcodec/codecs/libayumi/ayumi.c b/lib/rbcodec/codecs/libayumi/ayumi.c new file mode 100644 index 0000000000..2e0419f6cb --- /dev/null +++ b/lib/rbcodec/codecs/libayumi/ayumi.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /* Author: Peter Sovietov */ | ||
2 | |||
3 | #include <string.h> | ||
4 | #include <math.h> | ||
5 | #include "ayumi.h" | ||
6 | |||
7 | static const double AY_dac_table[] = { | ||
8 | 0.0, 0.0, | ||
9 | 0.00999465934234, 0.00999465934234, | ||
10 | 0.0144502937362, 0.0144502937362, | ||
11 | 0.0210574502174, 0.0210574502174, | ||
12 | 0.0307011520562, 0.0307011520562, | ||
13 | 0.0455481803616, 0.0455481803616, | ||
14 | 0.0644998855573, 0.0644998855573, | ||
15 | 0.107362478065, 0.107362478065, | ||
16 | 0.126588845655, 0.126588845655, | ||
17 | 0.20498970016, 0.20498970016, | ||
18 | 0.292210269322, 0.292210269322, | ||
19 | 0.372838941024, 0.372838941024, | ||
20 | 0.492530708782, 0.492530708782, | ||
21 | 0.635324635691, 0.635324635691, | ||
22 | 0.805584802014, 0.805584802014, | ||
23 | 1.0, 1.0 | ||
24 | }; | ||
25 | |||
26 | static const double YM_dac_table[] = { | ||
27 | 0.0, 0.0, | ||
28 | 0.00465400167849, 0.00772106507973, | ||
29 | 0.0109559777218, 0.0139620050355, | ||
30 | 0.0169985503929, 0.0200198367285, | ||
31 | 0.024368657969, 0.029694056611, | ||
32 | 0.0350652323186, 0.0403906309606, | ||
33 | 0.0485389486534, 0.0583352407111, | ||
34 | 0.0680552376593, 0.0777752346075, | ||
35 | 0.0925154497597, 0.111085679408, | ||
36 | 0.129747463188, 0.148485542077, | ||
37 | 0.17666895552, 0.211551079576, | ||
38 | 0.246387426566, 0.281101701381, | ||
39 | 0.333730067903, 0.400427252613, | ||
40 | 0.467383840696, 0.53443198291, | ||
41 | 0.635172045472, 0.75800717174, | ||
42 | 0.879926756695, 1.0 | ||
43 | }; | ||
44 | |||
45 | static void reset_segment(struct ayumi* ay); | ||
46 | |||
47 | double sqrt(double n) | ||
48 | { | ||
49 | double x0 = n; | ||
50 | double x1; | ||
51 | for (;;) { | ||
52 | x1 = x0 - (x0 * x0 - n) / (2 * x0); | ||
53 | double delta = (x1 - x0) / x0; | ||
54 | if (delta < .000001 && delta > -.000001) | ||
55 | return x1; | ||
56 | x0 = x1; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | static int update_tone(struct ayumi* ay, int index) { | ||
61 | struct tone_channel* ch = &ay->channels[index]; | ||
62 | ch->tone_counter += 1; | ||
63 | if (ch->tone_counter >= ch->tone_period) { | ||
64 | ch->tone_counter = 0; | ||
65 | ch->tone ^= 1; | ||
66 | } | ||
67 | return ch->tone; | ||
68 | } | ||
69 | |||
70 | static int update_noise(struct ayumi* ay) { | ||
71 | int bit0x3; | ||
72 | ay->noise_counter += 1; | ||
73 | if (ay->noise_counter >= (ay->noise_period << 1)) { | ||
74 | ay->noise_counter = 0; | ||
75 | bit0x3 = ((ay->noise ^ (ay->noise >> 3)) & 1); | ||
76 | ay->noise = (ay->noise >> 1) | (bit0x3 << 16); | ||
77 | } | ||
78 | return ay->noise & 1; | ||
79 | } | ||
80 | |||
81 | static void slide_up(struct ayumi* ay) { | ||
82 | ay->envelope += 1; | ||
83 | if (ay->envelope > 31) { | ||
84 | ay->envelope_segment ^= 1; | ||
85 | reset_segment(ay); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static void slide_down(struct ayumi* ay) { | ||
90 | ay->envelope -= 1; | ||
91 | if (ay->envelope < 0) { | ||
92 | ay->envelope_segment ^= 1; | ||
93 | reset_segment(ay); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | static void hold_top(struct ayumi* ay) { | ||
98 | (void) ay; | ||
99 | } | ||
100 | |||
101 | static void hold_bottom(struct ayumi* ay) { | ||
102 | (void) ay; | ||
103 | } | ||
104 | |||
105 | static void (* const Envelopes[][2])(struct ayumi*) = { | ||
106 | {slide_down, hold_bottom}, | ||
107 | {slide_down, hold_bottom}, | ||
108 | {slide_down, hold_bottom}, | ||
109 | {slide_down, hold_bottom}, | ||
110 | {slide_up, hold_bottom}, | ||
111 | {slide_up, hold_bottom}, | ||
112 | {slide_up, hold_bottom}, | ||
113 | {slide_up, hold_bottom}, | ||
114 | {slide_down, slide_down}, | ||
115 | {slide_down, hold_bottom}, | ||
116 | {slide_down, slide_up}, | ||
117 | {slide_down, hold_top}, | ||
118 | {slide_up, slide_up}, | ||
119 | {slide_up, hold_top}, | ||
120 | {slide_up, slide_down}, | ||
121 | {slide_up, hold_bottom} | ||
122 | }; | ||
123 | |||
124 | static void reset_segment(struct ayumi* ay) { | ||
125 | if (Envelopes[ay->envelope_shape][ay->envelope_segment] == slide_down | ||
126 | || Envelopes[ay->envelope_shape][ay->envelope_segment] == hold_top) { | ||
127 | ay->envelope = 31; | ||
128 | return; | ||
129 | } | ||
130 | ay->envelope = 0; | ||
131 | } | ||
132 | |||
133 | int update_envelope(struct ayumi* ay) { | ||
134 | ay->envelope_counter += 1; | ||
135 | if (ay->envelope_counter >= ay->envelope_period) { | ||
136 | ay->envelope_counter = 0; | ||
137 | Envelopes[ay->envelope_shape][ay->envelope_segment](ay); | ||
138 | } | ||
139 | return ay->envelope; | ||
140 | } | ||
141 | |||
142 | static void update_mixer(struct ayumi* ay) { | ||
143 | int i; | ||
144 | int out; | ||
145 | int noise = update_noise(ay); | ||
146 | int envelope = update_envelope(ay); | ||
147 | ay->left = 0; | ||
148 | ay->right = 0; | ||
149 | for (i = 0; i < TONE_CHANNELS; i += 1) { | ||
150 | out = (update_tone(ay, i) | ay->channels[i].t_off) & (noise | ay->channels[i].n_off); | ||
151 | out *= ay->channels[i].e_on ? envelope : ay->channels[i].volume * 2 + 1; | ||
152 | ay->left += ay->dac_table[out] * ay->channels[i].pan_left; | ||
153 | ay->right += ay->dac_table[out] * ay->channels[i].pan_right; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | int ayumi_configure(struct ayumi* ay, int is_ym, double clock_rate, int sr) { | ||
158 | int i; | ||
159 | memset(ay, 0, sizeof(struct ayumi)); | ||
160 | ay->step = clock_rate / (sr * 8 * DECIMATE_FACTOR); | ||
161 | ay->dac_table = is_ym ? YM_dac_table : AY_dac_table; | ||
162 | ay->noise = 1; | ||
163 | ayumi_set_envelope(ay, 1); | ||
164 | for (i = 0; i < TONE_CHANNELS; i += 1) { | ||
165 | ayumi_set_tone(ay, i, 1); | ||
166 | } | ||
167 | return ay->step < 1; | ||
168 | } | ||
169 | |||
170 | void ayumi_set_pan(struct ayumi* ay, int index, double pan, int is_eqp) { | ||
171 | if (is_eqp) { | ||
172 | ay->channels[index].pan_left = sqrt(1 - pan); | ||
173 | ay->channels[index].pan_right = sqrt(pan); | ||
174 | } else { | ||
175 | ay->channels[index].pan_left = 1 - pan; | ||
176 | ay->channels[index].pan_right = pan; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | void ayumi_set_tone(struct ayumi* ay, int index, int period) { | ||
181 | period &= 0xfff; | ||
182 | ay->channels[index].tone_period = (period == 0) | period; | ||
183 | } | ||
184 | |||
185 | void ayumi_set_noise(struct ayumi* ay, int period) { | ||
186 | ay->noise_period = period & 0x1f; | ||
187 | } | ||
188 | |||
189 | void ayumi_set_mixer(struct ayumi* ay, int index, int t_off, int n_off, int e_on) { | ||
190 | ay->channels[index].t_off = t_off & 1; | ||
191 | ay->channels[index].n_off = n_off & 1; | ||
192 | ay->channels[index].e_on = e_on; | ||
193 | } | ||
194 | |||
195 | void ayumi_set_volume(struct ayumi* ay, int index, int volume) { | ||
196 | ay->channels[index].volume = volume & 0xf; | ||
197 | } | ||
198 | |||
199 | void ayumi_set_envelope(struct ayumi* ay, int period) { | ||
200 | period &= 0xffff; | ||
201 | ay->envelope_period = (period == 0) | period; | ||
202 | } | ||
203 | |||
204 | void ayumi_set_envelope_shape(struct ayumi* ay, int shape) { | ||
205 | ay->envelope_shape = shape & 0xf; | ||
206 | ay->envelope_counter = 0; | ||
207 | ay->envelope_segment = 0; | ||
208 | reset_segment(ay); | ||
209 | } | ||
210 | |||
211 | static double decimate(double* x) { | ||
212 | double y = -0.0000046183113992051936 * (x[1] + x[191]) + | ||
213 | -0.00001117761640887225 * (x[2] + x[190]) + | ||
214 | -0.000018610264502005432 * (x[3] + x[189]) + | ||
215 | -0.000025134586135631012 * (x[4] + x[188]) + | ||
216 | -0.000028494281690666197 * (x[5] + x[187]) + | ||
217 | -0.000026396828793275159 * (x[6] + x[186]) + | ||
218 | -0.000017094212558802156 * (x[7] + x[185]) + | ||
219 | 0.000023798193576966866 * (x[9] + x[183]) + | ||
220 | 0.000051281160242202183 * (x[10] + x[182]) + | ||
221 | 0.00007762197826243427 * (x[11] + x[181]) + | ||
222 | 0.000096759426664120416 * (x[12] + x[180]) + | ||
223 | 0.00010240229300393402 * (x[13] + x[179]) + | ||
224 | 0.000089344614218077106 * (x[14] + x[178]) + | ||
225 | 0.000054875700118949183 * (x[15] + x[177]) + | ||
226 | -0.000069839082210680165 * (x[17] + x[175]) + | ||
227 | -0.0001447966132360757 * (x[18] + x[174]) + | ||
228 | -0.00021158452917708308 * (x[19] + x[173]) + | ||
229 | -0.00025535069106550544 * (x[20] + x[172]) + | ||
230 | -0.00026228714374322104 * (x[21] + x[171]) + | ||
231 | -0.00022258805927027799 * (x[22] + x[170]) + | ||
232 | -0.00013323230495695704 * (x[23] + x[169]) + | ||
233 | 0.00016182578767055206 * (x[25] + x[167]) + | ||
234 | 0.00032846175385096581 * (x[26] + x[166]) + | ||
235 | 0.00047045611576184863 * (x[27] + x[165]) + | ||
236 | 0.00055713851457530944 * (x[28] + x[164]) + | ||
237 | 0.00056212565121518726 * (x[29] + x[163]) + | ||
238 | 0.00046901918553962478 * (x[30] + x[162]) + | ||
239 | 0.00027624866838952986 * (x[31] + x[161]) + | ||
240 | -0.00032564179486838622 * (x[33] + x[159]) + | ||
241 | -0.00065182310286710388 * (x[34] + x[158]) + | ||
242 | -0.00092127787309319298 * (x[35] + x[157]) + | ||
243 | -0.0010772534348943575 * (x[36] + x[156]) + | ||
244 | -0.0010737727700273478 * (x[37] + x[155]) + | ||
245 | -0.00088556645390392634 * (x[38] + x[154]) + | ||
246 | -0.00051581896090765534 * (x[39] + x[153]) + | ||
247 | 0.00059548767193795277 * (x[41] + x[151]) + | ||
248 | 0.0011803558710661009 * (x[42] + x[150]) + | ||
249 | 0.0016527320270369871 * (x[43] + x[149]) + | ||
250 | 0.0019152679330965555 * (x[44] + x[148]) + | ||
251 | 0.0018927324805381538 * (x[45] + x[147]) + | ||
252 | 0.0015481870327877937 * (x[46] + x[146]) + | ||
253 | 0.00089470695834941306 * (x[47] + x[145]) + | ||
254 | -0.0010178225878206125 * (x[49] + x[143]) + | ||
255 | -0.0020037400552054292 * (x[50] + x[142]) + | ||
256 | -0.0027874356824117317 * (x[51] + x[141]) + | ||
257 | -0.003210329988021943 * (x[52] + x[140]) + | ||
258 | -0.0031540624117984395 * (x[53] + x[139]) + | ||
259 | -0.0025657163651900345 * (x[54] + x[138]) + | ||
260 | -0.0014750752642111449 * (x[55] + x[137]) + | ||
261 | 0.0016624165446378462 * (x[57] + x[135]) + | ||
262 | 0.0032591192839069179 * (x[58] + x[134]) + | ||
263 | 0.0045165685815867747 * (x[59] + x[133]) + | ||
264 | 0.0051838984346123896 * (x[60] + x[132]) + | ||
265 | 0.0050774264697459933 * (x[61] + x[131]) + | ||
266 | 0.0041192521414141585 * (x[62] + x[130]) + | ||
267 | 0.0023628575417966491 * (x[63] + x[129]) + | ||
268 | -0.0026543507866759182 * (x[65] + x[127]) + | ||
269 | -0.0051990251084333425 * (x[66] + x[126]) + | ||
270 | -0.0072020238234656924 * (x[67] + x[125]) + | ||
271 | -0.0082672928192007358 * (x[68] + x[124]) + | ||
272 | -0.0081033739572956287 * (x[69] + x[123]) + | ||
273 | -0.006583111539570221 * (x[70] + x[122]) + | ||
274 | -0.0037839040415292386 * (x[71] + x[121]) + | ||
275 | 0.0042781252851152507 * (x[73] + x[119]) + | ||
276 | 0.0084176358598320178 * (x[74] + x[118]) + | ||
277 | 0.01172566057463055 * (x[75] + x[117]) + | ||
278 | 0.013550476647788672 * (x[76] + x[116]) + | ||
279 | 0.013388189369997496 * (x[77] + x[115]) + | ||
280 | 0.010979501242341259 * (x[78] + x[114]) + | ||
281 | 0.006381274941685413 * (x[79] + x[113]) + | ||
282 | -0.007421229604153888 * (x[81] + x[111]) + | ||
283 | -0.01486456304340213 * (x[82] + x[110]) + | ||
284 | -0.021143584622178104 * (x[83] + x[109]) + | ||
285 | -0.02504275058758609 * (x[84] + x[108]) + | ||
286 | -0.025473530942547201 * (x[85] + x[107]) + | ||
287 | -0.021627310017882196 * (x[86] + x[106]) + | ||
288 | -0.013104323383225543 * (x[87] + x[105]) + | ||
289 | 0.017065133989980476 * (x[89] + x[103]) + | ||
290 | 0.036978919264451952 * (x[90] + x[102]) + | ||
291 | 0.05823318062093958 * (x[91] + x[101]) + | ||
292 | 0.079072012081405949 * (x[92] + x[100]) + | ||
293 | 0.097675998716952317 * (x[93] + x[99]) + | ||
294 | 0.11236045936950932 * (x[94] + x[98]) + | ||
295 | 0.12176343577287731 * (x[95] + x[97]) + | ||
296 | 0.125 * x[96]; | ||
297 | memcpy(&x[FIR_SIZE - DECIMATE_FACTOR], x, DECIMATE_FACTOR * sizeof(double)); | ||
298 | return y; | ||
299 | } | ||
300 | |||
301 | void ayumi_process(struct ayumi* ay) { | ||
302 | int i; | ||
303 | double y1; | ||
304 | double* c_left = ay->interpolator_left.c; | ||
305 | double* y_left = ay->interpolator_left.y; | ||
306 | double* c_right = ay->interpolator_right.c; | ||
307 | double* y_right = ay->interpolator_right.y; | ||
308 | double* fir_left = &ay->fir_left[FIR_SIZE - ay->fir_index * DECIMATE_FACTOR]; | ||
309 | double* fir_right = &ay->fir_right[FIR_SIZE - ay->fir_index * DECIMATE_FACTOR]; | ||
310 | ay->fir_index = (ay->fir_index + 1) % (FIR_SIZE / DECIMATE_FACTOR - 1); | ||
311 | for (i = DECIMATE_FACTOR - 1; i >= 0; i -= 1) { | ||
312 | ay->x += ay->step; | ||
313 | if (ay->x >= 1) { | ||
314 | ay->x -= 1; | ||
315 | y_left[0] = y_left[1]; | ||
316 | y_left[1] = y_left[2]; | ||
317 | y_left[2] = y_left[3]; | ||
318 | y_right[0] = y_right[1]; | ||
319 | y_right[1] = y_right[2]; | ||
320 | y_right[2] = y_right[3]; | ||
321 | update_mixer(ay); | ||
322 | y_left[3] = ay->left; | ||
323 | y_right[3] = ay->right; | ||
324 | y1 = y_left[2] - y_left[0]; | ||
325 | c_left[0] = 0.5 * y_left[1] + 0.25 * (y_left[0] + y_left[2]); | ||
326 | c_left[1] = 0.5 * y1; | ||
327 | c_left[2] = 0.25 * (y_left[3] - y_left[1] - y1); | ||
328 | y1 = y_right[2] - y_right[0]; | ||
329 | c_right[0] = 0.5 * y_right[1] + 0.25 * (y_right[0] + y_right[2]); | ||
330 | c_right[1] = 0.5 * y1; | ||
331 | c_right[2] = 0.25 * (y_right[3] - y_right[1] - y1); | ||
332 | } | ||
333 | fir_left[i] = (c_left[2] * ay->x + c_left[1]) * ay->x + c_left[0]; | ||
334 | fir_right[i] = (c_right[2] * ay->x + c_right[1]) * ay->x + c_right[0]; | ||
335 | } | ||
336 | ay->left = decimate(fir_left); | ||
337 | ay->right = decimate(fir_right); | ||
338 | } | ||
339 | |||
340 | void ayumi_seek(struct ayumi* ay) { | ||
341 | int i; | ||
342 | for (i = DECIMATE_FACTOR - 1; i >= 0; i -= 1) { | ||
343 | ay->x += ay->step; | ||
344 | if (ay->x >= 1) { | ||
345 | ay->x -= 1; | ||
346 | update_mixer(ay); | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | |||
351 | static double dc_filter(struct dc_filter* dc, int index, double x) { | ||
352 | dc->sum += -dc->delay[index] + x; | ||
353 | dc->delay[index] = x; | ||
354 | return x - dc->sum / DC_FILTER_SIZE; | ||
355 | } | ||
356 | |||
357 | void ayumi_remove_dc(struct ayumi* ay) { | ||
358 | ay->left = dc_filter(&ay->dc_left, ay->dc_index, ay->left); | ||
359 | ay->right = dc_filter(&ay->dc_right, ay->dc_index, ay->right); | ||
360 | ay->dc_index = (ay->dc_index + 1) & (DC_FILTER_SIZE - 1); | ||
361 | } | ||
diff --git a/lib/rbcodec/codecs/libayumi/ayumi.h b/lib/rbcodec/codecs/libayumi/ayumi.h new file mode 100644 index 0000000000..66d767797e --- /dev/null +++ b/lib/rbcodec/codecs/libayumi/ayumi.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* Author: Peter Sovietov */ | ||
2 | |||
3 | #ifndef AYUMI_H | ||
4 | #define AYUMI_H | ||
5 | |||
6 | enum { | ||
7 | TONE_CHANNELS = 3, | ||
8 | DECIMATE_FACTOR = 8, | ||
9 | FIR_SIZE = 192, | ||
10 | DC_FILTER_SIZE = 1024 | ||
11 | }; | ||
12 | |||
13 | struct tone_channel { | ||
14 | int tone_period; | ||
15 | int tone_counter; | ||
16 | int tone; | ||
17 | int t_off; | ||
18 | int n_off; | ||
19 | int e_on; | ||
20 | int volume; | ||
21 | double pan_left; | ||
22 | double pan_right; | ||
23 | }; | ||
24 | |||
25 | struct interpolator { | ||
26 | double c[4]; | ||
27 | double y[4]; | ||
28 | }; | ||
29 | |||
30 | struct dc_filter { | ||
31 | double sum; | ||
32 | double delay[DC_FILTER_SIZE]; | ||
33 | }; | ||
34 | |||
35 | struct ayumi { | ||
36 | struct tone_channel channels[TONE_CHANNELS]; | ||
37 | int noise_period; | ||
38 | int noise_counter; | ||
39 | int noise; | ||
40 | int envelope_counter; | ||
41 | int envelope_period; | ||
42 | int envelope_shape; | ||
43 | int envelope_segment; | ||
44 | int envelope; | ||
45 | const double* dac_table; | ||
46 | double step; | ||
47 | double x; | ||
48 | struct interpolator interpolator_left; | ||
49 | struct interpolator interpolator_right; | ||
50 | double fir_left[FIR_SIZE * 2]; | ||
51 | double fir_right[FIR_SIZE * 2]; | ||
52 | int fir_index; | ||
53 | struct dc_filter dc_left; | ||
54 | struct dc_filter dc_right; | ||
55 | int dc_index; | ||
56 | double left; | ||
57 | double right; | ||
58 | }; | ||
59 | |||
60 | int ayumi_configure(struct ayumi* ay, int is_ym, double clock_rate, int sr); | ||
61 | void ayumi_set_pan(struct ayumi* ay, int index, double pan, int is_eqp); | ||
62 | void ayumi_set_tone(struct ayumi* ay, int index, int period); | ||
63 | void ayumi_set_noise(struct ayumi* ay, int period); | ||
64 | void ayumi_set_mixer(struct ayumi* ay, int index, int t_off, int n_off, int e_on); | ||
65 | void ayumi_set_volume(struct ayumi* ay, int index, int volume); | ||
66 | void ayumi_set_envelope(struct ayumi* ay, int period); | ||
67 | void ayumi_set_envelope_shape(struct ayumi* ay, int shape); | ||
68 | void ayumi_process(struct ayumi* ay); | ||
69 | void ayumi_seek(struct ayumi* ay); | ||
70 | void ayumi_remove_dc(struct ayumi* ay); | ||
71 | |||
72 | #endif | ||
diff --git a/lib/rbcodec/codecs/libayumi/ayumi_render.c b/lib/rbcodec/codecs/libayumi/ayumi_render.c new file mode 100644 index 0000000000..9bf0204597 --- /dev/null +++ b/lib/rbcodec/codecs/libayumi/ayumi_render.c | |||
@@ -0,0 +1,328 @@ | |||
1 | #include "ayumi_render.h" | ||
2 | |||
3 | #include <stdlib.h> | ||
4 | #include <string.h> | ||
5 | #include <stdint.h> | ||
6 | |||
7 | #include "ayumi.h" | ||
8 | #include "lzh.h" | ||
9 | #include "codeclib.h" | ||
10 | |||
11 | ayumi_render_t ay; | ||
12 | |||
13 | /* default panning settings, 7 stereo types */ | ||
14 | static const double default_pan[7][3] = { | ||
15 | /* A, B, C */ | ||
16 | |||
17 | {0.50, 0.50, 0.50}, /* MONO */ | ||
18 | {0.10, 0.50, 0.90}, /* ABC */ | ||
19 | {0.10, 0.90, 0.50}, /* ACB */ | ||
20 | {0.50, 0.10, 0.90}, /* BAC */ | ||
21 | {0.90, 0.10, 0.50}, /* BCA */ | ||
22 | {0.50, 0.90, 0.10}, /* CAB */ | ||
23 | {0.90, 0.50, 0.10} /* CBA */ | ||
24 | }; | ||
25 | |||
26 | static const char *chiptype_name[3] = { | ||
27 | "AY-3-8910", | ||
28 | "YM2149", | ||
29 | "Unknown" | ||
30 | }; | ||
31 | |||
32 | static const char *layout_name[9] = { | ||
33 | "Mono", | ||
34 | "ABC Stereo", | ||
35 | "ACB Stereo", | ||
36 | "BAC Stereo", | ||
37 | "BCA Stereo", | ||
38 | "CAB Stereo", | ||
39 | "CBA Stereo", | ||
40 | "Custom", | ||
41 | "Unknown" | ||
42 | }; | ||
43 | |||
44 | /* reader */ | ||
45 | |||
46 | #define VTX_STRING_MAX 254 | ||
47 | |||
48 | typedef struct { | ||
49 | uchar *ptr; | ||
50 | uint size; | ||
51 | } reader_t; | ||
52 | |||
53 | reader_t reader; | ||
54 | |||
55 | void Reader_Init(void *pBlock) { | ||
56 | reader.ptr = (uchar *) pBlock; | ||
57 | reader.size = 0; | ||
58 | } | ||
59 | |||
60 | uint Reader_ReadByte(void) { | ||
61 | uint res; | ||
62 | res = *reader.ptr++; | ||
63 | reader.size += 1; | ||
64 | return res; | ||
65 | } | ||
66 | |||
67 | uint Reader_ReadWord(void) { | ||
68 | uint res; | ||
69 | res = *reader.ptr++; | ||
70 | res += *reader.ptr++ << 8; | ||
71 | reader.size += 2; | ||
72 | return res; | ||
73 | } | ||
74 | |||
75 | uint Reader_ReadDWord(void) { | ||
76 | uint res; | ||
77 | res = *reader.ptr++; | ||
78 | res += *reader.ptr++ << 8; | ||
79 | res += *reader.ptr++ << 16; | ||
80 | res += *reader.ptr++ << 24; | ||
81 | reader.size += 4; | ||
82 | return res; | ||
83 | } | ||
84 | |||
85 | char *Reader_ReadString(void) { | ||
86 | char *res; | ||
87 | if (reader.ptr == NULL) | ||
88 | return NULL; | ||
89 | int len = strlen((const char *)reader.ptr); | ||
90 | if (len > VTX_STRING_MAX) | ||
91 | return NULL; | ||
92 | res = reader.ptr; | ||
93 | reader.ptr += len + 1; | ||
94 | reader.size += len + 1; | ||
95 | return res; | ||
96 | } | ||
97 | |||
98 | uchar *Reader_GetPtr(void) { | ||
99 | return reader.ptr; | ||
100 | } | ||
101 | |||
102 | uint Reader_GetSize(void) { | ||
103 | return reader.size; | ||
104 | } | ||
105 | |||
106 | /* ayumi_render */ | ||
107 | |||
108 | static int AyumiRender_LoadInfo(void *pBlock, uint size) | ||
109 | { | ||
110 | if (size < 20) | ||
111 | return 0; | ||
112 | |||
113 | Reader_Init(pBlock); | ||
114 | |||
115 | uint hdr = Reader_ReadWord(); | ||
116 | |||
117 | if (hdr == 0x7961) | ||
118 | ay.info.chiptype = VTX_CHIP_AY; | ||
119 | else if (hdr == 0x6d79) | ||
120 | ay.info.chiptype = VTX_CHIP_YM; | ||
121 | else { | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | ay.info.layout = (vtx_layout_t) | ||
126 | Reader_ReadByte(); | ||
127 | ay.info.loop = Reader_ReadWord(); | ||
128 | ay.info.chipfreq = Reader_ReadDWord(); | ||
129 | ay.info.playerfreq = Reader_ReadByte(); | ||
130 | ay.info.year = Reader_ReadWord(); | ||
131 | ay.data.regdata_size = Reader_ReadDWord(); | ||
132 | ay.info.frames = ay.data.regdata_size / 14; | ||
133 | ay.info.title = Reader_ReadString(); | ||
134 | ay.info.author = Reader_ReadString(); | ||
135 | ay.info.from = Reader_ReadString(); | ||
136 | ay.info.tracker = Reader_ReadString(); | ||
137 | ay.info.comment = Reader_ReadString(); | ||
138 | |||
139 | ay.data.lzhdata_size = size - Reader_GetSize(); | ||
140 | ay.data.lzhdata = (uchar *)codec_malloc(ay.data.lzhdata_size); | ||
141 | memcpy(ay.data.lzhdata, Reader_GetPtr(), ay.data.lzhdata_size); | ||
142 | |||
143 | return 1; | ||
144 | } | ||
145 | |||
146 | int AyumiRender_LoadFile(void *pBlock, uint size) | ||
147 | { | ||
148 | if (!AyumiRender_LoadInfo(pBlock, size)) | ||
149 | return 0; | ||
150 | |||
151 | ay.data.regdata = (uchar *)codec_malloc(ay.data.regdata_size); | ||
152 | if (ay.data.regdata == NULL) | ||
153 | return 0; | ||
154 | |||
155 | int bRet = LzUnpack(ay.data.lzhdata, ay.data.lzhdata_size, | ||
156 | ay.data.regdata, ay.data.regdata_size); | ||
157 | |||
158 | if (bRet) | ||
159 | return 0; | ||
160 | |||
161 | return 1; | ||
162 | } | ||
163 | |||
164 | const char *AyumiRender_GetChipTypeName(vtx_chiptype_t chiptype) | ||
165 | { | ||
166 | if (chiptype > VTX_CHIP_YM) | ||
167 | chiptype = (vtx_chiptype_t) (VTX_CHIP_YM + 1); | ||
168 | return chiptype_name[chiptype]; | ||
169 | } | ||
170 | |||
171 | const char *AyumiRender_GetLayoutName(vtx_layout_t layout) | ||
172 | { | ||
173 | if (layout > VTX_LAYOUT_CUSTOM) | ||
174 | layout = (vtx_layout_t) (VTX_LAYOUT_CUSTOM + 1); | ||
175 | return layout_name[layout]; | ||
176 | } | ||
177 | |||
178 | int AyumiRender_AyInit(vtx_chiptype_t chiptype, uint samplerate, | ||
179 | uint chipfreq, double playerfreq, uint dcfilter) | ||
180 | { | ||
181 | if (chiptype > VTX_CHIP_YM) | ||
182 | return 0; | ||
183 | if ((samplerate < 8000) || (samplerate > 768000)) | ||
184 | return 0; | ||
185 | if ((chipfreq < 1000000) || (chipfreq > 2000000)) | ||
186 | return 0; | ||
187 | if ((playerfreq < 1) || (playerfreq > 100)) | ||
188 | return 0; | ||
189 | |||
190 | ay.is_ym = (chiptype == VTX_CHIP_YM) ? 1 : 0; | ||
191 | ay.clock_rate = chipfreq; | ||
192 | ay.sr = samplerate; | ||
193 | |||
194 | ay.dc_filter_on = dcfilter ? 1 : 0; | ||
195 | |||
196 | ay.frame = 0; | ||
197 | ay.isr_counter = 1; | ||
198 | ay.isr_step = playerfreq / samplerate; | ||
199 | |||
200 | if (!ayumi_configure(&ay.ay, ay.is_ym, ay.clock_rate, ay.sr)) | ||
201 | return 0; | ||
202 | |||
203 | return 1; | ||
204 | } | ||
205 | |||
206 | int AyumiRender_SetLayout(vtx_layout_t layout, uint eqpower) | ||
207 | { | ||
208 | if (layout > VTX_LAYOUT_CUSTOM) | ||
209 | return 0; | ||
210 | ay.is_eqp = eqpower ? 1 : 0; | ||
211 | |||
212 | switch (layout) { | ||
213 | case VTX_LAYOUT_MONO: | ||
214 | case VTX_LAYOUT_ABC: | ||
215 | case VTX_LAYOUT_ACB: | ||
216 | case VTX_LAYOUT_BAC: | ||
217 | case VTX_LAYOUT_BCA: | ||
218 | case VTX_LAYOUT_CAB: | ||
219 | case VTX_LAYOUT_CBA: | ||
220 | for (int i = 0; i < 3; i++) | ||
221 | ay.pan[i] = default_pan[layout][i]; | ||
222 | break; | ||
223 | case VTX_LAYOUT_CUSTOM: | ||
224 | for (int i = 0; i < 3; i++) | ||
225 | ay.pan[i] = 0; // no custom layout | ||
226 | break; | ||
227 | default: | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | for (int i = 0; i < 3; i++) | ||
232 | ayumi_set_pan(&ay.ay, i, ay.pan[i], ay.is_eqp); | ||
233 | |||
234 | return 1; | ||
235 | } | ||
236 | |||
237 | uint AyumiRender_GetPos(void) | ||
238 | { | ||
239 | return ay.frame; | ||
240 | } | ||
241 | |||
242 | uint AyumiRender_GetMaxPos(void) | ||
243 | { | ||
244 | return ay.info.frames; | ||
245 | } | ||
246 | |||
247 | static void AyumiRender_UpdateAyumiState(void) | ||
248 | { | ||
249 | int r[16]; | ||
250 | |||
251 | if (ay.frame < ay.info.frames) { | ||
252 | uchar *ptr = ay.data.regdata + ay.frame; | ||
253 | for (int n = 0; n < 14; n++) { | ||
254 | r[n] = *ptr; | ||
255 | ptr += ay.info.frames; | ||
256 | } | ||
257 | } else { | ||
258 | for (int n = 0; n < 14; n++) { | ||
259 | r[n] = 0; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | ayumi_set_tone(&ay.ay, 0, (r[1] << 8) | r[0]); | ||
264 | ayumi_set_tone(&ay.ay, 1, (r[3] << 8) | r[2]); | ||
265 | ayumi_set_tone(&ay.ay, 2, (r[5] << 8) | r[4]); | ||
266 | ayumi_set_noise(&ay.ay, r[6]); | ||
267 | ayumi_set_mixer(&ay.ay, 0, r[7] & 1, (r[7] >> 3) & 1, r[8] >> 4); | ||
268 | ayumi_set_mixer(&ay.ay, 1, (r[7] >> 1) & 1, (r[7] >> 4) & 1, r[9] >> 4); | ||
269 | ayumi_set_mixer(&ay.ay, 2, (r[7] >> 2) & 1, (r[7] >> 5) & 1, r[10] >> 4); | ||
270 | ayumi_set_volume(&ay.ay, 0, r[8] & 0xf); | ||
271 | ayumi_set_volume(&ay.ay, 1, r[9] & 0xf); | ||
272 | ayumi_set_volume(&ay.ay, 2, r[10] & 0xf); | ||
273 | ayumi_set_envelope(&ay.ay, (r[12] << 8) | r[11]); | ||
274 | if (r[13] != 255) { | ||
275 | ayumi_set_envelope_shape(&ay.ay, r[13]); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | int AyumiRender_Seek(ulong nSample) | ||
280 | { | ||
281 | ulong samples = 0; | ||
282 | |||
283 | ay.frame = 0; | ||
284 | ay.isr_counter = 1; | ||
285 | |||
286 | ayumi_configure(&ay.ay, ay.is_ym, ay.clock_rate, ay.sr); | ||
287 | |||
288 | for (int i = 0; i < 3; i++) | ||
289 | ayumi_set_pan(&ay.ay, i, ay.pan[i], ay.is_eqp); | ||
290 | |||
291 | while (samples < nSample) { | ||
292 | ay.isr_counter += ay.isr_step; | ||
293 | if (ay.isr_counter >= 1) { | ||
294 | ay.isr_counter -= 1; | ||
295 | AyumiRender_UpdateAyumiState(); | ||
296 | ay.frame += 1; | ||
297 | } | ||
298 | ayumi_seek(&ay.ay); | ||
299 | samples++; | ||
300 | } | ||
301 | |||
302 | return 1; | ||
303 | } | ||
304 | |||
305 | ulong AyumiRender_AySynth(void *pBuffer, ulong nSamples) | ||
306 | { | ||
307 | ulong samples = 0; | ||
308 | short *out = (int16_t *) pBuffer; | ||
309 | |||
310 | for (ulong i = 0; i < nSamples; i++) { | ||
311 | ay.isr_counter += ay.isr_step; | ||
312 | if (ay.isr_counter >= 1) { | ||
313 | ay.isr_counter -= 1; | ||
314 | AyumiRender_UpdateAyumiState(); | ||
315 | ay.frame += 1; | ||
316 | } | ||
317 | ayumi_process(&ay.ay); | ||
318 | if (ay.dc_filter_on) { | ||
319 | ayumi_remove_dc(&ay.ay); | ||
320 | } | ||
321 | out[0] = (int16_t)(ay.ay.left * 16383); | ||
322 | out[1] = (int16_t)(ay.ay.right * 16383); | ||
323 | out += 2; | ||
324 | samples++; | ||
325 | } | ||
326 | |||
327 | return samples; | ||
328 | } | ||
diff --git a/lib/rbcodec/codecs/libayumi/ayumi_render.h b/lib/rbcodec/codecs/libayumi/ayumi_render.h new file mode 100644 index 0000000000..b09ea9fb3d --- /dev/null +++ b/lib/rbcodec/codecs/libayumi/ayumi_render.h | |||
@@ -0,0 +1,84 @@ | |||
1 | #ifndef AYUMI_RENDER_H | ||
2 | #define AYUMI_RENDER_H | ||
3 | |||
4 | #include "ayumi.h" | ||
5 | |||
6 | typedef unsigned char uchar; | ||
7 | typedef unsigned short ushort; | ||
8 | typedef unsigned int uint; | ||
9 | typedef unsigned long ulong; | ||
10 | |||
11 | typedef enum { | ||
12 | VTX_CHIP_AY = 0, /* emulate AY */ | ||
13 | VTX_CHIP_YM /* emulate YM */ | ||
14 | } vtx_chiptype_t; | ||
15 | |||
16 | typedef enum { | ||
17 | VTX_LAYOUT_MONO = 0, | ||
18 | VTX_LAYOUT_ABC, | ||
19 | VTX_LAYOUT_ACB, | ||
20 | VTX_LAYOUT_BAC, | ||
21 | VTX_LAYOUT_BCA, | ||
22 | VTX_LAYOUT_CAB, | ||
23 | VTX_LAYOUT_CBA, | ||
24 | VTX_LAYOUT_CUSTOM | ||
25 | } vtx_layout_t; | ||
26 | |||
27 | typedef struct { | ||
28 | vtx_chiptype_t chiptype; /* Type of sound chip */ | ||
29 | vtx_layout_t layout; /* stereo layout */ | ||
30 | uint loop; /* song loop */ | ||
31 | uint chipfreq; /* AY chip freq (1773400 for ZX) */ | ||
32 | uint playerfreq; /* 50 Hz for ZX, 60 Hz for yamaha */ | ||
33 | uint year; /* year song composed */ | ||
34 | char *title; /* song title */ | ||
35 | char *author; /* song author */ | ||
36 | char *from; /* song from */ | ||
37 | char *tracker; /* tracker */ | ||
38 | char *comment; /* comment */ | ||
39 | uint frames; /* number of AY data frames */ | ||
40 | } vtx_info_t; | ||
41 | |||
42 | typedef struct { | ||
43 | uchar *lzhdata; /* packed song data */ | ||
44 | uint lzhdata_size; /* size of packed data */ | ||
45 | uchar *regdata; /* unpacked song data */ | ||
46 | uint regdata_size; /* size of unpacked data */ | ||
47 | } vtx_data_t; | ||
48 | |||
49 | typedef struct { | ||
50 | uint frame; /* current frame position */ | ||
51 | double isr_step; | ||
52 | double isr_counter; | ||
53 | |||
54 | int dc_filter_on; | ||
55 | |||
56 | int is_ym; | ||
57 | double clock_rate; | ||
58 | int sr; | ||
59 | |||
60 | double pan[3]; | ||
61 | int is_eqp; | ||
62 | |||
63 | struct ayumi ay; /* ayumi structure */ | ||
64 | vtx_data_t data; /* packed & unpacked vtx data */ | ||
65 | vtx_info_t info; /* vtx info */ | ||
66 | } ayumi_render_t; | ||
67 | |||
68 | int AyumiRender_LoadFile(void *pBlock, uint size); | ||
69 | |||
70 | const char *AyumiRender_GetChipTypeName(vtx_chiptype_t chiptype); | ||
71 | const char *AyumiRender_GetLayoutName(vtx_layout_t layout); | ||
72 | |||
73 | uint AyumiRender_GetPos(void); | ||
74 | uint AyumiRender_GetMaxPos(void); | ||
75 | |||
76 | int AyumiRender_AyInit(vtx_chiptype_t chiptype, uint samplerate, uint chipfreq, | ||
77 | double playerfreq, uint dcfilter); | ||
78 | int AyumiRender_SetLayout(vtx_layout_t layout, uint eqpower); | ||
79 | |||
80 | int AyumiRender_Seek(ulong nSample); | ||
81 | |||
82 | ulong AyumiRender_AySynth(void *pBuffer, ulong nSamples); | ||
83 | |||
84 | #endif /* ifndef AYUMI_RENDER_H */ | ||
diff --git a/lib/rbcodec/codecs/libayumi/libayumi.make b/lib/rbcodec/codecs/libayumi/libayumi.make new file mode 100644 index 0000000000..029aa11a6f --- /dev/null +++ b/lib/rbcodec/codecs/libayumi/libayumi.make | |||
@@ -0,0 +1,18 @@ | |||
1 | # __________ __ ___. | ||
2 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
3 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
4 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
5 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
6 | # \/ \/ \/ \/ \/ | ||
7 | # $Id$ | ||
8 | # | ||
9 | |||
10 | # libayumi | ||
11 | AYUMILIB := $(CODECDIR)/libayumi.a | ||
12 | AYUMILIB_SRC := $(call preprocess, $(RBCODECLIB_DIR)/codecs/libayumi/SOURCES) | ||
13 | AYUMILIB_OBJ := $(call c2obj, $(AYUMILIB_SRC)) | ||
14 | OTHER_SRC += $(AYUMILIB_SRC) | ||
15 | |||
16 | $(AYUMILIB): $(AYUMILIB_OBJ) | ||
17 | $(SILENT)$(shell rm -f $@) | ||
18 | $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null | ||
diff --git a/lib/rbcodec/codecs/libayumi/lzh.c b/lib/rbcodec/codecs/libayumi/lzh.c new file mode 100644 index 0000000000..786d3bbafe --- /dev/null +++ b/lib/rbcodec/codecs/libayumi/lzh.c | |||
@@ -0,0 +1,420 @@ | |||
1 | #include "lzh.h" | ||
2 | |||
3 | #include <string.h> | ||
4 | |||
5 | #define BUFSIZE (1024 * 4) | ||
6 | |||
7 | typedef unsigned char uchar; | ||
8 | typedef unsigned short ushort; | ||
9 | typedef unsigned int uint; | ||
10 | typedef unsigned long ulong; | ||
11 | |||
12 | #ifndef CHAR_BIT | ||
13 | #define CHAR_BIT 8 | ||
14 | #endif | ||
15 | |||
16 | #ifndef UCHAR_MAX | ||
17 | #define UCHAR_MAX 255 | ||
18 | #endif | ||
19 | |||
20 | typedef ushort BITBUFTYPE; | ||
21 | |||
22 | #define BITBUFSIZ (CHAR_BIT * sizeof(BITBUFTYPE)) | ||
23 | #define DICBIT 13 /* 12(-lh4-) or 13(-lh5-) */ | ||
24 | #define DICSIZ (1U << DICBIT) | ||
25 | #define MAXMATCH 256 /* formerly F (not more than UCHAR_MAX + 1) */ | ||
26 | #define THRESHOLD 3 /* choose optimal value */ | ||
27 | #define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD) /* alphabet = {0, 1, 2, ..., NC - 1} */ | ||
28 | #define CBIT 9 /* $\lfloor \log_2 NC \rfloor + 1$ */ | ||
29 | #define CODE_BIT 16 /* codeword length */ | ||
30 | |||
31 | #define MAX_HASH_VAL (3 * DICSIZ + (DICSIZ / 512 + 1) * UCHAR_MAX) | ||
32 | |||
33 | #define NP (DICBIT + 1) | ||
34 | #define NT (CODE_BIT + 3) | ||
35 | #define PBIT 4 /* smallest integer such that (1U << PBIT) > NP */ | ||
36 | #define TBIT 5 /* smallest integer such that (1U << TBIT) > NT */ | ||
37 | #if NT > NP | ||
38 | #define NPT NT | ||
39 | #else | ||
40 | #define NPT NP | ||
41 | #endif | ||
42 | |||
43 | uchar *m_pSrc; | ||
44 | int m_srcSize; | ||
45 | uchar *m_pDst; | ||
46 | int m_dstSize; | ||
47 | |||
48 | int DataIn(void *pBuffer, int nBytes); | ||
49 | int DataOut(void *pOut, int nBytes); | ||
50 | |||
51 | void fillbuf(int n); | ||
52 | ushort getbits(int n); | ||
53 | void init_getbits(void); | ||
54 | int make_table(int nchar, uchar *bitlen, int tablebits, ushort *table); | ||
55 | void read_pt_len(int nn, int nbit, int i_special); | ||
56 | void read_c_len(void); | ||
57 | ushort decode_c(void); | ||
58 | ushort decode_p(void); | ||
59 | void huf_decode_start(void); | ||
60 | void decode_start(void); | ||
61 | void decode(uint count, uchar buffer[]); | ||
62 | |||
63 | int fillbufsize; | ||
64 | uchar buf[BUFSIZE]; | ||
65 | uchar outbuf[DICSIZ]; | ||
66 | ushort left[2 * NC - 1]; | ||
67 | ushort right[2 * NC - 1]; | ||
68 | BITBUFTYPE bitbuf; | ||
69 | uint subbitbuf; | ||
70 | int bitcount; | ||
71 | int decode_j; /* remaining bytes to copy */ | ||
72 | uchar c_len[NC]; | ||
73 | uchar pt_len[NPT]; | ||
74 | uint blocksize; | ||
75 | ushort c_table[4096]; | ||
76 | ushort pt_table[256]; | ||
77 | int with_error; | ||
78 | |||
79 | uint fillbuf_i; /* NOTE: these ones are not initialized at constructor time but inside the fillbuf and decode func. */ | ||
80 | uint decode_i; | ||
81 | |||
82 | /* Additions */ | ||
83 | |||
84 | int DataIn(void *pBuffer, int nBytes) | ||
85 | { | ||
86 | const int np = (nBytes <= m_srcSize) ? nBytes : m_srcSize; | ||
87 | if (np > 0) { | ||
88 | memcpy(pBuffer, m_pSrc, np); | ||
89 | m_pSrc += np; | ||
90 | m_srcSize -= np; | ||
91 | } | ||
92 | return np; | ||
93 | } | ||
94 | |||
95 | int DataOut(void *pBuffer, int nBytes) | ||
96 | { | ||
97 | const int np = (nBytes <= m_dstSize) ? nBytes : m_dstSize; | ||
98 | if (np > 0) { | ||
99 | memcpy(m_pDst, pBuffer, np); | ||
100 | m_pDst += np; | ||
101 | m_dstSize -= np; | ||
102 | } | ||
103 | return np; | ||
104 | } | ||
105 | |||
106 | /* io.c */ | ||
107 | |||
108 | /* Shift bitbuf n bits left, read n bits */ | ||
109 | void fillbuf(int n) | ||
110 | { | ||
111 | bitbuf = (bitbuf << n) & 0xffff; | ||
112 | while (n > bitcount) { | ||
113 | bitbuf |= subbitbuf << (n -= bitcount); | ||
114 | if (fillbufsize == 0) { | ||
115 | fillbuf_i = 0; | ||
116 | fillbufsize = DataIn(buf, BUFSIZE - 32); | ||
117 | } | ||
118 | if (fillbufsize > 0) | ||
119 | fillbufsize--, subbitbuf = buf[fillbuf_i++]; | ||
120 | else | ||
121 | subbitbuf = 0; | ||
122 | bitcount = CHAR_BIT; | ||
123 | } | ||
124 | bitbuf |= subbitbuf >> (bitcount -= n); | ||
125 | } | ||
126 | |||
127 | ushort getbits(int n) | ||
128 | { | ||
129 | ushort x; | ||
130 | x = bitbuf >> (BITBUFSIZ - n); | ||
131 | fillbuf(n); | ||
132 | return x; | ||
133 | } | ||
134 | |||
135 | void init_getbits(void) | ||
136 | { | ||
137 | bitbuf = 0; | ||
138 | subbitbuf = 0; | ||
139 | bitcount = 0; | ||
140 | fillbuf(BITBUFSIZ); | ||
141 | } | ||
142 | |||
143 | /* maketbl.c */ | ||
144 | |||
145 | int make_table(int nchar, uchar * bitlen, int tablebits, ushort * table) | ||
146 | { | ||
147 | ushort count[17], weight[17], start[18], *p; | ||
148 | uint jutbits, avail, mask; | ||
149 | int i, ch, len, nextcode; | ||
150 | |||
151 | for (i = 1; i <= 16; i++) | ||
152 | count[i] = 0; | ||
153 | for (i = 0; i < nchar; i++) | ||
154 | count[bitlen[i]]++; | ||
155 | |||
156 | start[1] = 0; | ||
157 | for (i = 1; i <= 16; i++) | ||
158 | start[i + 1] = start[i] + (count[i] << (16 - i)); | ||
159 | if (start[17] != (ushort) (1U << 16)) | ||
160 | return (1); /* error: bad table */ | ||
161 | |||
162 | jutbits = 16 - tablebits; | ||
163 | for (i = 1; i <= tablebits; i++) { | ||
164 | start[i] >>= jutbits; | ||
165 | weight[i] = 1U << (tablebits - i); | ||
166 | } | ||
167 | while (i <= 16) { | ||
168 | weight[i] = 1U << (16 - i); | ||
169 | i++; | ||
170 | } | ||
171 | |||
172 | i = start[tablebits + 1] >> jutbits; | ||
173 | if (i != (ushort) (1U << 16)) { | ||
174 | int k = 1U << tablebits; | ||
175 | while (i != k) | ||
176 | table[i++] = 0; | ||
177 | } | ||
178 | |||
179 | avail = nchar; | ||
180 | mask = 1U << (15 - tablebits); | ||
181 | for (ch = 0; ch < nchar; ch++) { | ||
182 | if ((len = bitlen[ch]) == 0) | ||
183 | continue; | ||
184 | nextcode = start[len] + weight[len]; | ||
185 | if (len <= tablebits) { | ||
186 | for (i = start[len]; i < nextcode; i++) | ||
187 | table[i] = ch; | ||
188 | } else { | ||
189 | uint k = start[len]; | ||
190 | p = &table[k >> jutbits]; | ||
191 | i = len - tablebits; | ||
192 | while (i != 0) { | ||
193 | if (*p == 0) { | ||
194 | right[avail] = left[avail] = 0; | ||
195 | *p = avail++; | ||
196 | } | ||
197 | if (k & mask) | ||
198 | p = &right[*p]; | ||
199 | else | ||
200 | p = &left[*p]; | ||
201 | k <<= 1; | ||
202 | i--; | ||
203 | } | ||
204 | *p = ch; | ||
205 | } | ||
206 | start[len] = nextcode; | ||
207 | } | ||
208 | return (0); | ||
209 | } | ||
210 | |||
211 | /* huf.c */ | ||
212 | |||
213 | void read_pt_len(int nn, int nbit, int i_special) | ||
214 | { | ||
215 | int i, n; | ||
216 | short c; | ||
217 | ushort mask; | ||
218 | |||
219 | n = getbits(nbit); | ||
220 | if (n == 0) { | ||
221 | c = getbits(nbit); | ||
222 | for (i = 0; i < nn; i++) | ||
223 | pt_len[i] = 0; | ||
224 | for (i = 0; i < 256; i++) | ||
225 | pt_table[i] = c; | ||
226 | } else { | ||
227 | i = 0; | ||
228 | while (i < n) { | ||
229 | c = bitbuf >> (BITBUFSIZ - 3); | ||
230 | if (c == 7) { | ||
231 | mask = 1U << (BITBUFSIZ - 1 - 3); | ||
232 | while (mask & bitbuf) { | ||
233 | mask >>= 1; | ||
234 | c++; | ||
235 | } | ||
236 | } | ||
237 | fillbuf((c < 7) ? 3 : c - 3); | ||
238 | pt_len[i++] = (unsigned char) (c); | ||
239 | if (i == i_special) { | ||
240 | c = getbits(2); | ||
241 | while (--c >= 0) | ||
242 | pt_len[i++] = 0; | ||
243 | } | ||
244 | } | ||
245 | while (i < nn) | ||
246 | pt_len[i++] = 0; | ||
247 | make_table(nn, pt_len, 8, pt_table); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | void read_c_len(void) | ||
252 | { | ||
253 | short i, c, n; | ||
254 | ushort mask; | ||
255 | |||
256 | n = getbits(CBIT); | ||
257 | if (n == 0) { | ||
258 | c = getbits(CBIT); | ||
259 | for (i = 0; i < NC; i++) | ||
260 | c_len[i] = 0; | ||
261 | for (i = 0; i < 4096; i++) | ||
262 | c_table[i] = c; | ||
263 | } else { | ||
264 | i = 0; | ||
265 | while (i < n) { | ||
266 | c = pt_table[bitbuf >> (BITBUFSIZ - 8)]; | ||
267 | if (c >= NT) { | ||
268 | mask = 1U << (BITBUFSIZ - 1 - 8); | ||
269 | do { | ||
270 | if (bitbuf & mask) | ||
271 | c = right[c]; | ||
272 | else | ||
273 | c = left[c]; | ||
274 | mask >>= 1; | ||
275 | } while (c >= NT); | ||
276 | } | ||
277 | fillbuf(pt_len[c]); | ||
278 | if (c <= 2) { | ||
279 | if (c == 0) | ||
280 | c = 1; | ||
281 | else if (c == 1) | ||
282 | c = getbits(4) + 3; | ||
283 | else | ||
284 | c = getbits(CBIT) + 20; | ||
285 | while (--c >= 0) | ||
286 | c_len[i++] = 0; | ||
287 | } else | ||
288 | c_len[i++] = c - 2; | ||
289 | } | ||
290 | while (i < NC) | ||
291 | c_len[i++] = 0; | ||
292 | make_table(NC, c_len, 12, c_table); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | ushort decode_c(void) | ||
297 | { | ||
298 | ushort j, mask; | ||
299 | |||
300 | if (blocksize == 0) { | ||
301 | blocksize = getbits(16); | ||
302 | read_pt_len(NT, TBIT, 3); | ||
303 | read_c_len(); | ||
304 | read_pt_len(NP, PBIT, -1); | ||
305 | } | ||
306 | blocksize--; | ||
307 | j = c_table[bitbuf >> (BITBUFSIZ - 12)]; | ||
308 | if (j >= NC) { | ||
309 | mask = 1U << (BITBUFSIZ - 1 - 12); | ||
310 | do { | ||
311 | if (bitbuf & mask) | ||
312 | j = right[j]; | ||
313 | else | ||
314 | j = left[j]; | ||
315 | mask >>= 1; | ||
316 | } | ||
317 | while (j >= NC); | ||
318 | } | ||
319 | fillbuf(c_len[j]); | ||
320 | return j; | ||
321 | } | ||
322 | |||
323 | ushort decode_p(void) | ||
324 | { | ||
325 | ushort j, mask; | ||
326 | |||
327 | j = pt_table[bitbuf >> (BITBUFSIZ - 8)]; | ||
328 | if (j >= NP) { | ||
329 | mask = 1U << (BITBUFSIZ - 1 - 8); | ||
330 | do { | ||
331 | if (bitbuf & mask) | ||
332 | j = right[j]; | ||
333 | else | ||
334 | j = left[j]; | ||
335 | mask >>= 1; | ||
336 | } while (j >= NP); | ||
337 | } | ||
338 | fillbuf(pt_len[j]); | ||
339 | if (j != 0) | ||
340 | j = (1U << (j - 1)) + getbits(j - 1); | ||
341 | return j; | ||
342 | } | ||
343 | |||
344 | void huf_decode_start(void) | ||
345 | { | ||
346 | init_getbits(); | ||
347 | blocksize = 0; | ||
348 | } | ||
349 | |||
350 | /* decode.c */ | ||
351 | |||
352 | void decode_start(void) | ||
353 | { | ||
354 | fillbufsize = 0; | ||
355 | huf_decode_start(); | ||
356 | decode_j = 0; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * The calling function must keep the number of bytes to be processed. This | ||
361 | * function decodes either 'count' bytes or 'DICSIZ' bytes, whichever is | ||
362 | * smaller, into the array 'buffer[]' of size 'DICSIZ' or more. Call | ||
363 | * decode_start() once for each new file before calling this function. | ||
364 | */ | ||
365 | void decode(uint count, uchar buffer[]) | ||
366 | { | ||
367 | uint r, c; | ||
368 | |||
369 | r = 0; | ||
370 | while (--decode_j >= 0) { | ||
371 | buffer[r] = buffer[decode_i]; | ||
372 | decode_i = (decode_i + 1) & (DICSIZ - 1); | ||
373 | if (++r == count) | ||
374 | return; | ||
375 | } | ||
376 | for (;;) { | ||
377 | c = decode_c(); | ||
378 | if (c <= UCHAR_MAX) { | ||
379 | buffer[r] = c; | ||
380 | if (++r == count) | ||
381 | return; | ||
382 | } else { | ||
383 | decode_j = c - (UCHAR_MAX + 1 - THRESHOLD); | ||
384 | decode_i = (r - decode_p() - 1) & (DICSIZ - 1); | ||
385 | while (--decode_j >= 0) { | ||
386 | buffer[r] = buffer[decode_i]; | ||
387 | decode_i = (decode_i + 1) & (DICSIZ - 1); | ||
388 | if (++r == count) | ||
389 | return; | ||
390 | } | ||
391 | } | ||
392 | } | ||
393 | } | ||
394 | |||
395 | int LzUnpack(void *pSrc, int srcSize, void *pDst, int dstSize) | ||
396 | { | ||
397 | with_error = 0; | ||
398 | |||
399 | m_pSrc = (uchar *) pSrc; | ||
400 | m_srcSize = srcSize; | ||
401 | m_pDst = (uchar *) pDst; | ||
402 | m_dstSize = dstSize; | ||
403 | |||
404 | decode_start(); | ||
405 | |||
406 | unsigned int origsize = dstSize; | ||
407 | while (origsize != 0) { | ||
408 | int n = (uint) ((origsize > DICSIZ) ? DICSIZ : origsize); | ||
409 | decode(n, outbuf); | ||
410 | if (with_error) | ||
411 | break; | ||
412 | |||
413 | DataOut(outbuf, n); | ||
414 | origsize -= n; | ||
415 | if (with_error) | ||
416 | break; | ||
417 | } | ||
418 | |||
419 | return (with_error); | ||
420 | } | ||
diff --git a/lib/rbcodec/codecs/libayumi/lzh.h b/lib/rbcodec/codecs/libayumi/lzh.h new file mode 100644 index 0000000000..5d896a56a3 --- /dev/null +++ b/lib/rbcodec/codecs/libayumi/lzh.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef LZH_H | ||
2 | #define LZH_H | ||
3 | |||
4 | int LzUnpack(void *pSrc, int srcSize, void *pDst, int dstSize); | ||
5 | |||
6 | #endif /* ifndef LZH_H */ | ||
diff --git a/lib/rbcodec/codecs/vtx.c b/lib/rbcodec/codecs/vtx.c new file mode 100644 index 0000000000..031af946b9 --- /dev/null +++ b/lib/rbcodec/codecs/vtx.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * VTX Codec for rockbox based on the Ayumi engine | ||
11 | * | ||
12 | * Ayumi engine Written by Peter Sovietov in 2015 | ||
13 | * Ported to rockbox '2019 by Roman Stolyarov | ||
14 | * | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License | ||
18 | * as published by the Free Software Foundation; either version 2 | ||
19 | * of the License, or (at your option) any later version. | ||
20 | * | ||
21 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
22 | * KIND, either express or implied. | ||
23 | * | ||
24 | ****************************************************************************/ | ||
25 | |||
26 | #include <codecs/lib/codeclib.h> | ||
27 | #include "libayumi/ayumi_render.h" | ||
28 | |||
29 | CODEC_HEADER | ||
30 | |||
31 | #define VTX_SAMPLE_RATE 44100 | ||
32 | |||
33 | /* Maximum number of bytes to process in one iteration */ | ||
34 | #define CHUNK_SIZE (1024*2) | ||
35 | |||
36 | static int16_t samples[CHUNK_SIZE] IBSS_ATTR; | ||
37 | extern ayumi_render_t ay; | ||
38 | |||
39 | /****************** rockbox interface ******************/ | ||
40 | |||
41 | /* this is the codec entry point */ | ||
42 | enum codec_status codec_main(enum codec_entry_call_reason reason) | ||
43 | { | ||
44 | if (reason == CODEC_LOAD) { | ||
45 | /* we only render 16 bits */ | ||
46 | ci->configure(DSP_SET_SAMPLE_DEPTH, 16); | ||
47 | |||
48 | /* 44 Khz, Interleaved stereo */ | ||
49 | ci->configure(DSP_SET_FREQUENCY, VTX_SAMPLE_RATE); | ||
50 | ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); | ||
51 | } | ||
52 | |||
53 | return CODEC_OK; | ||
54 | } | ||
55 | |||
56 | /* this is called for each file to process */ | ||
57 | enum codec_status codec_run(void) | ||
58 | { | ||
59 | uint8_t *buf; | ||
60 | size_t n; | ||
61 | intptr_t param; | ||
62 | uint32_t elapsed_time; | ||
63 | long smp; | ||
64 | int res; | ||
65 | |||
66 | /* reset values */ | ||
67 | elapsed_time = 0; | ||
68 | param = ci->id3->elapsed; | ||
69 | |||
70 | DEBUGF("VTX: next_track\n"); | ||
71 | if (codec_init()) { | ||
72 | return CODEC_ERROR; | ||
73 | } | ||
74 | |||
75 | codec_set_replaygain(ci->id3); | ||
76 | |||
77 | /* Read the entire file */ | ||
78 | DEBUGF("VTX: request file\n"); | ||
79 | ci->seek_buffer(0); | ||
80 | buf = ci->request_buffer(&n, ci->filesize); | ||
81 | if (!buf || n < (size_t)ci->filesize) { | ||
82 | DEBUGF("VTX: file load failed\n"); | ||
83 | return CODEC_ERROR; | ||
84 | } | ||
85 | |||
86 | res = AyumiRender_LoadFile((void *)buf, ci->filesize); | ||
87 | if (!res) { | ||
88 | DEBUGF("VTX: AyumiRender_LoadFile failed\n"); | ||
89 | return CODEC_ERROR; | ||
90 | } | ||
91 | |||
92 | res = AyumiRender_AyInit(ay.info.chiptype, VTX_SAMPLE_RATE, ay.info.chipfreq, ay.info.playerfreq, 1); | ||
93 | if (!res) { | ||
94 | DEBUGF("VTX: AyumiRender_AyInit failed\n"); | ||
95 | return CODEC_ERROR; | ||
96 | } | ||
97 | |||
98 | res = AyumiRender_SetLayout(ay.info.layout, 0); | ||
99 | if (!res) { | ||
100 | DEBUGF("VTX: AyumiRender_SetLayout failed\n"); | ||
101 | return CODEC_ERROR; | ||
102 | } | ||
103 | |||
104 | if (param) { | ||
105 | goto resume_start; | ||
106 | } | ||
107 | |||
108 | /* The main decoder loop */ | ||
109 | while (1) { | ||
110 | long action = ci->get_command(¶m); | ||
111 | |||
112 | if (action == CODEC_ACTION_HALT) | ||
113 | break; | ||
114 | |||
115 | if (action == CODEC_ACTION_SEEK_TIME) { | ||
116 | resume_start: | ||
117 | ci->set_elapsed(param); | ||
118 | elapsed_time = param; | ||
119 | ulong sample = ((ulong)elapsed_time * 441) / 10; | ||
120 | AyumiRender_Seek(sample); | ||
121 | ci->seek_complete(); | ||
122 | } | ||
123 | |||
124 | /* Generate audio buffer */ | ||
125 | smp = AyumiRender_AySynth((void *)&samples[0], CHUNK_SIZE >> 1); | ||
126 | |||
127 | ci->pcmbuf_insert(samples, NULL, smp); | ||
128 | |||
129 | /* Set elapsed time for one track files */ | ||
130 | elapsed_time += smp * 10 / 441; | ||
131 | ci->set_elapsed(elapsed_time); | ||
132 | |||
133 | if (AyumiRender_GetPos() >= AyumiRender_GetMaxPos()) | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | return CODEC_OK; | ||
138 | } | ||
diff --git a/lib/rbcodec/metadata/metadata.c b/lib/rbcodec/metadata/metadata.c index 9c41347975..aec72db97f 100644 --- a/lib/rbcodec/metadata/metadata.c +++ b/lib/rbcodec/metadata/metadata.c | |||
@@ -43,7 +43,7 @@ static bool get_shn_metadata(int fd, struct mp3entry *id3) | |||
43 | } | 43 | } |
44 | 44 | ||
45 | static bool get_other_asap_metadata(int fd, struct mp3entry *id3) | 45 | static bool get_other_asap_metadata(int fd, struct mp3entry *id3) |
46 | { | 46 | { |
47 | id3->bitrate = 706; | 47 | id3->bitrate = 706; |
48 | id3->frequency = 44100; | 48 | id3->frequency = 44100; |
49 | id3->vbr = false; | 49 | id3->vbr = false; |
@@ -85,7 +85,7 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | |||
85 | /* Musepack SV7 */ | 85 | /* Musepack SV7 */ |
86 | [AFMT_MPC_SV7] = | 86 | [AFMT_MPC_SV7] = |
87 | AFMT_ENTRY("MPCv7", "mpc", NULL, get_musepack_metadata,"mpc\0"), | 87 | AFMT_ENTRY("MPCv7", "mpc", NULL, get_musepack_metadata,"mpc\0"), |
88 | /* A/52 (aka AC3) audio */ | 88 | /* A/52 (aka AC3) audio */ |
89 | [AFMT_A52] = | 89 | [AFMT_A52] = |
90 | AFMT_ENTRY("AC3", "a52", NULL, get_a52_metadata, "a52\0ac3\0"), | 90 | AFMT_ENTRY("AC3", "a52", NULL, get_a52_metadata, "a52\0ac3\0"), |
91 | /* WavPack */ | 91 | /* WavPack */ |
@@ -109,7 +109,7 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | |||
109 | /* NESM (NES Sound Format) */ | 109 | /* NESM (NES Sound Format) */ |
110 | [AFMT_NSF] = | 110 | [AFMT_NSF] = |
111 | AFMT_ENTRY("NSF", "nsf", NULL, get_nsf_metadata, "nsf\0nsfe\0"), | 111 | AFMT_ENTRY("NSF", "nsf", NULL, get_nsf_metadata, "nsf\0nsfe\0"), |
112 | /* Speex File Format */ | 112 | /* Speex File Format */ |
113 | [AFMT_SPEEX] = | 113 | [AFMT_SPEEX] = |
114 | AFMT_ENTRY("Speex", "speex",NULL, get_ogg_metadata, "spx\0"), | 114 | AFMT_ENTRY("Speex", "speex",NULL, get_ogg_metadata, "spx\0"), |
115 | /* SPC700 Save State */ | 115 | /* SPC700 Save State */ |
@@ -162,12 +162,12 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | |||
162 | AFMT_ENTRY("DLT", "asap", NULL, get_other_asap_metadata,"dlt\0"), | 162 | AFMT_ENTRY("DLT", "asap", NULL, get_other_asap_metadata,"dlt\0"), |
163 | /* Atari MPT File */ | 163 | /* Atari MPT File */ |
164 | [AFMT_MPT] = | 164 | [AFMT_MPT] = |
165 | AFMT_ENTRY("MPT", "asap", NULL, get_other_asap_metadata,"mpt\0"), | 165 | AFMT_ENTRY("MPT", "asap", NULL, get_other_asap_metadata,"mpt\0"), |
166 | /* Atari MPD File */ | 166 | /* Atari MPD File */ |
167 | [AFMT_MPD] = | 167 | [AFMT_MPD] = |
168 | AFMT_ENTRY("MPD", "asap", NULL, get_other_asap_metadata,"mpd\0"), | 168 | AFMT_ENTRY("MPD", "asap", NULL, get_other_asap_metadata,"mpd\0"), |
169 | /* Atari RMT File */ | 169 | /* Atari RMT File */ |
170 | [AFMT_RMT] = | 170 | [AFMT_RMT] = |
171 | AFMT_ENTRY("RMT", "asap", NULL, get_other_asap_metadata,"rmt\0"), | 171 | AFMT_ENTRY("RMT", "asap", NULL, get_other_asap_metadata,"rmt\0"), |
172 | /* Atari TMC File */ | 172 | /* Atari TMC File */ |
173 | [AFMT_TMC] = | 173 | [AFMT_TMC] = |
@@ -177,10 +177,10 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | |||
177 | AFMT_ENTRY("TM8", "asap", NULL, get_other_asap_metadata,"tm8\0"), | 177 | AFMT_ENTRY("TM8", "asap", NULL, get_other_asap_metadata,"tm8\0"), |
178 | /* Atari TM2 File */ | 178 | /* Atari TM2 File */ |
179 | [AFMT_TM2] = | 179 | [AFMT_TM2] = |
180 | AFMT_ENTRY("TM2", "asap", NULL, get_other_asap_metadata,"tm2\0"), | 180 | AFMT_ENTRY("TM2", "asap", NULL, get_other_asap_metadata,"tm2\0"), |
181 | /* Atrac3 in Sony OMA Container */ | 181 | /* Atrac3 in Sony OMA Container */ |
182 | [AFMT_OMA_ATRAC3] = | 182 | [AFMT_OMA_ATRAC3] = |
183 | AFMT_ENTRY("ATRAC3","atrac3_oma",NULL, get_oma_metadata, "oma\0aa3\0"), | 183 | AFMT_ENTRY("ATRAC3","atrac3_oma",NULL, get_oma_metadata, "oma\0aa3\0"), |
184 | /* SMAF (Synthetic music Mobile Application Format) */ | 184 | /* SMAF (Synthetic music Mobile Application Format) */ |
185 | [AFMT_SMAF] = | 185 | [AFMT_SMAF] = |
186 | AFMT_ENTRY("SMAF", "smaf", NULL, get_smaf_metadata, "mmf\0"), | 186 | AFMT_ENTRY("SMAF", "smaf", NULL, get_smaf_metadata, "mmf\0"), |
@@ -194,7 +194,7 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | |||
194 | [AFMT_WAVE64] = | 194 | [AFMT_WAVE64] = |
195 | AFMT_ENTRY("WAVE64","wav64",NULL, get_wave64_metadata,"w64\0"), | 195 | AFMT_ENTRY("WAVE64","wav64",NULL, get_wave64_metadata,"w64\0"), |
196 | /* True Audio */ | 196 | /* True Audio */ |
197 | [AFMT_TTA] = | 197 | [AFMT_TTA] = |
198 | AFMT_ENTRY("TTA", "tta", NULL, get_tta_metadata, "tta\0"), | 198 | AFMT_ENTRY("TTA", "tta", NULL, get_tta_metadata, "tta\0"), |
199 | /* WMA Voice in ASF */ | 199 | /* WMA Voice in ASF */ |
200 | [AFMT_WMAVOICE] = | 200 | [AFMT_WMAVOICE] = |
@@ -206,8 +206,13 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | |||
206 | [AFMT_MP4_AAC_HE] = | 206 | [AFMT_MP4_AAC_HE] = |
207 | AFMT_ENTRY("AAC-HE","aac", NULL, get_mp4_metadata, "mp4\0"), | 207 | AFMT_ENTRY("AAC-HE","aac", NULL, get_mp4_metadata, "mp4\0"), |
208 | /* AY (ZX Spectrum, Amstrad CPC Sound Format) */ | 208 | /* AY (ZX Spectrum, Amstrad CPC Sound Format) */ |
209 | [AFMT_AY] = | 209 | [AFMT_AY] = |
210 | AFMT_ENTRY("AY", "ay", NULL, get_ay_metadata, "ay\0"), | 210 | AFMT_ENTRY("AY", "ay", NULL, get_ay_metadata, "ay\0"), |
211 | /* AY (ZX Spectrum Sound Format) */ | ||
212 | #ifdef HAVE_FPU | ||
213 | [AFMT_VTX] = | ||
214 | AFMT_ENTRY("VTX", "vtx", NULL, get_vtx_metadata, "vtx\0"), | ||
215 | #endif | ||
211 | /* GBS (Game Boy Sound Format) */ | 216 | /* GBS (Game Boy Sound Format) */ |
212 | [AFMT_GBS] = | 217 | [AFMT_GBS] = |
213 | AFMT_ENTRY("GBS", "gbs", NULL, get_gbs_metadata, "gbs\0"), | 218 | AFMT_ENTRY("GBS", "gbs", NULL, get_gbs_metadata, "gbs\0"), |
@@ -313,6 +318,9 @@ bool rbcodec_format_is_atomic(int afmt) | |||
313 | case AFMT_MOD: | 318 | case AFMT_MOD: |
314 | case AFMT_SAP: | 319 | case AFMT_SAP: |
315 | case AFMT_AY: | 320 | case AFMT_AY: |
321 | #ifdef HAVE_FPU | ||
322 | case AFMT_VTX: | ||
323 | #endif | ||
316 | case AFMT_GBS: | 324 | case AFMT_GBS: |
317 | case AFMT_HES: | 325 | case AFMT_HES: |
318 | case AFMT_SGC: | 326 | case AFMT_SGC: |
@@ -352,17 +360,17 @@ unsigned int probe_file_format(const char *filename) | |||
352 | { | 360 | { |
353 | char *suffix; | 361 | char *suffix; |
354 | unsigned int i; | 362 | unsigned int i; |
355 | 363 | ||
356 | suffix = strrchr(filename, '.'); | 364 | suffix = strrchr(filename, '.'); |
357 | 365 | ||
358 | if (suffix == NULL) | 366 | if (suffix == NULL) |
359 | { | 367 | { |
360 | return AFMT_UNKNOWN; | 368 | return AFMT_UNKNOWN; |
361 | } | 369 | } |
362 | 370 | ||
363 | /* skip '.' */ | 371 | /* skip '.' */ |
364 | suffix++; | 372 | suffix++; |
365 | 373 | ||
366 | for (i = 1; i < AFMT_NUM_CODECS; i++) | 374 | for (i = 1; i < AFMT_NUM_CODECS; i++) |
367 | { | 375 | { |
368 | /* search extension list for type */ | 376 | /* search extension list for type */ |
@@ -379,7 +387,7 @@ unsigned int probe_file_format(const char *filename) | |||
379 | } | 387 | } |
380 | while (*ext != '\0'); | 388 | while (*ext != '\0'); |
381 | } | 389 | } |
382 | 390 | ||
383 | return AFMT_UNKNOWN; | 391 | return AFMT_UNKNOWN; |
384 | } | 392 | } |
385 | 393 | ||
@@ -418,7 +426,7 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname) | |||
418 | close(logfd); | 426 | close(logfd); |
419 | } | 427 | } |
420 | } | 428 | } |
421 | 429 | ||
422 | /* Clear the mp3entry to avoid having bogus pointers appear */ | 430 | /* Clear the mp3entry to avoid having bogus pointers appear */ |
423 | wipe_mp3entry(id3); | 431 | wipe_mp3entry(id3); |
424 | 432 | ||
@@ -454,7 +462,7 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname) | |||
454 | void strip_tags(int handle_id) | 462 | void strip_tags(int handle_id) |
455 | { | 463 | { |
456 | static const unsigned char tag[] = "TAG"; | 464 | static const unsigned char tag[] = "TAG"; |
457 | static const unsigned char apetag[] = "APETAGEX"; | 465 | static const unsigned char apetag[] = "APETAGEX"; |
458 | size_t len, version; | 466 | size_t len, version; |
459 | void *tail; | 467 | void *tail; |
460 | 468 | ||
@@ -502,7 +510,7 @@ void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig) | |||
502 | MOVE_ENTRY(entry->artist) | 510 | MOVE_ENTRY(entry->artist) |
503 | MOVE_ENTRY(entry->album) | 511 | MOVE_ENTRY(entry->album) |
504 | 512 | ||
505 | if (entry->genre_string > (char*)orig && | 513 | if (entry->genre_string > (char*)orig && |
506 | entry->genre_string < (char*)orig + sizeof(struct mp3entry)) | 514 | entry->genre_string < (char*)orig + sizeof(struct mp3entry)) |
507 | /* Don't adjust that if it points to an entry of the "genres" array */ | 515 | /* Don't adjust that if it points to an entry of the "genres" array */ |
508 | entry->genre_string += offset; | 516 | entry->genre_string += offset; |
diff --git a/lib/rbcodec/metadata/metadata.h b/lib/rbcodec/metadata/metadata.h index 5c78eae9d4..fc9c1d062c 100644 --- a/lib/rbcodec/metadata/metadata.h +++ b/lib/rbcodec/metadata/metadata.h | |||
@@ -83,6 +83,9 @@ enum | |||
83 | AFMT_MPC_SV8, /* Musepack SV8 */ | 83 | AFMT_MPC_SV8, /* Musepack SV8 */ |
84 | AFMT_MP4_AAC_HE, /* Advanced Audio Coding (AAC-HE) in M4A container */ | 84 | AFMT_MP4_AAC_HE, /* Advanced Audio Coding (AAC-HE) in M4A container */ |
85 | AFMT_AY, /* AY (ZX Spectrum, Amstrad CPC Sound Format) */ | 85 | AFMT_AY, /* AY (ZX Spectrum, Amstrad CPC Sound Format) */ |
86 | #ifdef HAVE_FPU | ||
87 | AFMT_VTX, /* VTX (ZX Spectrum Sound Format) */ | ||
88 | #endif | ||
86 | AFMT_GBS, /* GBS (Game Boy Sound Format) */ | 89 | AFMT_GBS, /* GBS (Game Boy Sound Format) */ |
87 | AFMT_HES, /* HES (Hudson Entertainment System Sound Format) */ | 90 | AFMT_HES, /* HES (Hudson Entertainment System Sound Format) */ |
88 | AFMT_SGC, /* SGC (Sega Master System, Game Gear, Coleco Vision Sound Format) */ | 91 | AFMT_SGC, /* SGC (Sega Master System, Game Gear, Coleco Vision Sound Format) */ |
@@ -140,7 +143,7 @@ enum rec_format_indexes | |||
140 | REC_FORMAT_CFG_NUM_BITS = 2 | 143 | REC_FORMAT_CFG_NUM_BITS = 2 |
141 | }; | 144 | }; |
142 | 145 | ||
143 | #define REC_FORMAT_CFG_VAL_LIST "wave,aiff,wvpk,mpa3" | 146 | #define REC_FORMAT_CFG_VAL_LIST "wave,aiff,wvpk,mpa3" |
144 | 147 | ||
145 | /* get REC_FORMAT_* corresponding AFMT_* */ | 148 | /* get REC_FORMAT_* corresponding AFMT_* */ |
146 | extern const int rec_format_afmt[REC_NUM_FORMATS]; | 149 | extern const int rec_format_afmt[REC_NUM_FORMATS]; |
@@ -232,7 +235,7 @@ struct mp3entry { | |||
232 | char* comment; | 235 | char* comment; |
233 | char* albumartist; | 236 | char* albumartist; |
234 | char* grouping; | 237 | char* grouping; |
235 | int discnum; | 238 | int discnum; |
236 | int tracknum; | 239 | int tracknum; |
237 | int layer; | 240 | int layer; |
238 | int year; | 241 | int year; |
@@ -283,7 +286,7 @@ struct mp3entry { | |||
283 | 286 | ||
284 | #ifdef HAVE_TAGCACHE | 287 | #ifdef HAVE_TAGCACHE |
285 | unsigned char autoresumable; /* caches result of autoresumable() */ | 288 | unsigned char autoresumable; /* caches result of autoresumable() */ |
286 | 289 | ||
287 | /* runtime database fields */ | 290 | /* runtime database fields */ |
288 | long tagcache_idx; /* 0=invalid, otherwise idx+1 */ | 291 | long tagcache_idx; /* 0=invalid, otherwise idx+1 */ |
289 | int rating; | 292 | int rating; |
@@ -292,7 +295,7 @@ struct mp3entry { | |||
292 | long lastplayed; | 295 | long lastplayed; |
293 | long playtime; | 296 | long playtime; |
294 | #endif | 297 | #endif |
295 | 298 | ||
296 | /* replaygain support */ | 299 | /* replaygain support */ |
297 | long track_level; /* holds the level in dB * (1<<FP_BITS) */ | 300 | long track_level; /* holds the level in dB * (1<<FP_BITS) */ |
298 | long album_level; | 301 | long album_level; |
@@ -329,5 +332,3 @@ bool rbcodec_format_is_atomic(int afmt); | |||
329 | bool format_buffers_with_offset(int afmt); | 332 | bool format_buffers_with_offset(int afmt); |
330 | 333 | ||
331 | #endif | 334 | #endif |
332 | |||
333 | |||
diff --git a/lib/rbcodec/metadata/metadata_parsers.h b/lib/rbcodec/metadata/metadata_parsers.h index cc7d8a102e..6a4da51b63 100644 --- a/lib/rbcodec/metadata/metadata_parsers.h +++ b/lib/rbcodec/metadata/metadata_parsers.h | |||
@@ -49,6 +49,9 @@ bool get_vox_metadata(int fd, struct mp3entry* id3); | |||
49 | bool get_wave64_metadata(int fd, struct mp3entry* id3); | 49 | bool get_wave64_metadata(int fd, struct mp3entry* id3); |
50 | bool get_tta_metadata(int fd, struct mp3entry* id3); | 50 | bool get_tta_metadata(int fd, struct mp3entry* id3); |
51 | bool get_ay_metadata(int fd, struct mp3entry* id3); | 51 | bool get_ay_metadata(int fd, struct mp3entry* id3); |
52 | #ifdef HAVE_FPU | ||
53 | bool get_vtx_metadata(int fd, struct mp3entry* id3); | ||
54 | #endif | ||
52 | bool get_gbs_metadata(int fd, struct mp3entry* id3); | 55 | bool get_gbs_metadata(int fd, struct mp3entry* id3); |
53 | bool get_hes_metadata(int fd, struct mp3entry* id3); | 56 | bool get_hes_metadata(int fd, struct mp3entry* id3); |
54 | bool get_sgc_metadata(int fd, struct mp3entry* id3); | 57 | bool get_sgc_metadata(int fd, struct mp3entry* id3); |
diff --git a/lib/rbcodec/metadata/vtx.c b/lib/rbcodec/metadata/vtx.c new file mode 100644 index 0000000000..eb06528b29 --- /dev/null +++ b/lib/rbcodec/metadata/vtx.c | |||
@@ -0,0 +1,150 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <string.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <ctype.h> | ||
5 | #include <inttypes.h> | ||
6 | #include "platform.h" | ||
7 | |||
8 | #include "metadata.h" | ||
9 | #include "metadata_common.h" | ||
10 | #include "metadata_parsers.h" | ||
11 | #include "rbunicode.h" | ||
12 | #include "string-extra.h" | ||
13 | |||
14 | typedef unsigned char uchar; | ||
15 | typedef unsigned short ushort; | ||
16 | typedef unsigned int uint; | ||
17 | typedef unsigned long ulong; | ||
18 | |||
19 | typedef enum { | ||
20 | VTX_CHIP_AY = 0, /* emulate AY */ | ||
21 | VTX_CHIP_YM /* emulate YM */ | ||
22 | } vtx_chiptype_t; | ||
23 | |||
24 | typedef enum { | ||
25 | VTX_LAYOUT_MONO = 0, | ||
26 | VTX_LAYOUT_ABC, | ||
27 | VTX_LAYOUT_ACB, | ||
28 | VTX_LAYOUT_BAC, | ||
29 | VTX_LAYOUT_BCA, | ||
30 | VTX_LAYOUT_CAB, | ||
31 | VTX_LAYOUT_CBA, | ||
32 | VTX_LAYOUT_CUSTOM | ||
33 | } vtx_layout_t; | ||
34 | |||
35 | typedef struct { | ||
36 | vtx_chiptype_t chiptype; /* Type of sound chip */ | ||
37 | vtx_layout_t layout; /* stereo layout */ | ||
38 | uint loop; /* song loop */ | ||
39 | uint chipfreq; /* AY chip freq (1773400 for ZX) */ | ||
40 | uint playerfreq; /* 50 Hz for ZX, 60 Hz for yamaha */ | ||
41 | uint year; /* year song composed */ | ||
42 | char *title; /* song title */ | ||
43 | char *author; /* song author */ | ||
44 | char *from; /* song from */ | ||
45 | char *tracker; /* tracker */ | ||
46 | char *comment; /* comment */ | ||
47 | uint regdata_size; /* size of unpacked data */ | ||
48 | uint frames; /* number of AY data frames */ | ||
49 | } vtx_info_t; | ||
50 | |||
51 | #define VTX_STRING_MAX 254 | ||
52 | |||
53 | static uint Reader_ReadByte(int fd) { | ||
54 | unsigned char c; | ||
55 | read(fd, &c, sizeof(c)); | ||
56 | return c; | ||
57 | } | ||
58 | |||
59 | static uint Reader_ReadWord(int fd) { | ||
60 | unsigned short s; | ||
61 | read(fd, &s, sizeof(s)); | ||
62 | return letoh16(s); | ||
63 | } | ||
64 | |||
65 | static uint Reader_ReadDWord(int fd) { | ||
66 | unsigned int i; | ||
67 | read(fd, &i, sizeof(i)); | ||
68 | return letoh32(i); | ||
69 | } | ||
70 | |||
71 | static char* Reader_ReadString(int fd, char *str) { | ||
72 | int i = 0; | ||
73 | char c = 1; | ||
74 | char *p = str; | ||
75 | |||
76 | if (str) | ||
77 | *str = 0; | ||
78 | |||
79 | while (i < VTX_STRING_MAX && c) { | ||
80 | read(fd, &c, sizeof(c)); | ||
81 | if (str) | ||
82 | *str++ = c; | ||
83 | i++; | ||
84 | } | ||
85 | |||
86 | if (str) | ||
87 | *str = 0; | ||
88 | |||
89 | return p; | ||
90 | } | ||
91 | |||
92 | /* vtx info */ | ||
93 | |||
94 | bool get_vtx_metadata(int fd, struct mp3entry* id3) | ||
95 | { | ||
96 | vtx_info_t info; | ||
97 | char *p = id3->id3v2buf; | ||
98 | char buf[VTX_STRING_MAX+1]; | ||
99 | |||
100 | if (lseek(fd, 0, SEEK_SET) < 0) | ||
101 | goto exit_bad; | ||
102 | |||
103 | if (filesize(fd) < 20) | ||
104 | goto exit_bad; | ||
105 | |||
106 | uint hdr = Reader_ReadWord(fd); | ||
107 | |||
108 | if ((hdr != 0x7961) && (hdr != 0x6d79)) | ||
109 | goto exit_bad; | ||
110 | |||
111 | info.layout = (vtx_layout_t)Reader_ReadByte(fd); | ||
112 | info.loop = Reader_ReadWord(fd); | ||
113 | info.chipfreq = Reader_ReadDWord(fd); | ||
114 | info.playerfreq = Reader_ReadByte(fd); | ||
115 | info.year = Reader_ReadWord(fd); | ||
116 | info.regdata_size = Reader_ReadDWord(fd); | ||
117 | info.frames = info.regdata_size / 14; | ||
118 | info.title = Reader_ReadString(fd, buf); | ||
119 | if (buf[0]) { | ||
120 | /* Title */ | ||
121 | id3->title = p; | ||
122 | p += strlcpy(p, info.title, VTX_STRING_MAX) + 1; | ||
123 | } | ||
124 | info.author = Reader_ReadString(fd, buf); | ||
125 | if (buf[0]) { | ||
126 | /* Artist */ | ||
127 | id3->artist = p; | ||
128 | p += strlcpy(p, info.author, VTX_STRING_MAX) + 1; | ||
129 | } | ||
130 | info.from = Reader_ReadString(fd, NULL); | ||
131 | info.tracker = Reader_ReadString(fd, NULL); | ||
132 | info.comment = Reader_ReadString(fd, buf); | ||
133 | if (buf[0]) { | ||
134 | /* Comment */ | ||
135 | id3->comment = p; | ||
136 | p += strlcpy(p, info.comment, VTX_STRING_MAX) + 1; | ||
137 | } | ||
138 | |||
139 | id3->vbr = false; | ||
140 | id3->bitrate = 706; | ||
141 | id3->frequency = 44100; // XXX allow this to be configured? | ||
142 | |||
143 | id3->filesize = filesize(fd); | ||
144 | id3->length = info.frames * 1000 / info.playerfreq; | ||
145 | |||
146 | return true; | ||
147 | |||
148 | exit_bad: | ||
149 | return false; | ||
150 | } | ||