summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2020-09-26 17:19:07 -0400
committerSolomon Peachy <pizza@shaftnet.org>2020-10-09 11:39:25 -0400
commit4231c2c83f2b5331e3e38b10a308ee3752315f9c (patch)
tree1e14867e9c9f0d7b778e7c4c18103a7cbd491794
parent278522f8118bd2cfce065ec95f0a93ca53e3ca44 (diff)
downloadrockbox-4231c2c83f2b5331e3e38b10a308ee3752315f9c.tar.gz
rockbox-4231c2c83f2b5331e3e38b10a308ee3752315f9c.zip
codecs: Add support for the 'VTX' ZX Spectrum chiptunes format.
This codec requires floating point. Original author: Peter Sovietov Ported to Rockbox: Roman Skylarov Further integration and bugfixes: Solomon Peachy Change-Id: I781ecd3592dfcdbbc694063334350342534f1d6c
-rw-r--r--apps/filetypes.c1
-rw-r--r--apps/plugins/sdl/sdl.make5
-rw-r--r--firmware/export/config/agptekrocker.h2
-rw-r--r--firmware/export/config/android.h4
-rw-r--r--firmware/export/config/gigabeats.h2
-rw-r--r--firmware/export/config/ibassodx50.h4
-rw-r--r--firmware/export/config/ibassodx90.h4
-rw-r--r--firmware/export/config/nokian8xx.h2
-rw-r--r--firmware/export/config/nokian900.h3
-rw-r--r--firmware/export/config/sdlapp.h1
-rw-r--r--firmware/export/config/xduoox20.h2
-rw-r--r--firmware/export/config/xduoox3ii.h2
-rw-r--r--lib/rbcodec/SOURCES3
-rw-r--r--lib/rbcodec/codecs/SOURCES3
-rw-r--r--lib/rbcodec/codecs/codecs.make3
-rw-r--r--lib/rbcodec/codecs/libayumi/SOURCES5
-rw-r--r--lib/rbcodec/codecs/libayumi/ayumi.c361
-rw-r--r--lib/rbcodec/codecs/libayumi/ayumi.h72
-rw-r--r--lib/rbcodec/codecs/libayumi/ayumi_render.c328
-rw-r--r--lib/rbcodec/codecs/libayumi/ayumi_render.h84
-rw-r--r--lib/rbcodec/codecs/libayumi/libayumi.make18
-rw-r--r--lib/rbcodec/codecs/libayumi/lzh.c420
-rw-r--r--lib/rbcodec/codecs/libayumi/lzh.h6
-rw-r--r--lib/rbcodec/codecs/vtx.c138
-rw-r--r--lib/rbcodec/metadata/metadata.c40
-rw-r--r--lib/rbcodec/metadata/metadata.h13
-rw-r--r--lib/rbcodec/metadata/metadata_parsers.h3
-rw-r--r--lib/rbcodec/metadata/vtx.c150
-rwxr-xr-xtools/configure4
29 files changed, 1642 insertions, 41 deletions
diff --git a/apps/filetypes.c b/apps/filetypes.c
index 391412b172..280cd8c4b4 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -104,6 +104,7 @@ static const struct filetype inbuilt_filetypes[] = {
104 { "w64", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 104 { "w64", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
105 { "tta", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 105 { "tta", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
106 { "ay", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 106 { "ay", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
107 { "vtx", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
107 { "gbs", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 108 { "gbs", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
108 { "hes", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 109 { "hes", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
109 { "sgc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 110 { "sgc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
diff --git a/apps/plugins/sdl/sdl.make b/apps/plugins/sdl/sdl.make
index 4e7e518fc1..194d609fb8 100644
--- a/apps/plugins/sdl/sdl.make
+++ b/apps/plugins/sdl/sdl.make
@@ -39,11 +39,6 @@ SDLFLAGS = -I$(SDL_SRCDIR)/include $(filter-out -O%,$(PLUGINFLAGS)) \
39#-ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations \ 39#-ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations \
40#-D_GNU_SOURCE=1 -D_REENTRANT -DSDL -DELF 40#-D_GNU_SOURCE=1 -D_REENTRANT -DSDL -DELF
41 41
42# use FPU on ARMv6
43ifeq ($(ARCH_VERSION),6)
44 SDLFLAGS += -mfloat-abi=softfp
45endif
46
47ifndef APP_TYPE 42ifndef APP_TYPE
48 ### no target has a big enough plugin buffer 43 ### no target has a big enough plugin buffer
49 ROCKS += $(SDL_OBJDIR)/duke3d.ovl 44 ROCKS += $(SDL_OBJDIR)/duke3d.ovl
diff --git a/firmware/export/config/agptekrocker.h b/firmware/export/config/agptekrocker.h
index c688513137..749786dff1 100644
--- a/firmware/export/config/agptekrocker.h
+++ b/firmware/export/config/agptekrocker.h
@@ -17,6 +17,8 @@
17#define CONFIG_PLATFORM (PLATFORM_HOSTED) 17#define CONFIG_PLATFORM (PLATFORM_HOSTED)
18#endif 18#endif
19 19
20#define HAVE_FPU
21
20/* define this if you have a colour LCD */ 22/* define this if you have a colour LCD */
21#define HAVE_LCD_COLOR 23#define HAVE_LCD_COLOR
22 24
diff --git a/firmware/export/config/android.h b/firmware/export/config/android.h
index 8f91d21845..7d3355ef9d 100644
--- a/firmware/export/config/android.h
+++ b/firmware/export/config/android.h
@@ -4,6 +4,7 @@
4 4
5/* We don't run on hardware directly */ 5/* We don't run on hardware directly */
6#define CONFIG_PLATFORM (PLATFORM_HOSTED|PLATFORM_ANDROID) 6#define CONFIG_PLATFORM (PLATFORM_HOSTED|PLATFORM_ANDROID)
7#define HAVE_FPU
7 8
8/* For Rolo and boot loader */ 9/* For Rolo and boot loader */
9#define MODEL_NUMBER 100 10#define MODEL_NUMBER 100
@@ -12,9 +13,6 @@
12 13
13#define USB_NONE 14#define USB_NONE
14 15
15
16
17
18/* define this if you have a colour LCD */ 16/* define this if you have a colour LCD */
19#define HAVE_LCD_COLOR 17#define HAVE_LCD_COLOR
20 18
diff --git a/firmware/export/config/gigabeats.h b/firmware/export/config/gigabeats.h
index ba71c5a400..8d82b44065 100644
--- a/firmware/export/config/gigabeats.h
+++ b/firmware/export/config/gigabeats.h
@@ -153,6 +153,8 @@
153 153
154#define CONFIG_CPU IMX31L 154#define CONFIG_CPU IMX31L
155 155
156#define HAVE_FPU
157
156/* Define this if you want to use imx31l's i2c interface */ 158/* Define this if you want to use imx31l's i2c interface */
157#define CONFIG_I2C I2C_IMX31L 159#define CONFIG_I2C I2C_IMX31L
158 160
diff --git a/firmware/export/config/ibassodx50.h b/firmware/export/config/ibassodx50.h
index 05e8aa9213..4107fd496f 100644
--- a/firmware/export/config/ibassodx50.h
+++ b/firmware/export/config/ibassodx50.h
@@ -25,6 +25,7 @@
25 25
26/* We don't run on hardware directly */ 26/* We don't run on hardware directly */
27#define CONFIG_PLATFORM PLATFORM_HOSTED 27#define CONFIG_PLATFORM PLATFORM_HOSTED
28#define HAVE_FPU
28 29
29/* For Rolo and boot loader */ 30/* For Rolo and boot loader */
30#define MODEL_NUMBER 94 31#define MODEL_NUMBER 94
@@ -33,9 +34,6 @@
33 34
34#define USB_NONE 35#define USB_NONE
35 36
36
37
38
39/* define this if you have a colour LCD */ 37/* define this if you have a colour LCD */
40#define HAVE_LCD_COLOR 38#define HAVE_LCD_COLOR
41 39
diff --git a/firmware/export/config/ibassodx90.h b/firmware/export/config/ibassodx90.h
index 1e2a1be062..ae5a446aa3 100644
--- a/firmware/export/config/ibassodx90.h
+++ b/firmware/export/config/ibassodx90.h
@@ -25,6 +25,7 @@
25 25
26/* We don't run on hardware directly */ 26/* We don't run on hardware directly */
27#define CONFIG_PLATFORM PLATFORM_HOSTED 27#define CONFIG_PLATFORM PLATFORM_HOSTED
28#define HAVE_FPU
28 29
29/* For Rolo and boot loader */ 30/* For Rolo and boot loader */
30#define MODEL_NUMBER 95 31#define MODEL_NUMBER 95
@@ -33,9 +34,6 @@
33 34
34#define USB_NONE 35#define USB_NONE
35 36
36
37
38
39/* define this if you have a colour LCD */ 37/* define this if you have a colour LCD */
40#define HAVE_LCD_COLOR 38#define HAVE_LCD_COLOR
41 39
diff --git a/firmware/export/config/nokian8xx.h b/firmware/export/config/nokian8xx.h
index c1585251e8..550ee112d1 100644
--- a/firmware/export/config/nokian8xx.h
+++ b/firmware/export/config/nokian8xx.h
@@ -12,7 +12,7 @@
12 12
13#define USB_NONE 13#define USB_NONE
14 14
15 15#define HAVE_FPU
16 16
17 17
18/* define this if you have a colour LCD */ 18/* define this if you have a colour LCD */
diff --git a/firmware/export/config/nokian900.h b/firmware/export/config/nokian900.h
index 1050763623..ebbe5e2cc8 100644
--- a/firmware/export/config/nokian900.h
+++ b/firmware/export/config/nokian900.h
@@ -12,8 +12,7 @@
12 12
13#define USB_NONE 13#define USB_NONE
14 14
15 15#define HAVE_FPU
16
17 16
18/* define this if you have a colour LCD */ 17/* define this if you have a colour LCD */
19#define HAVE_LCD_COLOR 18#define HAVE_LCD_COLOR
diff --git a/firmware/export/config/sdlapp.h b/firmware/export/config/sdlapp.h
index 038e1d8c8e..d8c1266f51 100644
--- a/firmware/export/config/sdlapp.h
+++ b/firmware/export/config/sdlapp.h
@@ -4,6 +4,7 @@
4 4
5/* We don't run on hardware directly */ 5/* We don't run on hardware directly */
6#define CONFIG_PLATFORM (PLATFORM_HOSTED|PLATFORM_SDL) 6#define CONFIG_PLATFORM (PLATFORM_HOSTED|PLATFORM_SDL)
7#define HAVE_FPU
7 8
8/* For Rolo and boot loader */ 9/* For Rolo and boot loader */
9#define MODEL_NUMBER 100 10#define MODEL_NUMBER 100
diff --git a/firmware/export/config/xduoox20.h b/firmware/export/config/xduoox20.h
index 62b2d58582..1852027cf0 100644
--- a/firmware/export/config/xduoox20.h
+++ b/firmware/export/config/xduoox20.h
@@ -17,6 +17,8 @@
17#define CONFIG_PLATFORM (PLATFORM_HOSTED) 17#define CONFIG_PLATFORM (PLATFORM_HOSTED)
18#endif 18#endif
19 19
20#define HAVE_FPU
21
20/* define this if you have a colour LCD */ 22/* define this if you have a colour LCD */
21#define HAVE_LCD_COLOR 23#define HAVE_LCD_COLOR
22 24
diff --git a/firmware/export/config/xduoox3ii.h b/firmware/export/config/xduoox3ii.h
index 893fcc5e51..dab7c0f257 100644
--- a/firmware/export/config/xduoox3ii.h
+++ b/firmware/export/config/xduoox3ii.h
@@ -17,6 +17,8 @@
17#define CONFIG_PLATFORM (PLATFORM_HOSTED) 17#define CONFIG_PLATFORM (PLATFORM_HOSTED)
18#endif 18#endif
19 19
20#define HAVE_FPU
21
20/* define this if you have a colour LCD */ 22/* define this if you have a colour LCD */
21#define HAVE_LCD_COLOR 23#define HAVE_LCD_COLOR
22 24
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
40metadata/asf.c 40metadata/asf.c
41metadata/au.c 41metadata/au.c
42metadata/ay.c 42metadata/ay.c
43#ifdef HAVE_FPU
44metadata/vtx.c
45#endif
43metadata/flac.c 46metadata/flac.c
44metadata/gbs.c 47metadata/gbs.c
45metadata/hes.c 48metadata/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
34tta.c 34tta.c
35wmapro.c 35wmapro.c
36ay.c 36ay.c
37#ifdef HAVE_FPU
38vtx.c
39#endif
37gbs.c 40gbs.c
38hes.c 41hes.c
39nsf.c 42nsf.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
39include $(RBCODECLIB_DIR)/codecs/libalac/libalac.make 39include $(RBCODECLIB_DIR)/codecs/libalac/libalac.make
40include $(RBCODECLIB_DIR)/codecs/libasap/libasap.make 40include $(RBCODECLIB_DIR)/codecs/libasap/libasap.make
41include $(RBCODECLIB_DIR)/codecs/libasf/libasf.make 41include $(RBCODECLIB_DIR)/codecs/libasf/libasf.make
42include $(RBCODECLIB_DIR)/codecs/libayumi/libayumi.make
42include $(RBCODECLIB_DIR)/codecs/libfaad/libfaad.make 43include $(RBCODECLIB_DIR)/codecs/libfaad/libfaad.make
43include $(RBCODECLIB_DIR)/codecs/libffmpegFLAC/libffmpegFLAC.make 44include $(RBCODECLIB_DIR)/codecs/libffmpegFLAC/libffmpegFLAC.make
44include $(RBCODECLIB_DIR)/codecs/libm4a/libm4a.make 45include $(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
2ayumi_render.c
3ayumi.c
4lzh.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
7static 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
26static 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
45static void reset_segment(struct ayumi* ay);
46
47double 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
60static 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
70static 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
81static 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
89static 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
97static void hold_top(struct ayumi* ay) {
98 (void) ay;
99}
100
101static void hold_bottom(struct ayumi* ay) {
102 (void) ay;
103}
104
105static 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
124static 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
133int 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
142static 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
157int 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
170void 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
180void ayumi_set_tone(struct ayumi* ay, int index, int period) {
181 period &= 0xfff;
182 ay->channels[index].tone_period = (period == 0) | period;
183}
184
185void ayumi_set_noise(struct ayumi* ay, int period) {
186 ay->noise_period = period & 0x1f;
187}
188
189void 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
195void ayumi_set_volume(struct ayumi* ay, int index, int volume) {
196 ay->channels[index].volume = volume & 0xf;
197}
198
199void ayumi_set_envelope(struct ayumi* ay, int period) {
200 period &= 0xffff;
201 ay->envelope_period = (period == 0) | period;
202}
203
204void 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
211static 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
301void 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
340void 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
351static 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
357void 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
6enum {
7 TONE_CHANNELS = 3,
8 DECIMATE_FACTOR = 8,
9 FIR_SIZE = 192,
10 DC_FILTER_SIZE = 1024
11};
12
13struct 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
25struct interpolator {
26 double c[4];
27 double y[4];
28};
29
30struct dc_filter {
31 double sum;
32 double delay[DC_FILTER_SIZE];
33};
34
35struct 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
60int ayumi_configure(struct ayumi* ay, int is_ym, double clock_rate, int sr);
61void ayumi_set_pan(struct ayumi* ay, int index, double pan, int is_eqp);
62void ayumi_set_tone(struct ayumi* ay, int index, int period);
63void ayumi_set_noise(struct ayumi* ay, int period);
64void ayumi_set_mixer(struct ayumi* ay, int index, int t_off, int n_off, int e_on);
65void ayumi_set_volume(struct ayumi* ay, int index, int volume);
66void ayumi_set_envelope(struct ayumi* ay, int period);
67void ayumi_set_envelope_shape(struct ayumi* ay, int shape);
68void ayumi_process(struct ayumi* ay);
69void ayumi_seek(struct ayumi* ay);
70void 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
11ayumi_render_t ay;
12
13/* default panning settings, 7 stereo types */
14static 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
26static const char *chiptype_name[3] = {
27 "AY-3-8910",
28 "YM2149",
29 "Unknown"
30};
31
32static 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
48typedef struct {
49 uchar *ptr;
50 uint size;
51} reader_t;
52
53reader_t reader;
54
55void Reader_Init(void *pBlock) {
56 reader.ptr = (uchar *) pBlock;
57 reader.size = 0;
58}
59
60uint Reader_ReadByte(void) {
61 uint res;
62 res = *reader.ptr++;
63 reader.size += 1;
64 return res;
65}
66
67uint Reader_ReadWord(void) {
68 uint res;
69 res = *reader.ptr++;
70 res += *reader.ptr++ << 8;
71 reader.size += 2;
72 return res;
73}
74
75uint 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
85char *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
98uchar *Reader_GetPtr(void) {
99 return reader.ptr;
100}
101
102uint Reader_GetSize(void) {
103 return reader.size;
104}
105
106/* ayumi_render */
107
108static 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
146int 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
164const 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
171const 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
178int 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
206int 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
237uint AyumiRender_GetPos(void)
238{
239 return ay.frame;
240}
241
242uint AyumiRender_GetMaxPos(void)
243{
244 return ay.info.frames;
245}
246
247static 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
279int 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
305ulong 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
6typedef unsigned char uchar;
7typedef unsigned short ushort;
8typedef unsigned int uint;
9typedef unsigned long ulong;
10
11typedef enum {
12 VTX_CHIP_AY = 0, /* emulate AY */
13 VTX_CHIP_YM /* emulate YM */
14} vtx_chiptype_t;
15
16typedef 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
27typedef 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
42typedef 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
49typedef 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
68int AyumiRender_LoadFile(void *pBlock, uint size);
69
70const char *AyumiRender_GetChipTypeName(vtx_chiptype_t chiptype);
71const char *AyumiRender_GetLayoutName(vtx_layout_t layout);
72
73uint AyumiRender_GetPos(void);
74uint AyumiRender_GetMaxPos(void);
75
76int AyumiRender_AyInit(vtx_chiptype_t chiptype, uint samplerate, uint chipfreq,
77 double playerfreq, uint dcfilter);
78int AyumiRender_SetLayout(vtx_layout_t layout, uint eqpower);
79
80int AyumiRender_Seek(ulong nSample);
81
82ulong 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
11AYUMILIB := $(CODECDIR)/libayumi.a
12AYUMILIB_SRC := $(call preprocess, $(RBCODECLIB_DIR)/codecs/libayumi/SOURCES)
13AYUMILIB_OBJ := $(call c2obj, $(AYUMILIB_SRC))
14OTHER_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
7typedef unsigned char uchar;
8typedef unsigned short ushort;
9typedef unsigned int uint;
10typedef 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
20typedef 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
43uchar *m_pSrc;
44int m_srcSize;
45uchar *m_pDst;
46int m_dstSize;
47
48int DataIn(void *pBuffer, int nBytes);
49int DataOut(void *pOut, int nBytes);
50
51void fillbuf(int n);
52ushort getbits(int n);
53void init_getbits(void);
54int make_table(int nchar, uchar *bitlen, int tablebits, ushort *table);
55void read_pt_len(int nn, int nbit, int i_special);
56void read_c_len(void);
57ushort decode_c(void);
58ushort decode_p(void);
59void huf_decode_start(void);
60void decode_start(void);
61void decode(uint count, uchar buffer[]);
62
63int fillbufsize;
64uchar buf[BUFSIZE];
65uchar outbuf[DICSIZ];
66ushort left[2 * NC - 1];
67ushort right[2 * NC - 1];
68BITBUFTYPE bitbuf;
69uint subbitbuf;
70int bitcount;
71int decode_j; /* remaining bytes to copy */
72uchar c_len[NC];
73uchar pt_len[NPT];
74uint blocksize;
75ushort c_table[4096];
76ushort pt_table[256];
77int with_error;
78
79uint fillbuf_i; /* NOTE: these ones are not initialized at constructor time but inside the fillbuf and decode func. */
80uint decode_i;
81
82/* Additions */
83
84int 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
95int 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 */
109void 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
127ushort getbits(int n)
128{
129 ushort x;
130 x = bitbuf >> (BITBUFSIZ - n);
131 fillbuf(n);
132 return x;
133}
134
135void init_getbits(void)
136{
137 bitbuf = 0;
138 subbitbuf = 0;
139 bitcount = 0;
140 fillbuf(BITBUFSIZ);
141}
142
143/* maketbl.c */
144
145int 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
213void 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
251void 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
296ushort 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
323ushort 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
344void huf_decode_start(void)
345{
346 init_getbits();
347 blocksize = 0;
348}
349
350/* decode.c */
351
352void 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 */
365void 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
395int 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
4int 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
29CODEC_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
36static int16_t samples[CHUNK_SIZE] IBSS_ATTR;
37extern ayumi_render_t ay;
38
39/****************** rockbox interface ******************/
40
41/* this is the codec entry point */
42enum 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 */
57enum 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(&param);
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
45static bool get_other_asap_metadata(int fd, struct mp3entry *id3) 45static 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)
454void strip_tags(int handle_id) 462void 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_* */
146extern const int rec_format_afmt[REC_NUM_FORMATS]; 149extern 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);
329bool format_buffers_with_offset(int afmt); 332bool 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);
49bool get_wave64_metadata(int fd, struct mp3entry* id3); 49bool get_wave64_metadata(int fd, struct mp3entry* id3);
50bool get_tta_metadata(int fd, struct mp3entry* id3); 50bool get_tta_metadata(int fd, struct mp3entry* id3);
51bool get_ay_metadata(int fd, struct mp3entry* id3); 51bool get_ay_metadata(int fd, struct mp3entry* id3);
52#ifdef HAVE_FPU
53bool get_vtx_metadata(int fd, struct mp3entry* id3);
54#endif
52bool get_gbs_metadata(int fd, struct mp3entry* id3); 55bool get_gbs_metadata(int fd, struct mp3entry* id3);
53bool get_hes_metadata(int fd, struct mp3entry* id3); 56bool get_hes_metadata(int fd, struct mp3entry* id3);
54bool get_sgc_metadata(int fd, struct mp3entry* id3); 57bool 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
14typedef unsigned char uchar;
15typedef unsigned short ushort;
16typedef unsigned int uint;
17typedef unsigned long ulong;
18
19typedef enum {
20 VTX_CHIP_AY = 0, /* emulate AY */
21 VTX_CHIP_YM /* emulate YM */
22} vtx_chiptype_t;
23
24typedef 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
35typedef 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
53static uint Reader_ReadByte(int fd) {
54 unsigned char c;
55 read(fd, &c, sizeof(c));
56 return c;
57}
58
59static uint Reader_ReadWord(int fd) {
60 unsigned short s;
61 read(fd, &s, sizeof(s));
62 return letoh16(s);
63}
64
65static uint Reader_ReadDWord(int fd) {
66 unsigned int i;
67 read(fd, &i, sizeof(i));
68 return letoh32(i);
69}
70
71static 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
94bool 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
148exit_bad:
149 return false;
150}
diff --git a/tools/configure b/tools/configure
index 2b29a3d784..9e29d84ed8 100755
--- a/tools/configure
+++ b/tools/configure
@@ -556,7 +556,7 @@ arm926ejscc () {
556 556
557arm1136jfscc () { 557arm1136jfscc () {
558 findarmgcc 558 findarmgcc
559 GCCOPTS="$CCOPTS -mcpu=arm1136jf-s" 559 GCCOPTS="$CCOPTS -mcpu=arm1136jf-s -mfloat-abi=softfp"
560 GCCOPTIMIZE="-fomit-frame-pointer" 560 GCCOPTIMIZE="-fomit-frame-pointer"
561 endian="little" 561 endian="little"
562} 562}
@@ -890,7 +890,7 @@ androidndkcc()
890 890
891mipsellinuxcc () { 891mipsellinuxcc () {
892 GCCOPTS=`echo $CCOPTS | sed -e s/-ffreestanding// -e s/-nostdlib//` 892 GCCOPTS=`echo $CCOPTS | sed -e s/-ffreestanding// -e s/-nostdlib//`
893 GCCOPTS="$GCCOPTS -march=mips32r2 -mno-mips16 -mno-long-calls -Umips -fPIC" 893 GCCOPTS="$GCCOPTS -march=mips32r2 -mhard-float -mno-mips16 -mno-long-calls -Umips -fPIC"
894 GCCOPTIMIZE='' 894 GCCOPTIMIZE=''
895 LDOPTS="-lasound -lpthread -lm -ldl -lrt $LDOPTS" 895 LDOPTS="-lasound -lpthread -lm -ldl -lrt $LDOPTS"
896 GLOBAL_LDOPTS="$GLOBAL_LDOPTS -Wl,-z,defs" 896 GLOBAL_LDOPTS="$GLOBAL_LDOPTS -Wl,-z,defs"