summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndree Buschmann <AndreeBuschmann@t-online.de>2011-08-07 20:01:04 +0000
committerAndree Buschmann <AndreeBuschmann@t-online.de>2011-08-07 20:01:04 +0000
commitacb0917556fc33681c1df5a530cf754193e67705 (patch)
tree052a47097009a210e4aed9c207bd6aa4828cc000
parent93c6f1329a5691a8be158cefe15641bd1daf9ef8 (diff)
downloadrockbox-acb0917556fc33681c1df5a530cf754193e67705.tar.gz
rockbox-acb0917556fc33681c1df5a530cf754193e67705.zip
Submit initial patch from FS#12176. Adds support for several new game music formats (AY, GBS, HES, KSS, SGC, VGM and VGZ) and replaces the current NSF and NSFE with a new implementation based on a port of the Game Music Emu library 'GME'. This first submit does not cover the full functionality provided by the author's original patch: Coleco-SGV is not supported, some GME-specific m3u-support has been removed and IRAM is not used yet. Further changes are very likely to follow this submit. Thanks to Mauricio Garrido.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30264 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/SOURCES6
-rw-r--r--apps/codecs/SOURCES6
-rw-r--r--apps/codecs/ay.c137
-rw-r--r--apps/codecs/codecs.make14
-rw-r--r--apps/codecs/gbs.c108
-rw-r--r--apps/codecs/hes.c108
-rw-r--r--apps/codecs/kss.c113
-rw-r--r--apps/codecs/libgme/2413tone.h20
-rw-r--r--apps/codecs/libgme/281btone.h20
-rw-r--r--apps/codecs/libgme/AYSOURCES6
-rw-r--r--apps/codecs/libgme/GBSSOURCES8
-rw-r--r--apps/codecs/libgme/HESSOURCES7
-rw-r--r--apps/codecs/libgme/KSSSOURCES14
-rw-r--r--apps/codecs/libgme/NSFSOURCES15
-rw-r--r--apps/codecs/libgme/SGCSOURCES10
-rw-r--r--apps/codecs/libgme/VGMSOURCES12
-rw-r--r--apps/codecs/libgme/ay_apu.c413
-rw-r--r--apps/codecs/libgme/ay_apu.h79
-rw-r--r--apps/codecs/libgme/ay_cpu.c59
-rw-r--r--apps/codecs/libgme/ay_emu.c783
-rw-r--r--apps/codecs/libgme/ay_emu.h172
-rw-r--r--apps/codecs/libgme/blargg_common.h159
-rw-r--r--apps/codecs/libgme/blargg_config.h42
-rw-r--r--apps/codecs/libgme/blargg_endian.h147
-rw-r--r--apps/codecs/libgme/blargg_source.h71
-rw-r--r--apps/codecs/libgme/blip_buffer.c285
-rw-r--r--apps/codecs/libgme/blip_buffer.h279
-rw-r--r--apps/codecs/libgme/emu2413.c1958
-rw-r--r--apps/codecs/libgme/emu2413.h164
-rw-r--r--apps/codecs/libgme/emu8950.c1198
-rw-r--r--apps/codecs/libgme/emu8950.h248
-rw-r--r--apps/codecs/libgme/emuadpcm.c298
-rw-r--r--apps/codecs/libgme/emuadpcm.h52
-rw-r--r--apps/codecs/libgme/emutables.h170
-rw-r--r--apps/codecs/libgme/emutypes.h41
-rw-r--r--apps/codecs/libgme/gb_apu.c410
-rw-r--r--apps/codecs/libgme/gb_apu.h85
-rw-r--r--apps/codecs/libgme/gb_cpu.c53
-rw-r--r--apps/codecs/libgme/gb_cpu.h80
-rw-r--r--apps/codecs/libgme/gb_cpu_run.h1187
-rw-r--r--apps/codecs/libgme/gb_oscs.c787
-rw-r--r--apps/codecs/libgme/gb_oscs.h198
-rw-r--r--apps/codecs/libgme/gbs_cpu.c120
-rw-r--r--apps/codecs/libgme/gbs_emu.c631
-rw-r--r--apps/codecs/libgme/gbs_emu.h204
-rw-r--r--apps/codecs/libgme/gme.h18
-rw-r--r--apps/codecs/libgme/gme_types.h21
-rw-r--r--apps/codecs/libgme/hes_apu.c315
-rw-r--r--apps/codecs/libgme/hes_apu.h55
-rw-r--r--apps/codecs/libgme/hes_apu_adpcm.c297
-rw-r--r--apps/codecs/libgme/hes_apu_adpcm.h89
-rw-r--r--apps/codecs/libgme/hes_cpu.c1321
-rw-r--r--apps/codecs/libgme/hes_cpu.h95
-rw-r--r--apps/codecs/libgme/hes_cpu_io.h72
-rw-r--r--apps/codecs/libgme/hes_emu.c877
-rw-r--r--apps/codecs/libgme/hes_emu.h229
-rw-r--r--apps/codecs/libgme/inflate/bbfuncs.c147
-rw-r--r--apps/codecs/libgme/inflate/bbfuncs.h33
-rw-r--r--apps/codecs/libgme/inflate/inflate.c1159
-rw-r--r--apps/codecs/libgme/inflate/inflate.h30
-rw-r--r--apps/codecs/libgme/inflate/mallocer.c86
-rw-r--r--apps/codecs/libgme/inflate/mallocer.h16
-rw-r--r--apps/codecs/libgme/inflate/mbreader.c16
-rw-r--r--apps/codecs/libgme/inflate/mbreader.h15
-rw-r--r--apps/codecs/libgme/kss_cpu.c35
-rw-r--r--apps/codecs/libgme/kss_emu.c883
-rw-r--r--apps/codecs/libgme/kss_emu.h228
-rw-r--r--apps/codecs/libgme/kss_scc_apu.c166
-rw-r--r--apps/codecs/libgme/kss_scc_apu.h51
-rw-r--r--apps/codecs/libgme/libay.make21
-rw-r--r--apps/codecs/libgme/libgbs.make21
-rw-r--r--apps/codecs/libgme/libhes.make21
-rw-r--r--apps/codecs/libgme/libkss.make21
-rw-r--r--apps/codecs/libgme/libnsf.make21
-rw-r--r--apps/codecs/libgme/libsgc.make21
-rw-r--r--apps/codecs/libgme/libvgm.make21
-rw-r--r--apps/codecs/libgme/m3u_playlist.h31
-rw-r--r--apps/codecs/libgme/msxtypes.h36
-rw-r--r--apps/codecs/libgme/multi_buffer.c226
-rw-r--r--apps/codecs/libgme/multi_buffer.h72
-rw-r--r--apps/codecs/libgme/nes_apu.c393
-rw-r--r--apps/codecs/libgme/nes_apu.h134
-rw-r--r--apps/codecs/libgme/nes_cpu.c62
-rw-r--r--apps/codecs/libgme/nes_cpu.h106
-rw-r--r--apps/codecs/libgme/nes_cpu_io.h94
-rw-r--r--apps/codecs/libgme/nes_cpu_run.h1122
-rw-r--r--apps/codecs/libgme/nes_fds_apu.c291
-rw-r--r--apps/codecs/libgme/nes_fds_apu.h116
-rw-r--r--apps/codecs/libgme/nes_fme7_apu.c135
-rw-r--r--apps/codecs/libgme/nes_fme7_apu.h90
-rw-r--r--apps/codecs/libgme/nes_mmc5_apu.h61
-rw-r--r--apps/codecs/libgme/nes_namco_apu.c133
-rw-r--r--apps/codecs/libgme/nes_namco_apu.h71
-rw-r--r--apps/codecs/libgme/nes_oscs.c583
-rw-r--r--apps/codecs/libgme/nes_oscs.h165
-rw-r--r--apps/codecs/libgme/nes_vrc6_apu.c191
-rw-r--r--apps/codecs/libgme/nes_vrc6_apu.h62
-rw-r--r--apps/codecs/libgme/nes_vrc7_apu.c89
-rw-r--r--apps/codecs/libgme/nes_vrc7_apu.h52
-rw-r--r--apps/codecs/libgme/nsf_cpu.c115
-rw-r--r--apps/codecs/libgme/nsf_emu.c1105
-rw-r--r--apps/codecs/libgme/nsf_emu.h262
-rw-r--r--apps/codecs/libgme/nsfe_info.c272
-rw-r--r--apps/codecs/libgme/nsfe_info.h30
-rw-r--r--apps/codecs/libgme/opl_apu.c198
-rw-r--r--apps/codecs/libgme/opl_apu.h62
-rw-r--r--apps/codecs/libgme/opltables.h242
-rw-r--r--apps/codecs/libgme/resampler.c320
-rw-r--r--apps/codecs/libgme/resampler.h68
-rw-r--r--apps/codecs/libgme/rom_data.c68
-rw-r--r--apps/codecs/libgme/rom_data.h83
-rw-r--r--apps/codecs/libgme/sgc_cpu.c36
-rw-r--r--apps/codecs/libgme/sgc_emu.c673
-rw-r--r--apps/codecs/libgme/sgc_emu.h199
-rw-r--r--apps/codecs/libgme/sms_apu.c310
-rw-r--r--apps/codecs/libgme/sms_apu.h63
-rw-r--r--apps/codecs/libgme/sms_fm_apu.c82
-rw-r--r--apps/codecs/libgme/sms_fm_apu.h43
-rw-r--r--apps/codecs/libgme/vgm_emu.c1053
-rw-r--r--apps/codecs/libgme/vgm_emu.h211
-rw-r--r--apps/codecs/libgme/vrc7tone.h20
-rw-r--r--apps/codecs/libgme/ym2413_emu.c45
-rw-r--r--apps/codecs/libgme/ym2413_emu.h61
-rw-r--r--apps/codecs/libgme/ym2612_emu.c1359
-rw-r--r--apps/codecs/libgme/ym2612_emu.h237
-rw-r--r--apps/codecs/libgme/ymdeltat.c655
-rw-r--r--apps/codecs/libgme/ymdeltat.h100
-rw-r--r--apps/codecs/libgme/ymtables.h559
-rw-r--r--apps/codecs/libgme/z80_cpu.c85
-rw-r--r--apps/codecs/libgme/z80_cpu.h116
-rw-r--r--apps/codecs/libgme/z80_cpu_run.h1696
-rw-r--r--apps/codecs/nsf.c4483
-rw-r--r--apps/codecs/sgc.c123
-rw-r--r--apps/codecs/vgm.c142
-rw-r--r--apps/filetypes.c7
-rw-r--r--apps/metadata.c24
-rw-r--r--apps/metadata.h6
-rw-r--r--apps/metadata/ay.c148
-rw-r--r--apps/metadata/gbs.c65
-rw-r--r--apps/metadata/hes.c39
-rw-r--r--apps/metadata/kss.c53
-rw-r--r--apps/metadata/metadata_common.c8
-rw-r--r--apps/metadata/metadata_common.h1
-rw-r--r--apps/metadata/metadata_parsers.h6
-rw-r--r--apps/metadata/nsf.c12
-rw-r--r--apps/metadata/sgc.c67
-rw-r--r--apps/metadata/vgm.c195
-rw-r--r--docs/CREDITS1
-rw-r--r--manual/appendix/file_formats.tex55
149 files changed, 33129 insertions, 4427 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 79642e1f1d..26e53d1bb0 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -227,6 +227,12 @@ metadata/smaf.c
227metadata/au.c 227metadata/au.c
228metadata/vox.c 228metadata/vox.c
229metadata/tta.c 229metadata/tta.c
230metadata/ay.c
231metadata/gbs.c
232metadata/hes.c
233metadata/sgc.c
234metadata/vgm.c
235metadata/kss.c
230#endif 236#endif
231#ifdef HAVE_TAGCACHE 237#ifdef HAVE_TAGCACHE
232tagcache.c 238tagcache.c
diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES
index d950ffd46f..508969bd20 100644
--- a/apps/codecs/SOURCES
+++ b/apps/codecs/SOURCES
@@ -33,6 +33,12 @@ vox.c
33wav64.c 33wav64.c
34tta.c 34tta.c
35wmapro.c 35wmapro.c
36ay.c
37gbs.c
38hes.c
39sgc.c
40vgm.c
41kss.c
36 42
37#ifdef HAVE_RECORDING 43#ifdef HAVE_RECORDING
38 44
diff --git a/apps/codecs/ay.c b/apps/codecs/ay.c
new file mode 100644
index 0000000000..baccf3d99b
--- /dev/null
+++ b/apps/codecs/ay.c
@@ -0,0 +1,137 @@
1
2/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
3
4#include <codecs/lib/codeclib.h>
5#include "libgme/ay_emu.h"
6
7CODEC_HEADER
8
9/* Maximum number of bytes to process in one iteration */
10#define CHUNK_SIZE (1024*2)
11
12static int16_t samples[CHUNK_SIZE] IBSS_ATTR;
13static struct Ay_Emu ay_emu IDATA_ATTR CACHEALIGN_ATTR;
14
15/****************** rockbox interface ******************/
16
17static void set_codec_track(int t, int multitrack) {
18 Ay_start_track(&ay_emu, t);
19
20 /* for REPEAT_ONE we disable track limits */
21 if (ci->global_settings->repeat_mode != REPEAT_ONE) {
22 Track_set_fade(&ay_emu, Track_get_length( &ay_emu, t ) - 4000, 4000);
23 }
24 if (multitrack) ci->set_elapsed(t*1000); /* t is track no to display */
25 else ci->set_elapsed(0);
26}
27
28/* this is the codec entry point */
29enum codec_status codec_main(enum codec_entry_call_reason reason)
30{
31 if (reason == CODEC_LOAD) {
32 /* we only render 16 bits */
33 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
34
35 /* 44 Khz, Interleaved stereo */
36 ci->configure(DSP_SET_FREQUENCY, 44100);
37 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
38
39 Ay_init(&ay_emu);
40 Ay_set_sample_rate(&ay_emu, 44100);
41 }
42
43 return CODEC_OK;
44}
45
46/* this is called for each file to process */
47enum codec_status codec_run(void)
48{
49 blargg_err_t err;
50 uint8_t *buf;
51 size_t n;
52 int track, is_multitrack;
53 intptr_t param;
54 uint32_t elapsed_time;
55
56 /* reset values */
57 track = is_multitrack = 0;
58 elapsed_time = 0;
59
60 DEBUGF("AY: next_track\n");
61 if (codec_init()) {
62 return CODEC_ERROR;
63 }
64
65 codec_set_replaygain(ci->id3);
66
67 /* Read the entire file */
68 DEBUGF("AY: request file\n");
69 ci->seek_buffer(0);
70 buf = ci->request_buffer(&n, ci->filesize);
71 if (!buf || n < (size_t)ci->filesize) {
72 DEBUGF("AY: file load failed\n");
73 return CODEC_ERROR;
74 }
75
76 if ((err = Ay_load_mem(&ay_emu, buf, ci->filesize))) {
77 DEBUGF("AY: Ay_load failed (%s)\n", err);
78 return CODEC_ERROR;
79 }
80
81 /* Update internal track count */
82 if (ay_emu.m3u.size > 0)
83 ay_emu.track_count = ay_emu.m3u.size;
84
85 /* Check if file has multiple tracks */
86 if (ay_emu.track_count > 1) {
87 is_multitrack = 1;
88 }
89
90next_track:
91 set_codec_track(track, is_multitrack);
92
93 /* The main decoder loop */
94 while (1) {
95 enum codec_command_action action = ci->get_command(&param);
96
97 if (action == CODEC_ACTION_HALT)
98 break;
99
100 if (action == CODEC_ACTION_SEEK_TIME) {
101 if (is_multitrack) {
102 track = param/1000;
103 ci->seek_complete();
104 if (track >= ay_emu.track_count) break;
105 goto next_track;
106 }
107
108 ci->set_elapsed(param);
109 elapsed_time = param;
110 Track_seek(&ay_emu, param);
111 ci->seek_complete();
112
113 /* Set fade again */
114 if (ci->global_settings->repeat_mode != REPEAT_ONE) {
115 Track_set_fade(&ay_emu, Track_get_length( &ay_emu, track ) - 4000, 4000);
116 }
117 }
118
119 /* Generate audio buffer */
120 err = Ay_play(&ay_emu, CHUNK_SIZE, samples);
121 if (err || ay_emu.track_ended) {
122 track++;
123 if (track >= ay_emu.track_count) break;
124 goto next_track;
125 }
126
127 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE >> 1);
128
129 /* Set elapsed time for one track files */
130 if (!is_multitrack) {
131 elapsed_time += (CHUNK_SIZE / 2) / 44.1;
132 ci->set_elapsed(elapsed_time);
133 }
134 }
135
136 return CODEC_OK;
137}
diff --git a/apps/codecs/codecs.make b/apps/codecs/codecs.make
index 1a5dd8f36a..19ff60ba3a 100644
--- a/apps/codecs/codecs.make
+++ b/apps/codecs/codecs.make
@@ -43,6 +43,13 @@ include $(APPSDIR)/codecs/librm/librm.make
43include $(APPSDIR)/codecs/libatrac/libatrac.make 43include $(APPSDIR)/codecs/libatrac/libatrac.make
44include $(APPSDIR)/codecs/libpcm/libpcm.make 44include $(APPSDIR)/codecs/libpcm/libpcm.make
45include $(APPSDIR)/codecs/libtta/libtta.make 45include $(APPSDIR)/codecs/libtta/libtta.make
46include $(APPSDIR)/codecs/libgme/libay.make
47include $(APPSDIR)/codecs/libgme/libgbs.make
48include $(APPSDIR)/codecs/libgme/libhes.make
49include $(APPSDIR)/codecs/libgme/libnsf.make
50include $(APPSDIR)/codecs/libgme/libsgc.make
51include $(APPSDIR)/codecs/libgme/libvgm.make
52include $(APPSDIR)/codecs/libgme/libkss.make
46 53
47# compile flags for codecs 54# compile flags for codecs
48CODECFLAGS = $(CFLAGS) -fstrict-aliasing -I$(APPSDIR)/codecs \ 55CODECFLAGS = $(CFLAGS) -fstrict-aliasing -I$(APPSDIR)/codecs \
@@ -93,6 +100,13 @@ $(CODECDIR)/au.codec : $(CODECDIR)/libpcm.a
93$(CODECDIR)/vox.codec : $(CODECDIR)/libpcm.a 100$(CODECDIR)/vox.codec : $(CODECDIR)/libpcm.a
94$(CODECDIR)/wav64.codec : $(CODECDIR)/libpcm.a 101$(CODECDIR)/wav64.codec : $(CODECDIR)/libpcm.a
95$(CODECDIR)/tta.codec : $(CODECDIR)/libtta.a 102$(CODECDIR)/tta.codec : $(CODECDIR)/libtta.a
103$(CODECDIR)/ay.codec : $(CODECDIR)/libay.a
104$(CODECDIR)/gbs.codec : $(CODECDIR)/libgbs.a
105$(CODECDIR)/hes.codec : $(CODECDIR)/libhes.a
106$(CODECDIR)/nsf.codec : $(CODECDIR)/libnsf.a
107$(CODECDIR)/sgc.codec : $(CODECDIR)/libsgc.a
108$(CODECDIR)/vgm.codec : $(CODECDIR)/libvgm.a
109$(CODECDIR)/kss.codec : $(CODECDIR)/libkss.a
96 110
97$(CODECS): $(CODECLIB) # this must be last in codec dependency list 111$(CODECS): $(CODECLIB) # this must be last in codec dependency list
98 112
diff --git a/apps/codecs/gbs.c b/apps/codecs/gbs.c
new file mode 100644
index 0000000000..bc6d31e6b8
--- /dev/null
+++ b/apps/codecs/gbs.c
@@ -0,0 +1,108 @@
1
2/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
3
4#include <codecs/lib/codeclib.h>
5#include "libgme/gbs_emu.h"
6
7CODEC_HEADER
8
9/* Maximum number of bytes to process in one iteration */
10#define CHUNK_SIZE (1024*2)
11
12static int16_t samples[CHUNK_SIZE] IBSS_ATTR;
13static struct Gbs_Emu gbs_emu IDATA_ATTR CACHEALIGN_ATTR;
14
15/****************** rockbox interface ******************/
16
17static void set_codec_track(int t) {
18 Gbs_start_track(&gbs_emu, t);
19
20 /* for REPEAT_ONE we disable track limits */
21 if (ci->global_settings->repeat_mode != REPEAT_ONE) {
22 Track_set_fade(&gbs_emu, Track_get_length( &gbs_emu, t ), 4000);
23 }
24 ci->set_elapsed(t*1000); /* t is track no to display */
25}
26
27/* this is the codec entry point */
28enum codec_status codec_main(enum codec_entry_call_reason reason)
29{
30 if (reason == CODEC_LOAD) {
31 /* we only render 16 bits */
32 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
33
34 /* 44 Khz, Interleaved stereo */
35 ci->configure(DSP_SET_FREQUENCY, 44100);
36 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
37
38 Gbs_init(&gbs_emu);
39 Gbs_set_sample_rate(&gbs_emu, 44100);
40 }
41
42 return CODEC_OK;
43}
44
45/* this is called for each file to process */
46enum codec_status codec_run(void)
47{
48 blargg_err_t err;
49 uint8_t *buf;
50 size_t n;
51 intptr_t param;
52 int track = 0;
53
54 DEBUGF("GBS: next_track\n");
55 if (codec_init()) {
56 return CODEC_ERROR;
57 }
58
59 codec_set_replaygain(ci->id3);
60
61 /* Read the entire file */
62 DEBUGF("GBS: request file\n");
63 ci->seek_buffer(0);
64 buf = ci->request_buffer(&n, ci->filesize);
65 if (!buf || n < (size_t)ci->filesize) {
66 DEBUGF("GBS: file load failed\n");
67 return CODEC_ERROR;
68 }
69
70 if ((err = Gbs_load(&gbs_emu, buf, ci->filesize))) {
71 DEBUGF("GBS: Gbs_load failed (%s)\n", err);
72 return CODEC_ERROR;
73 }
74
75 /* Update internal track count */
76 if (gbs_emu.m3u.size > 0)
77 gbs_emu.track_count = gbs_emu.m3u.size;
78
79next_track:
80 set_codec_track(track);
81
82 /* The main decoder loop */
83 while (1) {
84 enum codec_command_action action = ci->get_command(&param);
85
86 if (action == CODEC_ACTION_HALT)
87 break;
88
89 if (action == CODEC_ACTION_SEEK_TIME) {
90 track = param/1000;
91 ci->seek_complete();
92 if (track >= gbs_emu.track_count) break;
93 goto next_track;
94 }
95
96 /* Generate audio buffer */
97 err = Gbs_play(&gbs_emu, CHUNK_SIZE, samples);
98 if (err || gbs_emu.track_ended) {
99 track++;
100 if (track >= gbs_emu.track_count) break;
101 goto next_track;
102 }
103
104 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE >> 1);
105 }
106
107 return CODEC_OK;
108}
diff --git a/apps/codecs/hes.c b/apps/codecs/hes.c
new file mode 100644
index 0000000000..598d787594
--- /dev/null
+++ b/apps/codecs/hes.c
@@ -0,0 +1,108 @@
1/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
2
3#include <string.h>
4#include "codeclib.h"
5#include "libgme/hes_emu.h"
6
7CODEC_HEADER
8
9/* Maximum number of bytes to process in one iteration */
10#define CHUNK_SIZE (1024*2)
11
12static int16_t samples[CHUNK_SIZE] IBSS_ATTR;
13static struct Hes_Emu hes_emu IDATA_ATTR CACHEALIGN_ATTR;
14
15/****************** rockbox interface ******************/
16
17static void set_codec_track(int t) {
18 Hes_start_track(&hes_emu, t);
19
20 /* for REPEAT_ONE we disable track limits */
21 if (ci->global_settings->repeat_mode != REPEAT_ONE) {
22 Track_set_fade(&hes_emu, Track_get_length( &hes_emu, t ), 4000);
23 }
24 ci->set_elapsed(t*1000); /* t is track no to display */
25}
26
27/* this is the codec entry point */
28enum codec_status codec_main(enum codec_entry_call_reason reason)
29{
30 if (reason == CODEC_LOAD) {
31 /* we only render 16 bits */
32 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
33
34 /* 44 Khz, Interleaved stereo */
35 ci->configure(DSP_SET_FREQUENCY, 44100);
36 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
37
38 Hes_init(&hes_emu);
39 Hes_set_sample_rate(&hes_emu, 44100);
40 }
41
42 return CODEC_OK;
43}
44
45/* this is called for each file to process */
46enum codec_status codec_run(void)
47{
48 blargg_err_t err;
49 uint8_t *buf;
50 size_t n;
51 intptr_t param;
52 int track = 0;
53
54 DEBUGF("HES: next_track\n");
55 if (codec_init()) {
56 return CODEC_ERROR;
57 }
58
59 codec_set_replaygain(ci->id3);
60
61 /* Read the entire file */
62 DEBUGF("HES: request file\n");
63 ci->seek_buffer(0);
64 buf = ci->request_buffer(&n, ci->filesize);
65 if (!buf || n < (size_t)ci->filesize) {
66 DEBUGF("HES: file load failed\n");
67 return CODEC_ERROR;
68 }
69
70 if ((err = Hes_load(&hes_emu, buf, ci->filesize))) {
71 DEBUGF("HES: Hes_load failed (%s)\n", err);
72 return CODEC_ERROR;
73 }
74
75 /* Update internal track count */
76 if (hes_emu.m3u.size > 0)
77 hes_emu.track_count = hes_emu.m3u.size;
78
79next_track:
80 set_codec_track(track);
81
82 /* The main decoder loop */
83 while ( 1 ) {
84 enum codec_command_action action = ci->get_command(&param);
85
86 if (action == CODEC_ACTION_HALT)
87 break;
88
89 if (action == CODEC_ACTION_SEEK_TIME) {
90 track = param/1000;
91 ci->seek_complete();
92 if (track >= hes_emu.track_count) break;
93 goto next_track;
94 }
95
96 /* Generate audio buffer */
97 err = Hes_play(&hes_emu, CHUNK_SIZE, samples);
98 if (err || hes_emu.track_ended) {
99 track++;
100 if (track >= hes_emu.track_count) break;
101 goto next_track;
102 }
103
104 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE >> 1);
105 }
106
107 return CODEC_OK;
108}
diff --git a/apps/codecs/kss.c b/apps/codecs/kss.c
new file mode 100644
index 0000000000..9db16521b4
--- /dev/null
+++ b/apps/codecs/kss.c
@@ -0,0 +1,113 @@
1
2/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
3
4#include <codecs/lib/codeclib.h>
5#include "libgme/kss_emu.h"
6
7CODEC_HEADER
8
9/* Maximum number of bytes to process in one iteration */
10#define CHUNK_SIZE (1024*2)
11
12static int16_t samples[CHUNK_SIZE] IBSS_ATTR;
13static struct Kss_Emu kss_emu IDATA_ATTR CACHEALIGN_ATTR;
14
15/****************** rockbox interface ******************/
16
17static void set_codec_track(int t) {
18 Kss_start_track(&kss_emu, t);
19
20 /* for REPEAT_ONE we disable track limits */
21 if (ci->global_settings->repeat_mode != REPEAT_ONE) {
22 Track_set_fade(&kss_emu, Track_get_length( &kss_emu, t ), 4000);
23 }
24 ci->set_elapsed(t*1000); /* t is track no to display */
25}
26
27/* this is the codec entry point */
28enum codec_status codec_main(enum codec_entry_call_reason reason)
29{
30 if (reason == CODEC_LOAD) {
31 /* we only render 16 bits */
32 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
33
34 /* 44 Khz, Interleaved stereo */
35 ci->configure(DSP_SET_FREQUENCY, 44100);
36 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
37
38 Kss_init(&kss_emu);
39 Kss_set_sample_rate(&kss_emu, 44100);
40 }
41
42 return CODEC_OK;
43}
44
45/* this is called for each file to process */
46enum codec_status codec_run(void)
47{
48 blargg_err_t err;
49 uint8_t *buf;
50 size_t n;
51 int track;
52 intptr_t param;
53 uint32_t elapsed_time;
54
55 /* reset values */
56 track = 0;
57 elapsed_time = 0;
58
59 DEBUGF("KSS: next_track\n");
60 if (codec_init()) {
61 return CODEC_ERROR;
62 }
63
64 codec_set_replaygain(ci->id3);
65
66 /* Read the entire file */
67 DEBUGF("KSS: request file\n");
68 ci->seek_buffer(0);
69 buf = ci->request_buffer(&n, ci->filesize);
70 if (!buf || n < (size_t)ci->filesize) {
71 DEBUGF("KSS: file load failed\n");
72 return CODEC_ERROR;
73 }
74
75 if ((err = Kss_load_mem(&kss_emu, buf, ci->filesize))) {
76 DEBUGF("KSS: Kss_load failed (%s)\n", err);
77 return CODEC_ERROR;
78 }
79
80 /* Update internal track count */
81 if (kss_emu.m3u.size > 0)
82 kss_emu.track_count = kss_emu.m3u.size;
83
84next_track:
85 set_codec_track(track);
86
87 /* The main decoder loop */
88 while (1) {
89 enum codec_command_action action = ci->get_command(&param);
90
91 if (action == CODEC_ACTION_HALT)
92 break;
93
94 if (action == CODEC_ACTION_SEEK_TIME) {
95 track = param/1000;
96 ci->seek_complete();
97 if (track >= kss_emu.track_count) break;
98 goto next_track;
99 }
100
101 /* Generate audio buffer */
102 err = Kss_play(&kss_emu, CHUNK_SIZE, samples);
103 if (err || kss_emu.track_ended) {
104 track++;
105 if (track >= kss_emu.track_count) break;
106 goto next_track;
107 }
108
109 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE >> 1);
110 }
111
112 return CODEC_OK;
113}
diff --git a/apps/codecs/libgme/2413tone.h b/apps/codecs/libgme/2413tone.h
new file mode 100644
index 0000000000..e4366ab245
--- /dev/null
+++ b/apps/codecs/libgme/2413tone.h
@@ -0,0 +1,20 @@
1/* YM2413 tone by okazaki@angel.ne.jp */
20x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
30x61,0x61,0x1e,0x17,0xf0,0x7f,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
40x13,0x41,0x16,0x0e,0xfd,0xf4,0x23,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
50x03,0x01,0x9a,0x04,0xf3,0xf3,0x13,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
60x11,0x61,0x0e,0x07,0xfa,0x64,0x70,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
70x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
80x21,0x22,0x16,0x05,0xf0,0x71,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
90x21,0x61,0x1d,0x07,0x82,0x80,0x17,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100x23,0x21,0x2d,0x16,0x90,0x90,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
110x21,0x21,0x1b,0x06,0x64,0x65,0x10,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
120x21,0x21,0x0b,0x1a,0x85,0xa0,0x70,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
130x23,0x01,0x83,0x10,0xff,0xb4,0x10,0xf4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
140x97,0xc1,0x20,0x07,0xff,0xf4,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
150x61,0x00,0x0c,0x05,0xc2,0xf6,0x40,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
160x01,0x01,0x56,0x03,0x94,0xc2,0x03,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
170x21,0x01,0x89,0x03,0xf1,0xe4,0xf0,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
180x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
190x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
200x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
diff --git a/apps/codecs/libgme/281btone.h b/apps/codecs/libgme/281btone.h
new file mode 100644
index 0000000000..1300523fbe
--- /dev/null
+++ b/apps/codecs/libgme/281btone.h
@@ -0,0 +1,20 @@
1/* YMF281B tone by Chabin */
20x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
30x62,0x21,0x1a,0x07,0xf0,0x6f,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
40x00,0x10,0x44,0x02,0xf6,0xf4,0x54,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
50x03,0x01,0x97,0x04,0xf3,0xf3,0x13,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
60x01,0x61,0x0a,0x0f,0xfa,0x64,0x70,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
70x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
80x00,0x61,0x8a,0x0e,0xc0,0x61,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
90x21,0x61,0x1b,0x07,0x84,0x80,0x17,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100x37,0x32,0xc9,0x01,0x66,0x64,0x40,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
110x01,0x21,0x06,0x03,0xa5,0x71,0x51,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
120x06,0x11,0x5e,0x07,0xf3,0xf2,0xf6,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
130x00,0x20,0x18,0x06,0xf5,0xf3,0x20,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
140x97,0x41,0x20,0x07,0xff,0xf4,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
150x65,0x61,0x15,0x00,0xf7,0xf3,0x16,0xf4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
160x01,0x31,0x0e,0x07,0xfa,0xf3,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
170x48,0x61,0x09,0x07,0xf1,0x94,0xf0,0xf5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
180x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
190x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
200x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
diff --git a/apps/codecs/libgme/AYSOURCES b/apps/codecs/libgme/AYSOURCES
new file mode 100644
index 0000000000..51253fe2f1
--- /dev/null
+++ b/apps/codecs/libgme/AYSOURCES
@@ -0,0 +1,6 @@
1ay_apu.c
2ay_cpu.c
3ay_emu.c
4blip_buffer.c
5multi_buffer.c
6z80_cpu.c
diff --git a/apps/codecs/libgme/GBSSOURCES b/apps/codecs/libgme/GBSSOURCES
new file mode 100644
index 0000000000..5548fd85eb
--- /dev/null
+++ b/apps/codecs/libgme/GBSSOURCES
@@ -0,0 +1,8 @@
1gb_apu.c
2gb_cpu.c
3gbs_cpu.c
4gb_oscs.c
5gbs_emu.c
6blip_buffer.c
7multi_buffer.c
8rom_data.c
diff --git a/apps/codecs/libgme/HESSOURCES b/apps/codecs/libgme/HESSOURCES
new file mode 100644
index 0000000000..58a38f2f5a
--- /dev/null
+++ b/apps/codecs/libgme/HESSOURCES
@@ -0,0 +1,7 @@
1hes_apu.c
2hes_apu_adpcm.c
3hes_cpu.c
4hes_emu.c
5blip_buffer.c
6multi_buffer.c
7rom_data.c
diff --git a/apps/codecs/libgme/KSSSOURCES b/apps/codecs/libgme/KSSSOURCES
new file mode 100644
index 0000000000..a934bec02a
--- /dev/null
+++ b/apps/codecs/libgme/KSSSOURCES
@@ -0,0 +1,14 @@
1ay_apu.c
2kss_cpu.c
3kss_emu.c
4kss_scc_apu.c
5opl_apu.c
6sms_apu.c
7ymdeltat.c
8z80_cpu.c
9blip_buffer.c
10multi_buffer.c
11rom_data.c
12emu2413.c
13emu8950.c
14emuadpcm.c
diff --git a/apps/codecs/libgme/NSFSOURCES b/apps/codecs/libgme/NSFSOURCES
new file mode 100644
index 0000000000..d96e1d3f32
--- /dev/null
+++ b/apps/codecs/libgme/NSFSOURCES
@@ -0,0 +1,15 @@
1nes_apu.c
2nes_cpu.c
3nes_fds_apu.c
4nes_fme7_apu.c
5nes_namco_apu.c
6nes_oscs.c
7nes_vrc6_apu.c
8nes_vrc7_apu.c
9nsf_cpu.c
10nsf_emu.c
11nsfe_info.c
12blip_buffer.c
13multi_buffer.c
14rom_data.c
15emu2413.c
diff --git a/apps/codecs/libgme/SGCSOURCES b/apps/codecs/libgme/SGCSOURCES
new file mode 100644
index 0000000000..72b06efef9
--- /dev/null
+++ b/apps/codecs/libgme/SGCSOURCES
@@ -0,0 +1,10 @@
1sgc_cpu.c
2sgc_emu.c
3sms_apu.c
4sms_fm_apu.c
5ym2413_emu.c
6z80_cpu.c
7blip_buffer.c
8multi_buffer.c
9rom_data.c
10emu2413.c
diff --git a/apps/codecs/libgme/VGMSOURCES b/apps/codecs/libgme/VGMSOURCES
new file mode 100644
index 0000000000..ed32baca0d
--- /dev/null
+++ b/apps/codecs/libgme/VGMSOURCES
@@ -0,0 +1,12 @@
1blip_buffer.c
2multi_buffer.c
3resampler.c
4sms_apu.c
5vgm_emu.c
6emu2413.c
7ym2413_emu.c
8ym2612_emu.c
9inflate/bbfuncs.c
10inflate/inflate.c
11inflate/mallocer.c
12inflate/mbreader.c
diff --git a/apps/codecs/libgme/ay_apu.c b/apps/codecs/libgme/ay_apu.c
new file mode 100644
index 0000000000..a2ec299167
--- /dev/null
+++ b/apps/codecs/libgme/ay_apu.c
@@ -0,0 +1,413 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "ay_apu.h"
4
5/* Copyright (C) 2006-2008 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18// Emulation inaccuracies:
19// * Noise isn't run when not in use
20// * Changes to envelope and noise periods are delayed until next reload
21// * Super-sonic tone should attenuate output to about 60%, not 50%
22
23// Tones above this frequency are treated as disabled tone at half volume.
24// Power of two is more efficient (avoids division).
25int const inaudible_freq = 16384;
26
27int const period_factor = 16;
28
29static byte const amp_table [16] =
30{
31#define ENTRY( n ) (byte) (n * ay_amp_range + 0.5)
32 // With channels tied together and 1K resistor to ground (as datasheet recommends),
33 // output nearly matches logarithmic curve as claimed. Approx. 1.5 dB per step.
34 ENTRY(0.000000),ENTRY(0.007813),ENTRY(0.011049),ENTRY(0.015625),
35 ENTRY(0.022097),ENTRY(0.031250),ENTRY(0.044194),ENTRY(0.062500),
36 ENTRY(0.088388),ENTRY(0.125000),ENTRY(0.176777),ENTRY(0.250000),
37 ENTRY(0.353553),ENTRY(0.500000),ENTRY(0.707107),ENTRY(1.000000),
38
39 /*
40 // Measured from an AY-3-8910A chip with date code 8611.
41
42 // Direct voltages without any load (very linear)
43 ENTRY(0.000000),ENTRY(0.046237),ENTRY(0.064516),ENTRY(0.089785),
44 ENTRY(0.124731),ENTRY(0.173118),ENTRY(0.225806),ENTRY(0.329032),
45 ENTRY(0.360215),ENTRY(0.494624),ENTRY(0.594624),ENTRY(0.672043),
46 ENTRY(0.766129),ENTRY(0.841935),ENTRY(0.926882),ENTRY(1.000000),
47 // With only some load
48 ENTRY(0.000000),ENTRY(0.011940),ENTRY(0.017413),ENTRY(0.024876),
49 ENTRY(0.036318),ENTRY(0.054229),ENTRY(0.072637),ENTRY(0.122388),
50 ENTRY(0.174129),ENTRY(0.239303),ENTRY(0.323881),ENTRY(0.410945),
51 ENTRY(0.527363),ENTRY(0.651741),ENTRY(0.832338),ENTRY(1.000000),
52 */
53#undef ENTRY
54};
55
56static byte const modes [8] =
57{
58#define MODE( a0,a1, b0,b1, c0,c1 ) \
59 (a0 | a1<<1 | b0<<2 | b1<<3 | c0<<4 | c1<<5)
60 MODE( 1,0, 1,0, 1,0 ),
61 MODE( 1,0, 0,0, 0,0 ),
62 MODE( 1,0, 0,1, 1,0 ),
63 MODE( 1,0, 1,1, 1,1 ),
64 MODE( 0,1, 0,1, 0,1 ),
65 MODE( 0,1, 1,1, 1,1 ),
66 MODE( 0,1, 1,0, 0,1 ),
67 MODE( 0,1, 0,0, 0,0 ),
68};
69
70void set_output( struct Ay_Apu* this, struct Blip_Buffer* b )
71{
72 int i;
73 for ( i = 0; i < ay_osc_count; ++i )
74 Ay_apu_set_output( this, i, b );
75}
76
77void Ay_apu_init( struct Ay_Apu* this )
78{
79 Synth_init( &this->synth_ );
80
81 // build full table of the upper 8 envelope waveforms
82 int m;
83 for ( m = 8; m--; )
84 {
85 byte* out = this->env_modes [m];
86 int x, y, flags = modes [m];
87 for ( x = 3; --x >= 0; )
88 {
89 int amp = flags & 1;
90 int end = flags >> 1 & 1;
91 int step = end - amp;
92 amp *= 15;
93 for ( y = 16; --y >= 0; )
94 {
95 *out++ = amp_table [amp];
96 amp += step;
97 }
98 flags >>= 2;
99 }
100 }
101
102 set_output( this, NULL );
103 Ay_apu_volume( this, 1.0 );
104 Ay_apu_reset( this );
105}
106
107void Ay_apu_reset( struct Ay_Apu* this )
108{
109 this->addr_ = 0;
110 this->last_time = 0;
111 this->noise_delay = 0;
112 this->noise_lfsr = 1;
113
114 struct osc_t* osc;
115 for ( osc = &this->oscs [ay_osc_count]; osc != this->oscs; )
116 {
117 osc--;
118 osc->period = period_factor;
119 osc->delay = 0;
120 osc->last_amp = 0;
121 osc->phase = 0;
122 }
123
124 int i;
125 for ( i = sizeof this->regs; --i >= 0; )
126 this->regs [i] = 0;
127 this->regs [7] = 0xFF;
128 write_data_( this, 13, 0 );
129}
130
131int Ay_apu_read( struct Ay_Apu* this )
132{
133 static byte const masks [ay_reg_count] = {
134 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x1F, 0x3F,
135 0x1F, 0x1F, 0x1F, 0xFF, 0xFF, 0x0F, 0x00, 0x00
136 };
137 return this->regs [this->addr_] & masks [this->addr_];
138}
139
140void write_data_( struct Ay_Apu* this, int addr, int data )
141{
142 assert( (unsigned) addr < ay_reg_count );
143
144 /* if ( (unsigned) addr >= 14 )
145 dprintf( "Wrote to I/O port %02X\n", (int) addr ); */
146
147 // envelope mode
148 if ( addr == 13 )
149 {
150 if ( !(data & 8) ) // convert modes 0-7 to proper equivalents
151 data = (data & 4) ? 15 : 9;
152 this->env_wave = this->env_modes [data - 7];
153 this->env_pos = -48;
154 this->env_delay = 0; // will get set to envelope period in run_until()
155 }
156 this->regs [addr] = data;
157
158 // handle period changes accurately
159 int i = addr >> 1;
160 if ( i < ay_osc_count )
161 {
162 blip_time_t period = (this->regs [i * 2 + 1] & 0x0F) * (0x100 * period_factor) +
163 this->regs [i * 2] * period_factor;
164 if ( !period )
165 period = period_factor;
166
167 // adjust time of next timer expiration based on change in period
168 struct osc_t* osc = &this->oscs [i];
169 if ( (osc->delay += period - osc->period) < 0 )
170 osc->delay = 0;
171 osc->period = period;
172 }
173
174 // TODO: same as above for envelope timer, and it also has a divide by two after it
175}
176
177int const noise_off = 0x08;
178int const tone_off = 0x01;
179
180void run_until( struct Ay_Apu* this, blip_time_t final_end_time )
181{
182 require( final_end_time >= this->last_time );
183
184 // noise period and initial values
185 blip_time_t const noise_period_factor = period_factor * 2; // verified
186 blip_time_t noise_period = (this->regs [6] & 0x1F) * noise_period_factor;
187 if ( !noise_period )
188 noise_period = noise_period_factor;
189 blip_time_t const old_noise_delay = this->noise_delay;
190 unsigned const old_noise_lfsr = this->noise_lfsr;
191
192 // envelope period
193 blip_time_t const env_period_factor = period_factor * 2; // verified
194 blip_time_t env_period = (this->regs [12] * 0x100 + this->regs [11]) * env_period_factor;
195 if ( !env_period )
196 env_period = env_period_factor; // same as period 1 on my AY chip
197 if ( !this->env_delay )
198 this->env_delay = env_period;
199
200 // run each osc separately
201 int index;
202 for ( index = 0; index < ay_osc_count; index++ )
203 {
204 struct osc_t* const osc = &this->oscs [index];
205 int osc_mode = this->regs [7] >> index;
206
207 // output
208 struct Blip_Buffer* const osc_output = osc->output;
209 if ( !osc_output )
210 continue;
211 Blip_set_modified( osc_output );
212
213 // period
214 int half_vol = 0;
215 blip_time_t inaudible_period = (unsigned) (Blip_clock_rate( osc_output ) +
216 inaudible_freq) / (unsigned) (inaudible_freq * 2);
217 if ( osc->period <= inaudible_period && !(osc_mode & tone_off) )
218 {
219 half_vol = 1; // Actually around 60%, but 50% is close enough
220 osc_mode |= tone_off;
221 }
222
223 // envelope
224 blip_time_t start_time = this->last_time;
225 blip_time_t end_time = final_end_time;
226 int const vol_mode = this->regs [0x08 + index];
227 int volume = amp_table [vol_mode & 0x0F] >> half_vol;
228 int osc_env_pos = this->env_pos;
229 if ( vol_mode & 0x10 )
230 {
231 volume = this->env_wave [osc_env_pos] >> half_vol;
232 // use envelope only if it's a repeating wave or a ramp that hasn't finished
233 if ( !(this->regs [13] & 1) || osc_env_pos < -32 )
234 {
235 end_time = start_time + this->env_delay;
236 if ( end_time >= final_end_time )
237 end_time = final_end_time;
238
239 //if ( !(regs [12] | regs [11]) )
240 // dprintf( "Used envelope period 0\n" );
241 }
242 else if ( !volume )
243 {
244 osc_mode = noise_off | tone_off;
245 }
246 }
247 else if ( !volume )
248 {
249 osc_mode = noise_off | tone_off;
250 }
251
252 // tone time
253 blip_time_t const period = osc->period;
254 blip_time_t time = start_time + osc->delay;
255 if ( osc_mode & tone_off ) // maintain tone's phase when off
256 {
257 int count = (final_end_time - time + period - 1) / period;
258 time += count * period;
259 osc->phase ^= count & 1;
260 }
261
262 // noise time
263 blip_time_t ntime = final_end_time;
264 unsigned noise_lfsr = 1;
265 if ( !(osc_mode & noise_off) )
266 {
267 ntime = start_time + old_noise_delay;
268 noise_lfsr = old_noise_lfsr;
269 //if ( (regs [6] & 0x1F) == 0 )
270 // dprintf( "Used noise period 0\n" );
271 }
272
273 // The following efficiently handles several cases (least demanding first):
274 // * Tone, noise, and envelope disabled, where channel acts as 4-bit DAC
275 // * Just tone or just noise, envelope disabled
276 // * Envelope controlling tone and/or noise
277 // * Tone and noise disabled, envelope enabled with high frequency
278 // * Tone and noise together
279 // * Tone and noise together with envelope
280
281 // this loop only runs one iteration if envelope is disabled. If envelope
282 // is being used as a waveform (tone and noise disabled), this loop will
283 // still be reasonably efficient since the bulk of it will be skipped.
284 while ( 1 )
285 {
286 // current amplitude
287 int amp = 0;
288 if ( (osc_mode | osc->phase) & 1 & (osc_mode >> 3 | noise_lfsr) )
289 amp = volume;
290 {
291 int delta = amp - osc->last_amp;
292 if ( delta )
293 {
294 osc->last_amp = amp;
295 Synth_offset( &this->synth_, start_time, delta, osc_output );
296 }
297 }
298
299 // Run wave and noise interleved with each catching up to the other.
300 // If one or both are disabled, their "current time" will be past end time,
301 // so there will be no significant performance hit.
302 if ( ntime < end_time || time < end_time )
303 {
304 // Since amplitude was updated above, delta will always be +/- volume,
305 // so we can avoid using last_amp every time to calculate the delta.
306 int delta = amp * 2 - volume;
307 int delta_non_zero = delta != 0;
308 int phase = osc->phase | (osc_mode & tone_off); assert( tone_off == 0x01 );
309 do
310 {
311 // run noise
312 blip_time_t end = end_time;
313 if ( end_time > time ) end = time;
314 if ( phase & delta_non_zero )
315 {
316 while ( ntime <= end ) // must advance *past* time to avoid hang
317 {
318 int changed = noise_lfsr + 1;
319 noise_lfsr = (-(noise_lfsr & 1) & 0x12000) ^ (noise_lfsr >> 1);
320 if ( changed & 2 )
321 {
322 delta = -delta;
323 Synth_offset( &this->synth_, ntime, delta, osc_output );
324 }
325 ntime += noise_period;
326 }
327 }
328 else
329 {
330 // 20 or more noise periods on average for some music
331 int remain = end - ntime;
332 int count = remain / noise_period;
333 if ( remain >= 0 )
334 ntime += noise_period + count * noise_period;
335 }
336
337 // run tone
338 end = end_time;
339 if ( end_time > ntime ) end = ntime;
340 if ( noise_lfsr & delta_non_zero )
341 {
342 while ( time < end )
343 {
344 delta = -delta;
345 Synth_offset( &this->synth_, time, delta, osc_output );
346 time += period;
347
348 // alternate (less-efficient) implementation
349 //phase ^= 1;
350 }
351 phase = (unsigned) (-delta) >> (CHAR_BIT * sizeof (unsigned) - 1);
352 check( phase == (delta > 0) );
353 }
354 else
355 {
356 // loop usually runs less than once
357 //SUB_CASE_COUNTER( (time < end) * (end - time + period - 1) / period );
358
359 while ( time < end )
360 {
361 time += period;
362 phase ^= 1;
363 }
364 }
365 }
366 while ( time < end_time || ntime < end_time );
367
368 osc->last_amp = (delta + volume) >> 1;
369 if ( !(osc_mode & tone_off) )
370 osc->phase = phase;
371 }
372
373 if ( end_time >= final_end_time )
374 break; // breaks first time when envelope is disabled
375
376 // next envelope step
377 if ( ++osc_env_pos >= 0 )
378 osc_env_pos -= 32;
379 volume = this->env_wave [osc_env_pos] >> half_vol;
380
381 start_time = end_time;
382 end_time += env_period;
383 if ( end_time > final_end_time )
384 end_time = final_end_time;
385 }
386 osc->delay = time - final_end_time;
387
388 if ( !(osc_mode & noise_off) )
389 {
390 this->noise_delay = ntime - final_end_time;
391 this->noise_lfsr = noise_lfsr;
392 }
393 }
394
395 // TODO: optimized saw wave envelope?
396
397 // maintain envelope phase
398 blip_time_t remain = final_end_time - this->last_time - this->env_delay;
399 if ( remain >= 0 )
400 {
401 int count = (remain + env_period) / env_period;
402 this->env_pos += count;
403 if ( this->env_pos >= 0 )
404 this->env_pos = (this->env_pos & 31) - 32;
405 remain -= count * env_period;
406 assert( -remain <= env_period );
407 }
408 this->env_delay = -remain;
409 assert( this->env_delay > 0 );
410 assert( this->env_pos < 0 );
411
412 this->last_time = final_end_time;
413}
diff --git a/apps/codecs/libgme/ay_apu.h b/apps/codecs/libgme/ay_apu.h
new file mode 100644
index 0000000000..ccdd204c46
--- /dev/null
+++ b/apps/codecs/libgme/ay_apu.h
@@ -0,0 +1,79 @@
1// AY-3-8910 sound chip ulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef AY_APU_H
5#define AY_APU_H
6
7#include "blargg_common.h"
8#include "blargg_source.h"
9#include "blip_buffer.h"
10
11// Number of registers
12enum { ay_reg_count = 16 };
13enum { ay_osc_count = 3 };
14enum { ay_amp_range = 255 };
15
16struct osc_t
17{
18 blip_time_t period;
19 blip_time_t delay;
20 short last_amp;
21 short phase;
22 struct Blip_Buffer* output;
23};
24
25struct Ay_Apu {
26 struct osc_t oscs [ay_osc_count];
27
28 blip_time_t last_time;
29 byte addr_;
30 byte regs [ay_reg_count];
31
32 blip_time_t noise_delay;
33 unsigned noise_lfsr;
34
35 blip_time_t env_delay;
36 byte const* env_wave;
37 int env_pos;
38 byte env_modes [8] [48]; // values already passed through volume table
39
40 struct Blip_Synth synth_; // used by Ay_Core for beeper sound
41};
42
43void Ay_apu_init( struct Ay_Apu* this );
44
45// Writes to address register
46static inline void Ay_apu_write_addr( struct Ay_Apu* this, int data ) { this->addr_ = data & 0x0F; }
47
48// Emulates to time t, then writes to current data register
49void run_until( struct Ay_Apu* this, blip_time_t final_end_time ) ICODE_ATTR;;
50void write_data_( struct Ay_Apu* this, int addr, int data ) ICODE_ATTR;
51static inline void Ay_apu_write_data( struct Ay_Apu* this, blip_time_t t, int data ) { run_until( this, t ); write_data_( this, this->addr_, data ); }
52
53// Reads from current data register
54int Ay_apu_read( struct Ay_Apu* this );
55
56// Resets sound chip
57void Ay_apu_reset( struct Ay_Apu* this );
58
59// Sets overall volume, where 1.0 is normal
60static inline void Ay_apu_volume( struct Ay_Apu* this, double v ) { Synth_volume( &this->synth_, 0.7/ay_osc_count/ay_amp_range * v ); }
61
62static inline void Ay_apu_set_output( struct Ay_Apu* this, int i, struct Blip_Buffer* out )
63{
64 assert( (unsigned) i < ay_osc_count );
65 this->oscs [i].output = out;
66}
67
68// Emulates to time t, then subtracts t from the current time.
69// OK if previous write call had time slightly after t.
70static inline void Ay_apu_end_frame( struct Ay_Apu* this, blip_time_t time )
71{
72 if ( time > this->last_time )
73 run_until( this, time );
74
75 this->last_time -= time;
76 assert( this->last_time >= 0 );
77}
78
79#endif
diff --git a/apps/codecs/libgme/ay_cpu.c b/apps/codecs/libgme/ay_cpu.c
new file mode 100644
index 0000000000..5fbfe7c1ea
--- /dev/null
+++ b/apps/codecs/libgme/ay_cpu.c
@@ -0,0 +1,59 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "ay_emu.h"
4
5#include "blargg_endian.h"
6//#include "z80_cpu_log.h"
7
8/* Copyright (C) 2006-2008 Shay Green. This module is free software; you
9can redistribute it and/or modify it under the terms of the GNU Lesser
10General Public License as published by the Free Software Foundation; either
11version 2.1 of the License, or (at your option) any later version. This
12module is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15details. You should have received a copy of the GNU Lesser General Public
16License along with this module; if not, write to the Free Software Foundation,
17Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19#include "blargg_source.h"
20
21void cpu_out( struct Ay_Emu* this, cpu_time_t time, addr_t addr, int data )
22{
23 if ( (addr & 0xFF) == 0xFE )
24 {
25 check( !cpc_mode );
26 this->spectrum_mode = !this->cpc_mode;
27
28 // beeper_mask and last_beeper are 0 if (cpc_mode || !beeper_output)
29 if ( (data &= this->beeper_mask) != this->last_beeper )
30 {
31 this->last_beeper = data;
32 int delta = -this->beeper_delta;
33 this->beeper_delta = delta;
34 struct Blip_Buffer* bb = this->beeper_output;
35 Blip_set_modified( bb );
36 Synth_offset( &this->apu.synth_, time, delta, bb );
37 }
38 }
39 else
40 {
41 cpu_out_( this, time, addr, data );
42 }
43}
44
45#define OUT_PORT( addr, data ) cpu_out( this, TIME(), addr, data )
46#define IN_PORT( addr ) 0xFF // cpu in
47#define FLAT_MEM mem
48
49#define CPU_BEGIN \
50bool run_cpu( struct Ay_Emu* this, cpu_time_t end_time ) \
51{\
52 struct Z80_Cpu* cpu = &this->cpu; \
53 Z80_set_end_time( cpu, end_time ); \
54 byte* const mem = this->mem.ram; // cache
55
56 #include "z80_cpu_run.h"
57
58 return warning;
59}
diff --git a/apps/codecs/libgme/ay_emu.c b/apps/codecs/libgme/ay_emu.c
new file mode 100644
index 0000000000..dc775cbf79
--- /dev/null
+++ b/apps/codecs/libgme/ay_emu.c
@@ -0,0 +1,783 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "ay_emu.h"
4
5#include "blargg_endian.h"
6
7/* Copyright (C) 2006-2009 Shay Green. This module is free software; you
8can redistribute it and/or modify it under the terms of the GNU Lesser
9General Public License as published by the Free Software Foundation; either
10version 2.1 of the License, or (at your option) any later version. This
11module is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14details. You should have received a copy of the GNU Lesser General Public
15License along with this module; if not, write to the Free Software Foundation,
16Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17
18#include "blargg_source.h"
19
20int const stereo = 2; // number of channels for stereo
21int const silence_max = 6; // seconds
22int const silence_threshold = 0x10;
23long const fade_block_size = 512;
24int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
25
26const char* const gme_wrong_file_type = "Wrong file type for this emulator";
27
28// TODO: probably don't need detailed errors as to why file is corrupt
29
30int const spectrum_clock = 3546900; // 128K Spectrum
31int const spectrum_period = 70908;
32
33//int const spectrum_clock = 3500000; // 48K Spectrum
34//int const spectrum_period = 69888;
35
36int const cpc_clock = 2000000;
37
38void clear_track_vars( struct Ay_Emu *this )
39{
40 this->current_track = -1;
41 this->out_time = 0;
42 this->emu_time = 0;
43 this->emu_track_ended_ = true;
44 this->track_ended = true;
45 this->fade_start = INT_MAX / 2 + 1;
46 this->fade_step = 1;
47 this->silence_time = 0;
48 this->silence_count = 0;
49 this->buf_remain = 0;
50 /* warning(); // clear warning */
51}
52
53void Ay_init( struct Ay_Emu *this )
54{
55 this->sample_rate = 0;
56 this->mute_mask_ = 0;
57 this->tempo = 1.0;
58 this->gain = 1.0;
59 this->track_count = 0;
60
61 // defaults
62 this->max_initial_silence = 2;
63 this->ignore_silence = false;
64
65 this->voice_count = 0;
66 clear_track_vars( this );
67 this->beeper_output = NULL;
68 disable_beeper( this );
69
70 Ay_apu_init( &this->apu );
71 Z80_init( &this->cpu );
72
73 this->silence_lookahead = 6 ;
74}
75
76// Track info
77
78// Given pointer to 2-byte offset of data, returns pointer to data, or NULL if
79// offset is 0 or there is less than min_size bytes of data available.
80static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size )
81{
82 int offset = (int16_t) get_be16( ptr );
83 int pos = ptr - (byte const*) file->header;
84 int size = file->end - (byte const*) file->header;
85 assert( (unsigned) pos <= (unsigned) size - 2 );
86 int limit = size - min_size;
87 if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit )
88 return NULL;
89 return ptr + offset;
90}
91
92static blargg_err_t parse_header( byte const in [], int size, struct file_t* out )
93{
94 if ( size < header_size )
95 return gme_wrong_file_type;
96
97 out->header = (struct header_t const*) in;
98 out->end = in + size;
99 struct header_t const* h = (struct header_t const*) in;
100 if ( memcmp( h->tag, "ZXAYEMUL", 8 ) )
101 return gme_wrong_file_type;
102
103 out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 );
104 if ( !out->tracks )
105 return "missing track data";
106
107 return 0;
108}
109
110long Track_get_length( struct Ay_Emu* this, int n )
111{
112 long length = 0;
113
114 byte const* track_info = get_data( &this->file, this->file.tracks + n * 4 + 2, 6 );
115 if ( track_info )
116 length = get_be16( track_info + 4 ) * (1000 / 50); // frames to msec
117
118 if ( (this->m3u.size > 0) && (n < this->m3u.size) ) {
119 struct entry_t* entry = &this->m3u.entries [n];
120 length = entry->length;
121 }
122
123 if ( length <= 0 )
124 length = 120 * 1000; /* 2 minutes */
125
126 return length;
127}
128
129// Setup
130
131void change_clock_rate( struct Ay_Emu *this, long rate )
132{
133 this->clock_rate_ = rate;
134 Buffer_clock_rate( &this->stereo_buf, rate );
135}
136
137blargg_err_t Ay_load_mem( struct Ay_Emu *this, byte const in [], int size )
138{
139 assert( offsetof (struct header_t,track_info [2]) == header_size );
140
141 RETURN_ERR( parse_header( in, size, &this->file ) );
142
143 /* if ( file.header->vers > 2 )
144 warning( "Unknown file version" ); */
145
146 this->voice_count = ay_osc_count + 1; // +1 for beeper
147 Ay_apu_volume( &this->apu, this->gain );
148
149 // Setup buffer
150 change_clock_rate( this, spectrum_clock );
151 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
152
153 Sound_set_tempo( this, this->tempo );
154
155 // Remute voices
156 Sound_mute_voices( this, this->mute_mask_ );
157
158 this->track_count = this->file.header->max_track + 1;
159 this->m3u.size = 0;
160 return 0;
161}
162
163void set_beeper_output( struct Ay_Emu *this, struct Blip_Buffer* b )
164{
165 this->beeper_output = b;
166 if ( b && !this->cpc_mode )
167 this->beeper_mask = 0x10;
168 else
169 disable_beeper( this );
170}
171
172void set_voice( struct Ay_Emu *this, int i, struct Blip_Buffer* center )
173{
174 if ( i >= ay_osc_count )
175 set_beeper_output( this, center );
176 else
177 Ay_apu_set_output( &this->apu, i, center );
178}
179
180blargg_err_t run_clocks( struct Ay_Emu *this, blip_time_t* duration, int msec )
181{
182#if defined(ROCKBOX)
183 (void) msec;
184#endif
185
186 cpu_time_t *end = duration;
187 struct Z80_Cpu* cpu = &this->cpu;
188 Z80_set_time( cpu, 0 );
189
190 // Since detection of CPC mode will halve clock rate during the frame
191 // and thus generate up to twice as much sound, we must generate half
192 // as much until mode is known.
193 if ( !(this->spectrum_mode | this->cpc_mode) )
194 *end /= 2;
195
196 while ( Z80_time( cpu ) < *end )
197 {
198 run_cpu( this, min( *end, this->next_play ) );
199
200 if ( Z80_time( cpu ) >= this->next_play )
201 {
202 // next frame
203 this->next_play += this->play_period;
204
205 if ( cpu->r.iff1 )
206 {
207 // interrupt enabled
208
209 if ( this->mem.ram [cpu->r.pc] == 0x76 )
210 cpu->r.pc++; // advance past HALT instruction
211
212 cpu->r.iff1 = 0;
213 cpu->r.iff2 = 0;
214
215 this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc >> 8);
216 this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc);
217
218 // fixed interrupt
219 cpu->r.pc = 0x38;
220 Z80_adjust_time( cpu, 12 );
221
222 if ( cpu->r.im == 2 )
223 {
224 // vectored interrupt
225 addr_t addr = cpu->r.i * 0x100 + 0xFF;
226 cpu->r.pc = this->mem.ram [(addr + 1) & 0xFFFF] * 0x100 + this->mem.ram [addr];
227 Z80_adjust_time( cpu, 6 );
228 }
229 }
230 }
231 }
232
233 // End time frame
234 *end = Z80_time( cpu );
235 this->next_play -= *end;
236 check( this->next_play >= 0 );
237 Z80_adjust_time( cpu, -*end );
238 Ay_apu_end_frame( &this->apu, *end );
239 return 0;
240}
241
242// Emulation
243
244void cpu_out_( struct Ay_Emu *this, cpu_time_t time, addr_t addr, int data )
245{
246 // Spectrum
247 if ( !this->cpc_mode )
248 {
249 switch ( addr & 0xFEFF )
250 {
251 case 0xFEFD:
252 this->spectrum_mode = true;
253 Ay_apu_write_addr( &this->apu, data );
254 return;
255
256 case 0xBEFD:
257 this->spectrum_mode = true;
258 Ay_apu_write_data( &this->apu, time, data );
259 return;
260 }
261 }
262
263 // CPC
264 if ( !this->spectrum_mode )
265 {
266 switch ( addr >> 8 )
267 {
268 case 0xF6:
269 switch ( data & 0xC0 )
270 {
271 case 0xC0:
272 Ay_apu_write_addr( &this->apu, this->cpc_latch );
273 goto enable_cpc;
274
275 case 0x80:
276 Ay_apu_write_data( &this->apu, time, this->cpc_latch );
277 goto enable_cpc;
278 }
279 break;
280
281 case 0xF4:
282 this->cpc_latch = data;
283 goto enable_cpc;
284 }
285 }
286
287 /* dprintf( "Unmapped OUT: $%04X <- $%02X\n", addr, data ); */
288 return;
289
290enable_cpc:
291 if ( !this->cpc_mode )
292 {
293 this->cpc_mode = true;
294 disable_beeper( this );
295
296 change_clock_rate( this, cpc_clock );
297 Sound_set_tempo( this, this->tempo );
298 }
299}
300
301blargg_err_t Ay_set_sample_rate( struct Ay_Emu *this, long rate )
302{
303 require( !this->sample_rate ); // sample rate can't be changed once set
304 Buffer_init( &this->stereo_buf );
305 RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) );
306
307 // Set buffer bass
308 Buffer_bass_freq( &this->stereo_buf, 160 );
309
310 this->sample_rate = rate;
311 return 0;
312}
313
314void Sound_mute_voice( struct Ay_Emu *this, int index, bool mute )
315{
316 require( (unsigned) index < (unsigned) this->voice_count );
317 int bit = 1 << index;
318 int mask = this->mute_mask_ | bit;
319 if ( !mute )
320 mask ^= bit;
321 Sound_mute_voices( this, mask );
322}
323
324void Sound_mute_voices( struct Ay_Emu *this, int mask )
325{
326 require( this->sample_rate ); // sample rate must be set first
327 this->mute_mask_ = mask;
328
329 int i;
330 for ( i = this->voice_count; i--; )
331 {
332 if ( mask & (1 << i) )
333 {
334 set_voice( this, i, 0 );
335 }
336 else
337 {
338 struct channel_t ch = Buffer_channel( &this->stereo_buf );
339 assert( (ch.center && ch.left && ch.right) ||
340 (!ch.center && !ch.left && !ch.right) ); // all or nothing
341 set_voice( this, i, ch.center );
342 }
343 }
344}
345
346void Sound_set_tempo( struct Ay_Emu *this, double t )
347{
348 require( this->sample_rate ); // sample rate must be set first
349 double const min = 0.02;
350 double const max = 4.00;
351 if ( t < min ) t = min;
352 if ( t > max ) t = max;
353 this->tempo = t;
354
355 int p = spectrum_period;
356 if ( this->clock_rate_ != spectrum_clock )
357 p = this->clock_rate_ / 50;
358
359 this->play_period = (blip_time_t) (p / t);
360}
361
362void fill_buf( struct Ay_Emu *this ) ICODE_ATTR;;
363blargg_err_t Ay_start_track( struct Ay_Emu *this, int track )
364{
365 clear_track_vars( this );
366
367 // Remap track if playlist available
368 if ( this->m3u.size > 0 ) {
369 struct entry_t* e = &this->m3u.entries[track];
370 track = e->track;
371 }
372
373 this->current_track = track;
374 Buffer_clear( &this->stereo_buf );
375
376 byte* const mem = this->mem.ram;
377
378 memset( mem + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET
379 memset( mem + 0x0100, 0xFF, 0x4000 - 0x100 );
380 memset( mem + ram_addr, 0x00, mem_size - ram_addr );
381
382 // locate data blocks
383 byte const* const data = get_data( &this->file, this->file.tracks + track * 4 + 2, 14 );
384 if ( !data )
385 return "file data missing";
386
387 byte const* const more_data = get_data( &this->file, data + 10, 6 );
388 if ( !more_data )
389 return "file data missing";
390
391 byte const* blocks = get_data( &this->file, data + 12, 8 );
392 if ( !blocks )
393 return "file data missing";
394
395 // initial addresses
396 unsigned addr = get_be16( blocks );
397 if ( !addr )
398 return "file data missing";
399
400 unsigned init = get_be16( more_data + 2 );
401 if ( !init )
402 init = addr;
403
404 // copy blocks into memory
405 do
406 {
407 blocks += 2;
408 unsigned len = get_be16( blocks ); blocks += 2;
409 if ( addr + len > mem_size )
410 {
411 /* warning( "Bad data block size" ); */
412 len = mem_size - addr;
413 }
414 check( len );
415 byte const* in = get_data( &this->file, blocks, 0 ); blocks += 2;
416 if ( len > (unsigned) (this->file.end - in) )
417 {
418 /* warning( "File data missing" ); */
419 len = this->file.end - in;
420 }
421
422 memcpy( mem + addr, in, len );
423
424 if ( this->file.end - blocks < 8 )
425 {
426 /* warning( "File data missing" ); */
427 break;
428 }
429 }
430 while ( (addr = get_be16( blocks )) != 0 );
431
432 // copy and configure driver
433 static byte const passive [] = {
434 0xF3, // DI
435 0xCD, 0, 0, // CALL init
436 0xED, 0x5E, // LOOP: IM 2
437 0xFB, // EI
438 0x76, // HALT
439 0x18, 0xFA // JR LOOP
440 };
441 static byte const active [] = {
442 0xF3, // DI
443 0xCD, 0, 0, // CALL init
444 0xED, 0x56, // LOOP: IM 1
445 0xFB, // EI
446 0x76, // HALT
447 0xCD, 0, 0, // CALL play
448 0x18, 0xF7 // JR LOOP
449 };
450 memcpy( mem, passive, sizeof passive );
451 int const play_addr = get_be16( more_data + 4 );
452 if ( play_addr )
453 {
454 memcpy( mem, active, sizeof active );
455 mem [ 9] = play_addr;
456 mem [10] = play_addr >> 8;
457 }
458 mem [2] = init;
459 mem [3] = init >> 8;
460
461 mem [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET)
462
463 // start at spectrum speed
464 change_clock_rate( this, spectrum_clock );
465 Sound_set_tempo( this, this->tempo );
466
467 struct registers_t r;
468 memset( &r, 0, sizeof(struct registers_t) );
469
470 r.sp = get_be16( more_data );
471 r.b.a = r.b.b = r.b.d = r.b.h = data [8];
472 r.b.flags = r.b.c = r.b.e = r.b.l = data [9];
473 r.alt.w = r.w;
474 r.ix = r.iy = r.w.hl;
475
476 memset( this->mem.padding1, 0xFF, sizeof this->mem.padding1 );
477
478 int const mirrored = 0x80; // this much is mirrored after end of memory
479 memset( this->mem.ram + mem_size + mirrored, 0xFF, sizeof this->mem.ram - mem_size - mirrored );
480 memcpy( this->mem.ram + mem_size, this->mem.ram, mirrored ); // some code wraps around (ugh)
481
482 Z80_reset( &this->cpu, this->mem.padding1, this->mem.padding1 );
483 Z80_map_mem( &this->cpu, 0, mem_size, this->mem.ram, this->mem.ram );
484 this->cpu.r = r;
485
486 this->beeper_delta = (int) (ay_amp_range * 0.8);
487 this->last_beeper = 0;
488 this->next_play = this->play_period;
489 this->spectrum_mode = false;
490 this->cpc_mode = false;
491 this->cpc_latch = 0;
492 set_beeper_output( this, this->beeper_output );
493 Ay_apu_reset( &this->apu );
494
495 // a few tunes rely on channels having tone enabled at the beginning
496 Ay_apu_write_addr( &this->apu, 7 );
497 Ay_apu_write_data( &this->apu, 0, 0x38 );
498
499 this->emu_track_ended_ = false;
500 this->track_ended = false;
501
502 if ( !this->ignore_silence )
503 {
504 // play until non-silence or end of track
505 long end;
506 for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; )
507 {
508 fill_buf( this );
509 if ( this->buf_remain | (int) this->emu_track_ended_ )
510 break;
511 }
512
513 this->emu_time = this->buf_remain;
514 this->out_time = 0;
515 this->silence_time = 0;
516 this->silence_count = 0;
517 }
518 /* return track_ended() ? warning() : 0; */
519 return 0;
520}
521
522// Tell/Seek
523
524blargg_long msec_to_samples( blargg_long msec, long sample_rate )
525{
526 blargg_long sec = msec / 1000;
527 msec -= sec * 1000;
528 return (sec * sample_rate + msec * sample_rate / 1000) * stereo;
529}
530
531long Track_tell( struct Ay_Emu *this )
532{
533 blargg_long rate = this->sample_rate * stereo;
534 blargg_long sec = this->out_time / rate;
535 return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate;
536}
537
538blargg_err_t Track_seek( struct Ay_Emu *this, long msec )
539{
540 blargg_long time = msec_to_samples( msec, this->sample_rate );
541 if ( time < this->out_time )
542 RETURN_ERR( Ay_start_track( this, this->current_track ) );
543 return Track_skip( this, time - this->out_time );
544}
545
546blargg_err_t play_( struct Ay_Emu *this, long count, sample_t* out ) ICODE_ATTR;
547blargg_err_t skip_( struct Ay_Emu *this, long count )
548{
549 // for long skip, mute sound
550 const long threshold = 30000;
551 if ( count > threshold )
552 {
553 int saved_mute = this->mute_mask_;
554 Sound_mute_voices( this, ~0 );
555
556 while ( count > threshold / 2 && !this->emu_track_ended_ )
557 {
558 RETURN_ERR( play_( this, buf_size, this->buf ) );
559 count -= buf_size;
560 }
561
562 Sound_mute_voices( this, saved_mute );
563 }
564
565 while ( count && !this->emu_track_ended_ )
566 {
567 long n = buf_size;
568 if ( n > count )
569 n = count;
570 count -= n;
571 RETURN_ERR( play_( this, n, this->buf ) );
572 }
573 return 0;
574}
575
576blargg_err_t Track_skip( struct Ay_Emu *this, long count )
577{
578 require( this->current_track >= 0 ); // start_track() must have been called already
579 this->out_time += count;
580
581 // remove from silence and buf first
582 {
583 long n = min( count, this->silence_count );
584 this->silence_count -= n;
585 count -= n;
586
587 n = min( count, this->buf_remain );
588 this->buf_remain -= n;
589 count -= n;
590 }
591
592 if ( count && !this->emu_track_ended_ )
593 {
594 this->emu_time += count;
595
596 // End track if error
597 if ( skip_( this, count ) )
598 this->emu_track_ended_ = true;
599 }
600
601 if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended
602 this->track_ended |= this->emu_track_ended_;
603
604 return 0;
605}
606
607// Fading
608
609void Track_set_fade( struct Ay_Emu *this, long start_msec, long length_msec )
610{
611 this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo);
612 this->fade_start = msec_to_samples( start_msec, this->sample_rate );
613}
614
615// unit / pow( 2.0, (double) x / step )
616static int int_log( blargg_long x, int step, int unit )
617{
618 int shift = x / step;
619 int fraction = (x - shift * step) * unit / step;
620 return ((unit - fraction) + (fraction >> 1)) >> shift;
621}
622
623void handle_fade( struct Ay_Emu *this, long out_count, sample_t* out )
624{
625 int i;
626 for ( i = 0; i < out_count; i += fade_block_size )
627 {
628 int const shift = 14;
629 int const unit = 1 << shift;
630 int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size,
631 this->fade_step, unit );
632 if ( gain < (unit >> fade_shift) )
633 this->track_ended = this->emu_track_ended_ = true;
634
635 sample_t* io = &out [i];
636 int count;
637 for ( count = min( fade_block_size, out_count - i ); count; --count )
638 {
639 *io = (sample_t) ((*io * gain) >> shift);
640 ++io;
641 }
642 }
643}
644
645// Silence detection
646
647void emu_play( struct Ay_Emu *this, long count, sample_t* out )
648{
649 check( current_track_ >= 0 );
650 this->emu_time += count;
651 if ( this->current_track >= 0 && !this->emu_track_ended_ ) {
652 if ( play_( this, count, out ) )
653 this->emu_track_ended_ = true;
654 }
655 else
656 memset( out, 0, count * sizeof *out );
657}
658
659// number of consecutive silent samples at end
660static long count_silence( sample_t* begin, long size )
661{
662 sample_t first = *begin;
663 *begin = silence_threshold; // sentinel
664 sample_t* p = begin + size;
665 while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { }
666 *begin = first;
667 return size - (p - begin);
668}
669
670// fill internal buffer and check it for silence
671void fill_buf( struct Ay_Emu *this )
672{
673 assert( !this->buf_remain );
674 if ( !this->emu_track_ended_ )
675 {
676 emu_play( this, buf_size, this->buf );
677 long silence = count_silence( this->buf, buf_size );
678 if ( silence < buf_size )
679 {
680 this->silence_time = this->emu_time - silence;
681 this->buf_remain = buf_size;
682 return;
683 }
684 }
685 this->silence_count += buf_size;
686}
687
688blargg_err_t Ay_play( struct Ay_Emu *this, long out_count, sample_t* out )
689{
690 if ( this->track_ended )
691 {
692 memset( out, 0, out_count * sizeof *out );
693 }
694 else
695 {
696 require( this->current_track >= 0 );
697 require( out_count % stereo == 0 );
698
699 assert( this->emu_time >= this->out_time );
700
701 // prints nifty graph of how far ahead we are when searching for silence
702 //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" );
703
704 long pos = 0;
705 if ( this->silence_count )
706 {
707 // during a run of silence, run emulator at >=2x speed so it gets ahead
708 long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time;
709 while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) )
710 fill_buf( this );
711
712 // fill with silence
713 pos = min( this->silence_count, out_count );
714 memset( out, 0, pos * sizeof *out );
715 this->silence_count -= pos;
716
717 if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate )
718 {
719 this->track_ended = this->emu_track_ended_ = true;
720 this->silence_count = 0;
721 this->buf_remain = 0;
722 }
723 }
724
725 if ( this->buf_remain )
726 {
727 // empty silence buf
728 long n = min( this->buf_remain, out_count - pos );
729 memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out );
730 this->buf_remain -= n;
731 pos += n;
732 }
733
734 // generate remaining samples normally
735 long remain = out_count - pos;
736 if ( remain )
737 {
738 emu_play( this, remain, out + pos );
739 this->track_ended |= this->emu_track_ended_;
740
741 if ( !this->ignore_silence || this->out_time > this->fade_start )
742 {
743 // check end for a new run of silence
744 long silence = count_silence( out + pos, remain );
745 if ( silence < remain )
746 this->silence_time = this->emu_time - silence;
747
748 if ( this->emu_time - this->silence_time >= buf_size )
749 fill_buf( this ); // cause silence detection on next play()
750 }
751 }
752
753 if ( this->out_time > this->fade_start )
754 handle_fade( this, out_count, out );
755 }
756 this->out_time += out_count;
757 return 0;
758}
759
760blargg_err_t play_( struct Ay_Emu *this, long count, sample_t* out )
761{
762 long remain = count;
763 while ( remain )
764 {
765 remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain );
766 if ( remain )
767 {
768 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) )
769 {
770 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
771
772 // Remute voices
773 Sound_mute_voices( this, this->mute_mask_ );
774 }
775 int msec = Buffer_length( &this->stereo_buf );
776 blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate_ / 1000 - 100;
777 RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) );
778 assert( clocks_emulated );
779 Buffer_end_frame( &this->stereo_buf, clocks_emulated );
780 }
781 }
782 return 0;
783}
diff --git a/apps/codecs/libgme/ay_emu.h b/apps/codecs/libgme/ay_emu.h
new file mode 100644
index 0000000000..91252166e4
--- /dev/null
+++ b/apps/codecs/libgme/ay_emu.h
@@ -0,0 +1,172 @@
1// Sinclair Spectrum AY music file emulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef AY_EMU_H
5#define AY_EMU_H
6
7#include "blargg_source.h"
8
9#include "multi_buffer.h"
10#include "z80_cpu.h"
11#include "ay_apu.h"
12#include "m3u_playlist.h"
13
14typedef short sample_t;
15
16// 64K memory to load code and data into before starting track. Caller
17// must parse the AY file.
18enum { mem_size = 0x10000 };
19enum { ram_addr = 0x4000 }; // where official RAM starts
20enum { buf_size = 2048 };
21
22// AY file header
23enum { header_size = 0x14 };
24struct header_t
25{
26 byte tag [8];
27 byte vers;
28 byte player;
29 byte unused [2];
30 byte author [2];
31 byte comment [2];
32 byte max_track;
33 byte first_track;
34 byte track_info [2];
35};
36
37struct file_t {
38 struct header_t const* header;
39 byte const* tracks;
40 byte const* end; // end of file data
41};
42
43struct mem_t {
44 uint8_t padding1 [0x100];
45 uint8_t ram [mem_size + 0x100];
46};
47
48struct Ay_Emu {
49 struct file_t file;
50
51 struct Blip_Buffer* beeper_output;
52 int beeper_delta;
53 int last_beeper;
54 int beeper_mask;
55
56 addr_t play_addr;
57 cpu_time_t play_period;
58 cpu_time_t next_play;
59
60 int cpc_latch;
61 bool spectrum_mode;
62 bool cpc_mode;
63
64 // general
65 int max_initial_silence;
66 int voice_count;
67 int mute_mask_;
68 double tempo;
69 double gain;
70
71 long sample_rate;
72
73 // track-specific
74 int current_track;
75 int track_count;
76 blargg_long out_time; // number of samples played since start of track
77 blargg_long emu_time; // number of samples emulator has generated since start of track
78 volatile bool track_ended;
79 bool emu_track_ended_; // emulator has reached end of track
80
81 // fading
82 blargg_long fade_start;
83 int fade_step;
84
85 // silence detection
86 bool ignore_silence;
87 int silence_lookahead; // speed to run emulator when looking ahead for silence
88 long silence_time; // number of samples where most recent silence began
89 long silence_count; // number of samples of silence to play before using buf
90 long buf_remain; // number of samples left in silence buffer
91
92 long clock_rate_;
93 unsigned buf_changed_count;
94
95 // M3u Playlist
96 struct M3u_Playlist m3u;
97
98 // large items
99 struct Ay_Apu apu;
100 sample_t buf [buf_size];
101 struct Stereo_Buffer stereo_buf; // NULL if using custom buffer
102 struct Z80_Cpu cpu;
103 struct mem_t mem;
104};
105
106// Basic functionality (see Gme_File.h for file loading/track info functions)
107void Ay_init( struct Ay_Emu* this );
108
109blargg_err_t Ay_load_mem( struct Ay_Emu* this, byte const in [], int size );
110
111// Set output sample rate. Must be called only once before loading file.
112blargg_err_t Ay_set_sample_rate( struct Ay_Emu* this, long sample_rate );
113
114// Start a track, where 0 is the first track. Also clears warning string.
115blargg_err_t Ay_start_track( struct Ay_Emu* this, int track );
116
117// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation
118// errors set warning string, and major errors also end track.
119blargg_err_t Ay_play( struct Ay_Emu* this, long count, sample_t* buf );
120
121
122// Track status/control
123
124// Number of milliseconds (1000 msec = 1 second) played since beginning of track
125long Track_tell( struct Ay_Emu* this );
126
127// Seek to new time in track. Seeking backwards or far forward can take a while.
128blargg_err_t Track_seek( struct Ay_Emu* this, long msec );
129
130// Skip n samples
131blargg_err_t Track_skip( struct Ay_Emu* this, long n );
132
133// Set start time and length of track fade out. Once fade ends track_ended() returns
134// true. Fade time can be changed while track is playing.
135void Track_set_fade( struct Ay_Emu* this, long start_msec, long length_msec );
136
137// Get track length in milliseconds
138long Track_get_length( struct Ay_Emu* this, int n );
139
140// Sound customization
141
142// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed.
143// Track length as returned by track_info() assumes a tempo of 1.0.
144void Sound_set_tempo( struct Ay_Emu* this, double t );
145
146// Mute/unmute voice i, where voice 0 is first voice
147void Sound_mute_voice( struct Ay_Emu* this, int index, bool mute );
148
149// Set muting state of all voices at once using a bit mask, where -1 mutes them all,
150// 0 unmutes them all, 0x01 mutes just the first voice, etc.
151void Sound_mute_voices( struct Ay_Emu* this, int mask );
152
153// Change overall output amplitude, where 1.0 results in minimal clamping.
154// Must be called before set_sample_rate().
155static inline void Sound_set_gain( struct Ay_Emu* this, double g )
156{
157 assert( !this->sample_rate ); // you must set gain before setting sample rate
158 this->gain = g;
159}
160
161// Emulation (You shouldn't touch these)
162void cpu_out( struct Ay_Emu* this, cpu_time_t, addr_t, int data );
163void cpu_out_( struct Ay_Emu* this, cpu_time_t, addr_t, int data );
164bool run_cpu( struct Ay_Emu* this, cpu_time_t end );
165
166static inline void disable_beeper( struct Ay_Emu *this )
167{
168 this->beeper_mask = 0;
169 this->last_beeper = 0;
170}
171
172#endif
diff --git a/apps/codecs/libgme/blargg_common.h b/apps/codecs/libgme/blargg_common.h
new file mode 100644
index 0000000000..be34379441
--- /dev/null
+++ b/apps/codecs/libgme/blargg_common.h
@@ -0,0 +1,159 @@
1// Sets up common environment for Shay Green's libraries.
2// To change configuration options, modify blargg_config.h, not this file.
3
4#ifndef BLARGG_COMMON_H
5#define BLARGG_COMMON_H
6
7#include <stddef.h>
8#include <stdlib.h>
9#include <string.h>
10#include <assert.h>
11#include <limits.h>
12
13#undef BLARGG_COMMON_H
14// allow blargg_config.h to #include blargg_common.h
15#include "blargg_config.h"
16#ifndef BLARGG_COMMON_H
17#define BLARGG_COMMON_H
18
19#if defined(ROCKBOX)
20#include "codeclib.h"
21#endif
22
23#if 1 /* IRAM configuration is not yet active for all libGME codecs. */
24 #undef ICODE_ATTR
25 #define ICODE_ATTR
26
27 #undef IDATA_ATTR
28 #define IDATA_ATTR
29
30 #undef ICONST_ATTR
31 #define ICONST_ATTR
32
33 #undef IBSS_ATTR
34 #define IBSS_ATTR
35#endif
36
37// BLARGG_RESTRICT: equivalent to C99's restrict, where supported
38#if __GNUC__ >= 3 || _MSC_VER >= 1100
39 #define BLARGG_RESTRICT __restrict
40#else
41 #define BLARGG_RESTRICT
42#endif
43
44// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
45#ifndef STATIC_CAST
46 #define STATIC_CAST(T,expr) ((T) (expr))
47#endif
48
49// blargg_err_t (0 on success, otherwise error string)
50#ifndef blargg_err_t
51 typedef const char* blargg_err_t;
52#endif
53
54#define BLARGG_4CHAR( a, b, c, d ) \
55 ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF))
56
57// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
58#ifndef BOOST_STATIC_ASSERT
59 #ifdef _MSC_VER
60 // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified
61 #define BOOST_STATIC_ASSERT( expr ) \
62 void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] )
63 #else
64 // Some other compilers fail when declaring same function multiple times in class,
65 // so differentiate them by line
66 #define BOOST_STATIC_ASSERT( expr ) \
67 void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] )
68 #endif
69#endif
70
71// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1,
72// compiler is assumed to support bool. If undefined, availability is determined.
73#ifndef BLARGG_COMPILER_HAS_BOOL
74 #if defined (__MWERKS__)
75 #if !__option(bool)
76 #define BLARGG_COMPILER_HAS_BOOL 0
77 #endif
78 #elif defined (_MSC_VER)
79 #if _MSC_VER < 1100
80 #define BLARGG_COMPILER_HAS_BOOL 0
81 #endif
82 #elif defined (__GNUC__)
83 // supports bool
84 #elif __cplusplus < 199711
85 #define BLARGG_COMPILER_HAS_BOOL 0
86 #endif
87#endif
88#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
89 // If you get errors here, modify your blargg_config.h file
90 typedef int bool;
91 static bool true = 1;
92 static bool false = 0;
93#endif
94
95// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough
96#include <limits.h>
97
98#if INT_MAX >= 0x7FFFFFFF
99 typedef int blargg_long;
100#else
101 typedef long blargg_long;
102#endif
103
104#if UINT_MAX >= 0xFFFFFFFF
105 typedef unsigned blargg_ulong;
106#else
107 typedef unsigned long blargg_ulong;
108#endif
109
110// int8_t etc.
111
112
113// ROCKBOX: If defined, use <codeclib.h> for int_8_t etc
114#if defined (ROCKBOX)
115 #include <codecs/lib/codeclib.h>
116// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
117#elif defined (HAVE_STDINT_H)
118 #include <stdint.h>
119 #define BOOST
120
121// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
122#elif defined (HAVE_INTTYPES_H)
123 #include <inttypes.h>
124 #define BOOST
125
126#else
127 #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F
128 typedef signed char int8_t;
129 typedef unsigned char uint8_t;
130 #else
131 // No suitable 8-bit type available
132 typedef struct see_blargg_common_h int8_t;
133 typedef struct see_blargg_common_h uint8_t;
134 #endif
135
136 #if USHRT_MAX == 0xFFFF
137 typedef short int16_t;
138 typedef unsigned short uint16_t;
139 #else
140 // No suitable 16-bit type available
141 typedef struct see_blargg_common_h int16_t;
142 typedef struct see_blargg_common_h uint16_t;
143 #endif
144
145 #if ULONG_MAX == 0xFFFFFFFF
146 typedef long int32_t;
147 typedef unsigned long uint32_t;
148 #elif UINT_MAX == 0xFFFFFFFF
149 typedef int int32_t;
150 typedef unsigned int uint32_t;
151 #else
152 // No suitable 32-bit type available
153 typedef struct see_blargg_common_h int32_t;
154 typedef struct see_blargg_common_h uint32_t;
155 #endif
156#endif
157
158#endif
159#endif
diff --git a/apps/codecs/libgme/blargg_config.h b/apps/codecs/libgme/blargg_config.h
new file mode 100644
index 0000000000..6490c15cfb
--- /dev/null
+++ b/apps/codecs/libgme/blargg_config.h
@@ -0,0 +1,42 @@
1// Library configuration. Modify this file as necessary.
2
3#ifndef BLARGG_CONFIG_H
4#define BLARGG_CONFIG_H
5
6// Uncomment to enable platform-specific optimizations
7//#define BLARGG_NONPORTABLE 1
8
9// Uncomment if automatic byte-order determination doesn't work
10#ifdef ROCKBOX_BIG_ENDIAN
11 #define BLARGG_BIG_ENDIAN 1
12#endif
13
14// Uncomment if you get errors in the bool section of blargg_common.h
15#define BLARGG_COMPILER_HAS_BOOL 1
16
17// Uncomment to use fast gb apu implementation
18// #define GB_APU_FAST 1
19
20// Uncomment to remove agb emulation support
21// #define GB_APU_NO_AGB 1
22
23// Uncomment to emulate only nes apu
24// #define NSF_EMU_APU_ONLY 1
25
26// Uncomment to remove vrc7 apu support
27// #define NSF_EMU_NO_VRC7 1
28
29// Uncomment to remove fmopl apu support
30// #define KSS_EMU_NO_FMOPL 1
31
32// To handle undefined reference to assert
33#define NDEBUG 1
34
35// Use standard config.h if present
36#define HAVE_CONFIG_H 1
37
38#ifdef HAVE_CONFIG_H
39 #include "config.h"
40#endif
41
42#endif
diff --git a/apps/codecs/libgme/blargg_endian.h b/apps/codecs/libgme/blargg_endian.h
new file mode 100644
index 0000000000..ae55d7fd3b
--- /dev/null
+++ b/apps/codecs/libgme/blargg_endian.h
@@ -0,0 +1,147 @@
1// CPU Byte Order Utilities
2
3// Game_Music_Emu 0.5.2
4#ifndef BLARGG_ENDIAN
5#define BLARGG_ENDIAN
6
7#include "blargg_common.h"
8
9// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
10#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
11 defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
12 #define BLARGG_CPU_X86 1
13 #define BLARGG_CPU_CISC 1
14#endif
15
16#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc)
17 #define BLARGG_CPU_POWERPC 1
18#endif
19
20// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
21// one may be #defined to 1. Only needed if something actually depends on byte order.
22#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
23#ifdef __GLIBC__
24 // GCC handles this for us
25 #include <endian.h>
26 #if __BYTE_ORDER == __LITTLE_ENDIAN
27 #define BLARGG_LITTLE_ENDIAN 1
28 #elif __BYTE_ORDER == __BIG_ENDIAN
29 #define BLARGG_BIG_ENDIAN 1
30 #endif
31#else
32
33#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || defined (BLARGG_CPU_X86) || \
34 (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234)
35 #define BLARGG_LITTLE_ENDIAN 1
36#endif
37
38#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \
39 defined (__mips__) || defined (__sparc__) || defined (BLARGG_CPU_POWERPC) || \
40 (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321)
41 #define BLARGG_BIG_ENDIAN 1
42#else
43 // No endian specified; assume little-endian, since it's most common
44 #define BLARGG_LITTLE_ENDIAN 1
45#endif
46#endif
47#endif
48
49#if defined (BLARGG_LITTLE_ENDIAN) && defined(BLARGG_BIG_ENDIAN)
50 #undef BLARGG_LITTLE_ENDIAN
51 #undef BLARGG_BIG_ENDIAN
52#endif
53
54static inline void blargg_verify_byte_order( void )
55{
56 #ifndef NDEBUG
57 #if BLARGG_BIG_ENDIAN
58 volatile int i = 1;
59 assert( *(volatile char*) &i == 0 );
60 #elif BLARGG_LITTLE_ENDIAN
61 volatile int i = 1;
62 assert( *(volatile char*) &i != 0 );
63 #endif
64 #endif
65}
66
67static inline unsigned get_le16( void const* p ) {
68 return ((unsigned char const*) p) [1] * 0x100u +
69 ((unsigned char const*) p) [0];
70}
71static inline unsigned get_be16( void const* p ) {
72 return ((unsigned char const*) p) [0] * 0x100u +
73 ((unsigned char const*) p) [1];
74}
75static inline blargg_ulong get_le32( void const* p ) {
76 return ((unsigned char const*) p) [3] * 0x01000000u +
77 ((unsigned char const*) p) [2] * 0x00010000u +
78 ((unsigned char const*) p) [1] * 0x00000100u +
79 ((unsigned char const*) p) [0];
80}
81static inline blargg_ulong get_be32( void const* p ) {
82 return ((unsigned char const*) p) [0] * 0x01000000u +
83 ((unsigned char const*) p) [1] * 0x00010000u +
84 ((unsigned char const*) p) [2] * 0x00000100u +
85 ((unsigned char const*) p) [3];
86}
87static inline void set_le16( void* p, unsigned n ) {
88 ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
89 ((unsigned char*) p) [0] = (unsigned char) n;
90}
91static inline void set_be16( void* p, unsigned n ) {
92 ((unsigned char*) p) [0] = (unsigned char) (n >> 8);
93 ((unsigned char*) p) [1] = (unsigned char) n;
94}
95static inline void set_le32( void* p, blargg_ulong n ) {
96 ((unsigned char*) p) [3] = (unsigned char) (n >> 24);
97 ((unsigned char*) p) [2] = (unsigned char) (n >> 16);
98 ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
99 ((unsigned char*) p) [0] = (unsigned char) n;
100}
101static inline void set_be32( void* p, blargg_ulong n ) {
102 ((unsigned char*) p) [0] = (unsigned char) (n >> 24);
103 ((unsigned char*) p) [1] = (unsigned char) (n >> 16);
104 ((unsigned char*) p) [2] = (unsigned char) (n >> 8);
105 ((unsigned char*) p) [3] = (unsigned char) n;
106}
107
108#if defined(BLARGG_NONPORTABLE)
109 // Optimized implementation if byte order is known
110 #if defined(BLARGG_LITTLE_ENDIAN)
111 #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr))
112 #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr))
113 #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
114 #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
115 #elif defined(BLARGG_BIG_ENDIAN)
116 #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr))
117 #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr))
118 #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
119 #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
120 #endif
121
122 #if defined(BLARGG_CPU_POWERPC) && defined (__MWERKS__)
123 // PowerPC has special byte-reversed instructions
124 // to do: assumes that PowerPC is running in big-endian mode
125 // to do: implement for other compilers which don't support these macros
126 #define GET_LE16( addr ) (__lhbrx( (addr), 0 ))
127 #define GET_LE32( addr ) (__lwbrx( (addr), 0 ))
128 #define SET_LE16( addr, data ) (__sthbrx( (data), (addr), 0 ))
129 #define SET_LE32( addr, data ) (__stwbrx( (data), (addr), 0 ))
130 #endif
131#endif
132
133#ifndef GET_LE16
134 #define GET_LE16( addr ) get_le16( addr )
135 #define GET_LE32( addr ) get_le32( addr )
136 #define SET_LE16( addr, data ) set_le16( addr, data )
137 #define SET_LE32( addr, data ) set_le32( addr, data )
138#endif
139
140#ifndef GET_BE16
141 #define GET_BE16( addr ) get_be16( addr )
142 #define GET_BE32( addr ) get_be32( addr )
143 #define SET_BE16( addr, data ) set_be16( addr, data )
144 #define SET_BE32( addr, data ) set_be32( addr, data )
145#endif
146
147#endif
diff --git a/apps/codecs/libgme/blargg_source.h b/apps/codecs/libgme/blargg_source.h
new file mode 100644
index 0000000000..4bea02a48b
--- /dev/null
+++ b/apps/codecs/libgme/blargg_source.h
@@ -0,0 +1,71 @@
1// Included at the beginning of library source files, after all other #include lines
2#ifndef BLARGG_SOURCE_H
3#define BLARGG_SOURCE_H
4
5// If debugging is enabled, abort program if expr is false. Meant for checking
6// internal state and consistency. A failed assertion indicates a bug in the module.
7// void assert( bool expr );
8#include <assert.h>
9
10// If debugging is enabled and expr is false, abort program. Meant for checking
11// caller-supplied parameters and operations that are outside the control of the
12// module. A failed requirement indicates a bug outside the module.
13// void require( bool expr );
14#if defined(ROCKBOX)
15#undef require
16#define require( expr )
17#else
18#undef require
19#define require( expr ) assert( expr )
20#endif
21
22// Like printf() except output goes to debug log file. Might be defined to do
23// nothing (not even evaluate its arguments).
24// void dprintf( const char* format, ... );
25#if defined(ROCKBOX)
26#define dprintf DEBUGF
27#else
28static inline void blargg_dprintf_( const char* fmt, ... ) { }
29#undef dprintf
30#define dprintf (1) ? (void) 0 : blargg_dprintf_
31#endif
32
33// If enabled, evaluate expr and if false, make debug log entry with source file
34// and line. Meant for finding situations that should be examined further, but that
35// don't indicate a problem. In all cases, execution continues normally.
36#undef check
37#define check( expr ) ((void) 0)
38
39// If expr yields error string, return it from current function, otherwise continue.
40#undef RETURN_ERR
41#define RETURN_ERR( expr ) do { \
42 blargg_err_t blargg_return_err_ = (expr); \
43 if ( blargg_return_err_ ) return blargg_return_err_; \
44 } while ( 0 )
45
46// If ptr is 0, return out of memory error string.
47#undef CHECK_ALLOC
48#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 )
49
50#ifndef max
51 #define max(a,b) (((a) > (b)) ? (a) : (b))
52#endif
53#ifndef min
54 #define min(a,b) (((a) < (b)) ? (a) : (b))
55#endif
56
57// TODO: good idea? bad idea?
58#undef byte
59#define byte byte_
60typedef unsigned char byte;
61
62// deprecated
63#define BLARGG_CHECK_ALLOC CHECK_ALLOC
64#define BLARGG_RETURN_ERR RETURN_ERR
65
66// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check
67#ifdef BLARGG_SOURCE_BEGIN
68 #include BLARGG_SOURCE_BEGIN
69#endif
70
71#endif
diff --git a/apps/codecs/libgme/blip_buffer.c b/apps/codecs/libgme/blip_buffer.c
new file mode 100644
index 0000000000..3061f68573
--- /dev/null
+++ b/apps/codecs/libgme/blip_buffer.c
@@ -0,0 +1,285 @@
1// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
2
3#include "blip_buffer.h"
4
5#include <assert.h>
6#include <limits.h>
7#include <string.h>
8#include <stdlib.h>
9#include <math.h>
10
11/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
12can redistribute it and/or modify it under the terms of the GNU Lesser
13General Public License as published by the Free Software Foundation; either
14version 2.1 of the License, or (at your option) any later version. This
15module is distributed in the hope that it will be useful, but WITHOUT ANY
16WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18details. You should have received a copy of the GNU Lesser General Public
19License along with this module; if not, write to the Free Software Foundation,
20Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
21
22#ifdef BLARGG_ENABLE_OPTIMIZER
23 #include BLARGG_ENABLE_OPTIMIZER
24#endif
25
26int const silent_buf_size = 1; // size used for Silent_Blip_Buffer
27
28void Blip_init( struct Blip_Buffer* this )
29{
30 this->factor_ = LONG_MAX;
31 this->offset_ = 0;
32 this->buffer_size_ = 0;
33 this->sample_rate_ = 0;
34 this->reader_accum_ = 0;
35 this->bass_shift_ = 0;
36 this->clock_rate_ = 0;
37 this->bass_freq_ = 16;
38 this->length_ = 0;
39
40 // assumptions code makes about implementation-defined features
41 #ifndef NDEBUG
42 // right shift of negative value preserves sign
43 buf_t_ i = -0x7FFFFFFE;
44 assert( (i >> 1) == -0x3FFFFFFF );
45
46 // casting to short truncates to 16 bits and sign-extends
47 i = 0x18000;
48 assert( (short) i == -0x8000 );
49 #endif
50}
51
52void Blip_stop( struct Blip_Buffer* this )
53{
54 if ( this->buffer_size_ != silent_buf_size )
55 free( this->buffer_ );
56}
57
58void Blip_clear( struct Blip_Buffer* this, int entire_buffer )
59{
60 this->offset_ = 0;
61 this->reader_accum_ = 0;
62 this->modified_ = 0;
63 if ( this->buffer_ )
64 {
65 long count = (entire_buffer ? this->buffer_size_ : Blip_samples_avail( this ));
66 memset( this->buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) );
67 }
68}
69
70blargg_err_t Blip_set_sample_rate( struct Blip_Buffer* this, long new_rate, int msec )
71{
72 if ( this->buffer_size_ == silent_buf_size )
73 {
74 assert( 0 );
75 return "Internal (tried to resize Silent_Blip_Buffer)";
76 }
77
78 // start with maximum length that resampled time can represent
79 long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64;
80 if ( msec != blip_max_length )
81 {
82 long s = (new_rate * (msec + 1) + 999) / 1000;
83 if ( s < new_size )
84 new_size = s;
85 else
86 assert( 0 ); // fails if requested buffer length exceeds limit
87 }
88
89 if ( new_size > blip_buffer_max )
90 return "Out of memory";
91
92 this->buffer_size_ = new_size;
93 assert( this->buffer_size_ != silent_buf_size );
94
95 // update things based on the sample rate
96 this->sample_rate_ = new_rate;
97 this->length_ = new_size * 1000 / new_rate - 1;
98 if ( msec )
99 assert( this->length_ == msec ); // ensure length is same as that passed in
100 if ( this->clock_rate_ )
101 Blip_set_clock_rate( this, this->clock_rate_ );
102 Blip_bass_freq( this, this->bass_freq_ );
103
104 Blip_clear( this, 1 );
105
106 return 0; // success
107}
108
109/* Not sure if this affects sound quality */
110#if defined(ROCKBOX)
111double floor(double x) {
112 if ( x > 0 ) return (int)x;
113 return (int)(x-0.9999999999999999);
114}
115#endif
116
117blip_resampled_time_t Blip_clock_rate_factor( struct Blip_Buffer* this, long rate )
118{
119 double ratio = (double) this->sample_rate_ / rate;
120 blip_long factor = (blip_long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
121 assert( factor > 0 || !this->sample_rate_ ); // fails if clock/output ratio is too large
122 return (blip_resampled_time_t) factor;
123}
124
125void Blip_bass_freq( struct Blip_Buffer* this, int freq )
126{
127 this->bass_freq_ = freq;
128 int shift = 31;
129 if ( freq > 0 )
130 {
131 shift = 13;
132 long f = (freq << 16) / this->sample_rate_;
133 while ( (f >>= 1) && --shift ) { }
134 }
135 this->bass_shift_ = shift;
136}
137
138void Blip_end_frame( struct Blip_Buffer* this, blip_time_t t )
139{
140 this->offset_ += t * this->factor_;
141 assert( Blip_samples_avail( this ) <= (long) this->buffer_size_ ); // time outside buffer length
142}
143
144void Blip_remove_silence( struct Blip_Buffer* this, long count )
145{
146 assert( count <= Blip_samples_avail( this ) ); // tried to remove more samples than available
147 this->offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
148}
149
150long Blip_count_samples( struct Blip_Buffer* this, blip_time_t t )
151{
152 unsigned long last_sample = Blip_resampled_time( this, t ) >> BLIP_BUFFER_ACCURACY;
153 unsigned long first_sample = this->offset_ >> BLIP_BUFFER_ACCURACY;
154 return (long) (last_sample - first_sample);
155}
156
157blip_time_t Blip_count_clocks( struct Blip_Buffer* this, long count )
158{
159 if ( !this->factor_ )
160 {
161 assert( 0 ); // sample rate and clock rates must be set first
162 return 0;
163 }
164
165 if ( count > this->buffer_size_ )
166 count = this->buffer_size_;
167 blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
168 return (blip_time_t) ((time - this->offset_ + this->factor_ - 1) / this->factor_);
169}
170
171void Blip_remove_samples( struct Blip_Buffer* this, long count )
172{
173 if ( count )
174 {
175 Blip_remove_silence( this, count );
176
177 // copy remaining samples to beginning and clear old samples
178 long remain = Blip_samples_avail( this ) + blip_buffer_extra_;
179 memmove( this->buffer_, this->buffer_ + count, remain * sizeof *this->buffer_ );
180 memset( this->buffer_ + remain, 0, count * sizeof *this->buffer_ );
181 }
182}
183
184long Blip_read_samples( struct Blip_Buffer* this, blip_sample_t* BLIP_RESTRICT out, long max_samples, int stereo )
185{
186 long count = Blip_samples_avail( this );
187 if ( count > max_samples )
188 count = max_samples;
189
190 if ( count )
191 {
192 int const bass = BLIP_READER_BASS( *this );
193 BLIP_READER_BEGIN( reader, *this );
194
195 if ( !stereo )
196 {
197 blip_long n;
198 for ( n = count; n; --n )
199 {
200 blip_long s = BLIP_READER_READ( reader );
201 if ( (blip_sample_t) s != s )
202 s = 0x7FFF - (s >> 24);
203 *out++ = (blip_sample_t) s;
204 BLIP_READER_NEXT( reader, bass );
205 }
206 }
207 else
208 {
209 blip_long n;
210 for ( n = count; n; --n )
211 {
212 blip_long s = BLIP_READER_READ( reader );
213 if ( (blip_sample_t) s != s )
214 s = 0x7FFF - (s >> 24);
215 *out = (blip_sample_t) s;
216 out += 2;
217 BLIP_READER_NEXT( reader, bass );
218 }
219 }
220 BLIP_READER_END( reader, *this );
221
222 Blip_remove_samples( this, count );
223 }
224 return count;
225}
226
227void Blip_mix_samples( struct Blip_Buffer* this, blip_sample_t const* in, long count )
228{
229 if ( this->buffer_size_ == silent_buf_size )
230 {
231 assert( 0 );
232 return;
233 }
234
235 buf_t_* out = this->buffer_ + (this->offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2;
236
237 int const sample_shift = blip_sample_bits - 16;
238 int prev = 0;
239 while ( count-- )
240 {
241 blip_long s = (blip_long) *in++ << sample_shift;
242 *out += s - prev;
243 prev = s;
244 ++out;
245 }
246 *out -= prev;
247}
248
249void Blip_set_modified( struct Blip_Buffer* this )
250{
251 this->modified_ = 1;
252}
253
254int Blip_clear_modified( struct Blip_Buffer* this )
255{
256 int b = this->modified_;
257 this->modified_ = 0;
258 return b;
259}
260
261blip_resampled_time_t Blip_resampled_duration( struct Blip_Buffer* this, int t )
262{
263 return t * this->factor_;
264}
265
266blip_resampled_time_t Blip_resampled_time( struct Blip_Buffer* this, blip_time_t t )
267{
268 return t * this->factor_ + this->offset_;
269}
270
271
272// Blip_Synth
273
274void Synth_init( struct Blip_Synth* this )
275{
276 this->buf = 0;
277 this->last_amp = 0;
278 this->delta_factor = 0;
279}
280
281// Set overall volume of waveform
282void Synth_volume( struct Blip_Synth* this, double v )
283{
284 this->delta_factor = (int) (v * (1L << blip_sample_bits) + 0.5);
285}
diff --git a/apps/codecs/libgme/blip_buffer.h b/apps/codecs/libgme/blip_buffer.h
new file mode 100644
index 0000000000..84ed6e6690
--- /dev/null
+++ b/apps/codecs/libgme/blip_buffer.h
@@ -0,0 +1,279 @@
1// Band-limited sound synthesis buffer
2
3// Blip_Buffer 0.4.1
4#ifndef BLIP_BUFFER_H
5#define BLIP_BUFFER_H
6
7#include <assert.h>
8
9 // internal
10 #include "blargg_common.h"
11 #if INT_MAX >= 0x7FFFFFFF
12 typedef int blip_long;
13 typedef unsigned blip_ulong;
14 #else
15 typedef long blip_long;
16 typedef unsigned long blip_ulong;
17 #endif
18
19// Time unit at source clock rate
20typedef blip_long blip_time_t;
21
22// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
23// but reduce maximum buffer size.
24#ifndef BLIP_BUFFER_ACCURACY
25 #define BLIP_BUFFER_ACCURACY 16
26#endif
27
28// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
29// noticeable broadband noise when synthesizing high frequency square waves.
30// Affects size of Blip_Synth objects since they store the waveform directly.
31#ifndef BLIP_PHASE_BITS
32 #define BLIP_PHASE_BITS 8
33#endif
34
35// Output samples are 16-bit signed, with a range of -32768 to 32767
36typedef short blip_sample_t;
37enum { blip_sample_max = 32767 };
38enum { blip_widest_impulse_ = 16 };
39enum { blip_buffer_extra_ = blip_widest_impulse_ + 2 };
40enum { blip_res = 1 << BLIP_PHASE_BITS };
41enum { blip_max_length = 0 };
42enum { blip_default_length = 250 };
43
44// Maximun buffer size (48Khz, 50 ms)
45enum { blip_buffer_max = 2466 };
46enum { blip_sample_bits = 30 };
47
48typedef blip_time_t buf_t_;
49/* typedef const char* blargg_err_t; */
50typedef blip_ulong blip_resampled_time_t;
51
52struct Blip_Buffer {
53 blip_ulong factor_;
54 blip_resampled_time_t offset_;
55 buf_t_ buffer_ [blip_buffer_max];
56 blip_long buffer_size_;
57 blip_long reader_accum_;
58 int bass_shift_;
59
60 long sample_rate_;
61 long clock_rate_;
62 int bass_freq_;
63 int length_;
64 int modified_;
65};
66
67// not documented yet
68void Blip_set_modified( struct Blip_Buffer* this ) ICODE_ATTR;
69int Blip_clear_modified( struct Blip_Buffer* this ) ICODE_ATTR;
70void Blip_remove_silence( struct Blip_Buffer* this, long count ) ICODE_ATTR;
71blip_resampled_time_t Blip_resampled_duration( struct Blip_Buffer* this, int t ) ICODE_ATTR;
72blip_resampled_time_t Blip_resampled_time( struct Blip_Buffer* this, blip_time_t t ) ICODE_ATTR;
73blip_resampled_time_t Blip_clock_rate_factor( struct Blip_Buffer* this, long clock_rate ) ICODE_ATTR;
74
75// Initializes Blip_Buffer structure
76void Blip_init( struct Blip_Buffer* this );
77
78// Stops (clear) Blip_Buffer structure
79void Blip_stop( struct Blip_Buffer* this );
80
81// Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
82// to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
83// isn't enough memory, returns error without affecting current buffer setup.
84blargg_err_t Blip_set_sample_rate( struct Blip_Buffer* this, long samples_per_sec, int msec_length );
85
86// Set number of source time units per second
87static inline void Blip_set_clock_rate( struct Blip_Buffer* this, long cps )
88{
89 this->factor_ = Blip_clock_rate_factor( this, this->clock_rate_ = cps );
90}
91
92// End current time frame of specified duration and make its samples available
93// (along with any still-unread samples) for reading with read_samples(). Begins
94// a new time frame at the end of the current frame.
95void Blip_end_frame( struct Blip_Buffer* this, blip_time_t time ) ICODE_ATTR;
96
97// Read at most 'max_samples' out of buffer into 'dest', removing them from from
98// the buffer. Returns number of samples actually read and removed. If stereo is
99// true, increments 'dest' one extra time after writing each sample, to allow
100// easy interleving of two channels into a stereo output buffer.
101long Blip_read_samples( struct Blip_Buffer* this, blip_sample_t* dest, long max_samples, int stereo ) ICODE_ATTR;
102
103// Additional optional features
104
105// Current output sample rate
106static inline long Blip_sample_rate( struct Blip_Buffer* this )
107{
108 return this->sample_rate_;
109}
110
111// Length of buffer, in milliseconds
112static inline int Blip_length( struct Blip_Buffer* this )
113{
114 return this->length_;
115}
116
117// Number of source time units per second
118static inline long Blip_clock_rate( struct Blip_Buffer* this )
119{
120 return this->clock_rate_;
121}
122
123
124// Set frequency high-pass filter frequency, where higher values reduce bass more
125void Blip_bass_freq( struct Blip_Buffer* this, int frequency );
126
127// Number of samples delay from synthesis to samples read out
128static inline int Blip_output_latency( void )
129{
130 return blip_widest_impulse_ / 2;
131}
132
133// Remove all available samples and clear buffer to silence. If 'entire_buffer' is
134// false, just clears out any samples waiting rather than the entire buffer.
135void Blip_clear( struct Blip_Buffer* this, int entire_buffer );
136
137// Number of samples available for reading with read_samples()
138static inline long Blip_samples_avail( struct Blip_Buffer* this )
139{
140 return (long) (this->offset_ >> BLIP_BUFFER_ACCURACY);
141}
142
143// Remove 'count' samples from those waiting to be read
144void Blip_remove_samples( struct Blip_Buffer* this, long count ) ICODE_ATTR;
145
146// Experimental features
147
148// Count number of clocks needed until 'count' samples will be available.
149// If buffer can't even hold 'count' samples, returns number of clocks until
150// buffer becomes full.
151blip_time_t Blip_count_clocks( struct Blip_Buffer* this, long count ) ICODE_ATTR;
152
153// Number of raw samples that can be mixed within frame of specified duration.
154long Blip_count_samples( struct Blip_Buffer* this, blip_time_t duration ) ICODE_ATTR;
155
156// Mix 'count' samples from 'buf' into buffer.
157void Blip_mix_samples( struct Blip_Buffer* this, blip_sample_t const* buf, long count ) ICODE_ATTR;
158
159// Range specifies the greatest expected change in amplitude. Calculate it
160// by finding the difference between the maximum and minimum expected
161// amplitudes (max - min).
162
163struct Blip_Synth {
164 struct Blip_Buffer* buf;
165 int last_amp;
166 int delta_factor;
167};
168
169// Initializes Blip_Synth structure
170void Synth_init( struct Blip_Synth* this );
171
172// Set overall volume of waveform
173void Synth_volume( struct Blip_Synth* this, double v ) ICODE_ATTR;
174
175// Get/set Blip_Buffer used for output
176const struct Blip_Buffer* Synth_output( struct Blip_Synth* this ) ICODE_ATTR;
177
178// Low-level interface
179
180 #if defined (__GNUC__) || _MSC_VER >= 1100
181 #define BLIP_RESTRICT __restrict
182 #else
183 #define BLIP_RESTRICT
184 #endif
185
186// Works directly in terms of fractional output samples. Contact author for more info.
187static inline void Synth_offset_resampled( struct Blip_Synth* this, blip_resampled_time_t time,
188 int delta, struct Blip_Buffer* blip_buf )
189{
190 // Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the
191 // need for a longer buffer as set by set_sample_rate().
192 assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
193 delta *= this->delta_factor;
194 blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
195 int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
196
197 blip_long left = buf [0] + delta;
198
199 // Kind of crappy, but doing shift after multiply results in overflow.
200 // Alternate way of delaying multiply by delta_factor results in worse
201 // sub-sample resolution.
202 blip_long right = (delta >> BLIP_PHASE_BITS) * phase;
203 left -= right;
204 right += buf [1];
205
206 buf [0] = left;
207 buf [1] = right;
208}
209
210// Update amplitude of waveform at given time. Using this requires a separate
211// Blip_Synth for each waveform.
212static inline void Synth_update( struct Blip_Synth* this, blip_time_t t, int amp )
213{
214 int delta = amp - this->last_amp;
215 this->last_amp = amp;
216 Synth_offset_resampled( this, t * this->buf->factor_ + this->buf->offset_, delta, this->buf );
217}
218
219// Add an amplitude transition of specified delta, optionally into specified buffer
220// rather than the one set with output(). Delta can be positive or negative.
221// The actual change in amplitude is delta * (volume / range)
222static inline void Synth_offset( struct Blip_Synth* this, blip_time_t t, int delta, struct Blip_Buffer* buf )
223{
224 Synth_offset_resampled( this, t * buf->factor_ + buf->offset_, delta, buf );
225}
226
227// Same as offset(), except code is inlined for higher performance
228static inline void Synth_offset_inline( struct Blip_Synth* this, blip_time_t t, int delta, struct Blip_Buffer* buf )
229{
230 Synth_offset_resampled( this, t * buf->factor_ + buf->offset_, delta, buf );
231}
232
233// Optimized reading from Blip_Buffer, for use in custom sample output
234
235// Begin reading from buffer. Name should be unique to the current block.
236#define BLIP_READER_BEGIN( name, blip_buffer ) \
237 buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\
238 blip_long name##_reader_accum = (blip_buffer).reader_accum_
239
240// Get value to pass to BLIP_READER_NEXT()
241#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)
242
243// Current sample
244#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16))
245
246// Current raw sample in full internal resolution
247#define BLIP_READER_READ_RAW( name ) (name##_reader_accum)
248
249// Advance to next sample
250#define BLIP_READER_NEXT( name, bass ) \
251 (void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))
252
253// End reading samples from buffer. The number of samples read must now be removed
254// using Blip_remove_samples().
255#define BLIP_READER_END( name, blip_buffer ) \
256 (void) ((blip_buffer).reader_accum_ = name##_reader_accum)
257
258#define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset)
259
260#define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\
261 name##_reader_accum -= name##_reader_accum >> (bass);\
262 name##_reader_accum += name##_reader_buf [(idx)];\
263}
264
265//// BLIP_CLAMP
266
267#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
268 defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
269 #define BLIP_X86 1
270 #define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in
271#else
272 #define BLIP_CLAMP_( in ) (blip_sample_t) in != in
273#endif
274
275// Clamp sample to blip_sample_t range
276#define BLIP_CLAMP( sample, out )\
277 { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 31) ^ 0x7FFF; }
278
279#endif
diff --git a/apps/codecs/libgme/emu2413.c b/apps/codecs/libgme/emu2413.c
new file mode 100644
index 0000000000..5def504cbd
--- /dev/null
+++ b/apps/codecs/libgme/emu2413.c
@@ -0,0 +1,1958 @@
1/***********************************************************************************
2
3 emu2413.c -- YM2413 emulator written by Mitsutaka Okazaki 2001
4
5 2001 01-08 : Version 0.10 -- 1st version.
6 2001 01-15 : Version 0.20 -- semi-public version.
7 2001 01-16 : Version 0.30 -- 1st public version.
8 2001 01-17 : Version 0.31 -- Fixed bassdrum problem.
9 : Version 0.32 -- LPF implemented.
10 2001 01-18 : Version 0.33 -- Fixed the drum problem, refine the mix-down method.
11 -- Fixed the LFO bug.
12 2001 01-24 : Version 0.35 -- Fixed the drum problem,
13 support undocumented EG behavior.
14 2001 02-02 : Version 0.38 -- Improved the performance.
15 Fixed the hi-hat and cymbal model.
16 Fixed the default percussive datas.
17 Noise reduction.
18 Fixed the feedback problem.
19 2001 03-03 : Version 0.39 -- Fixed some drum bugs.
20 Improved the performance.
21 2001 03-04 : Version 0.40 -- Improved the feedback.
22 Change the default table size.
23 Clock and Rate can be changed during play.
24 2001 06-24 : Version 0.50 -- Improved the hi-hat and the cymbal tone.
25 Added VRC7 patch (OPLL_reset_patch is changed).
26 Fixed OPLL_reset() bug.
27 Added OPLL_setMask, OPLL_getMask and OPLL_toggleMask.
28 Added OPLL_writeIO.
29 2001 09-28 : Version 0.51 -- Removed the noise table.
30 2002 01-28 : Version 0.52 -- Added Stereo mode.
31 2002 02-07 : Version 0.53 -- Fixed some drum bugs.
32 2002 02-20 : Version 0.54 -- Added the best quality mode.
33 2002 03-02 : Version 0.55 -- Removed OPLL_init & OPLL_close.
34 2002 05-30 : Version 0.60 -- Fixed HH&CYM generator and all voice datas.
35 2004 04-10 : Version 0.61 -- Added YMF281B tone (defined by Chabin).
36
37 2011 03-22 : --------------- Modified by gama to use precalculated tables.
38
39 References:
40 fmopl.c -- 1999,2000 written by Tatsuyuki Satoh (MAME development).
41 fmopl.c(fixed) -- (C) 2002 Jarek Burczynski.
42 s_opl.c -- 2001 written by Mamiya (NEZplug development).
43 fmgen.cpp -- 1999,2000 written by cisc.
44 fmpac.ill -- 2000 created by NARUTO.
45 MSX-Datapack
46 YMU757 data sheet
47 YM2143 data sheet
48
49**************************************************************************************/
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <math.h>
54#include "emu2413.h"
55
56#include "emutables.h"
57#if !defined(ROCKBOX)
58 #define EMU2413_CALCUL_TABLES
59#else
60 #define EMU2413_COMPACTION
61 #include "emutables.h"
62#endif
63
64#if defined(EMU2413_COMPACTION) && !defined(ROCKBOX)
65#define OPLL_TONE_NUM 1
66static unsigned char default_inst[OPLL_TONE_NUM][(16 + 3) * 16] = {
67 {
68#include "2413tone.h"
69 }
70};
71#else
72#define OPLL_TONE_NUM 3
73static unsigned char default_inst[OPLL_TONE_NUM][(16 + 3) * 16] = {
74 {
75#include "2413tone.h"
76 },
77 {
78#include "vrc7tone.h"
79 },
80 {
81#include "281btone.h"
82 }
83};
84#endif
85
86/* Size of Sintable ( 8 -- 18 can be used. 9 recommended.) */
87#define PG_BITS 9
88#define PG_WIDTH (1<<PG_BITS)
89
90/* Phase increment counter */
91#define DP_BITS 18
92#define DP_WIDTH (1<<DP_BITS)
93#define DP_BASE_BITS (DP_BITS - PG_BITS)
94
95/* Dynamic range (Accuracy of sin table) */
96#define DB_BITS 8
97#define DB_STEP (48.0/(1<<DB_BITS))
98#define DB_MUTE (1<<DB_BITS)
99
100/* Dynamic range of envelope */
101#define EG_STEP 0.375
102#define EG_BITS 7
103#define EG_MUTE (1<<EG_BITS)
104
105/* Dynamic range of total level */
106#define TL_STEP 0.75
107#define TL_BITS 6
108#define TL_MUTE (1<<TL_BITS)
109
110/* Dynamic range of sustine level */
111#define SL_STEP 3.0
112#define SL_BITS 4
113#define SL_MUTE (1<<SL_BITS)
114
115#define EG2DB(d) ((d)*(e_int32)(EG_STEP/DB_STEP))
116#define TL2EG(d) ((d)*(e_int32)(TL_STEP/EG_STEP))
117#define SL2EG(d) ((d)*(e_int32)(SL_STEP/EG_STEP))
118
119#define DB_POS(x) (e_uint32)((x)/DB_STEP)
120#define DB_NEG(x) (e_uint32)(DB_MUTE+DB_MUTE+(x)/DB_STEP)
121
122/* Bits for liner value */
123#define DB2LIN_AMP_BITS 8
124#define SLOT_AMP_BITS (DB2LIN_AMP_BITS)
125
126/* Bits for envelope phase incremental counter */
127#define EG_DP_BITS 22
128#define EG_DP_WIDTH (1<<EG_DP_BITS)
129
130/* Bits for Pitch and Amp modulator */
131#define PM_PG_BITS 8
132#define PM_PG_WIDTH (1<<PM_PG_BITS)
133#define PM_DP_BITS 16
134#define PM_DP_WIDTH (1<<PM_DP_BITS)
135#define AM_PG_BITS 8
136#define AM_PG_WIDTH (1<<AM_PG_BITS)
137#define AM_DP_BITS 16
138#define AM_DP_WIDTH (1<<AM_DP_BITS)
139
140/* PM table is calcurated by PM_AMP * pow(2,PM_DEPTH*sin(x)/1200) */
141#define PM_AMP_BITS 8
142#define PM_AMP (1<<PM_AMP_BITS)
143
144/* PM speed(Hz) and depth(cent) */
145#define PM_SPEED 6.4
146#define PM_DEPTH 13.75
147
148/* AM speed(Hz) and depth(dB) */
149#define AM_SPEED 3.6413
150#define AM_DEPTH 4.875
151
152/* Cut the lower b bit(s) off. */
153#define HIGHBITS(c,b) ((c)>>(b))
154
155/* Leave the lower b bit(s). */
156#define LOWBITS(c,b) ((c)&((1<<(b))-1))
157
158/* Expand x which is s bits to d bits. */
159#define EXPAND_BITS(x,s,d) ((x)<<((d)-(s)))
160
161/* Expand x which is s bits to d bits and fill expanded bits '1' */
162#define EXPAND_BITS_X(x,s,d) (((x)<<((d)-(s)))|((1<<((d)-(s)))-1))
163
164/* Adjust envelope speed which depends on sampling rate. */
165#define RATE_ADJUST(x) (rate==49716?(e_uint32)x:(e_uint32)((double)(x)*clk/72/rate + 0.5)) /* added 0.5 to round the value*/
166
167#define MOD(o,x) (&(o)->slot[(x)<<1])
168#define CAR(o,x) (&(o)->slot[((x)<<1)|1])
169
170#define BIT(s,b) (((s)>>(b))&1)
171
172/* Input clock */
173static e_uint32 clk = 844451141;
174/* Sampling rate */
175static e_uint32 rate = 3354932;
176
177/* WaveTable for each envelope amp */
178static e_uint16 fullsintable[PG_WIDTH];
179static e_uint16 halfsintable[PG_WIDTH];
180
181static e_uint16 *waveform[2] = { fullsintable, halfsintable };
182
183/* LFO Table */
184static e_int32 pmtable[PM_PG_WIDTH];
185static e_int32 amtable[AM_PG_WIDTH];
186
187/* Phase delta for LFO */
188static e_uint32 pm_dphase;
189static e_uint32 am_dphase;
190
191/* dB to Liner table */
192static e_int16 DB2LIN_TABLE[(DB_MUTE + DB_MUTE) * 2];
193
194/* Liner to Log curve conversion table (for Attack rate). */
195static e_uint16 AR_ADJUST_TABLE[1 << EG_BITS];
196
197/* Empty voice data */
198static OPLL_PATCH null_patch = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
199
200/* Basic voice Data */
201static OPLL_PATCH default_patch[OPLL_TONE_NUM][(16 + 3) * 2];
202
203/* Definition of envelope mode */
204enum OPLL_EG_STATE
205{ READY, ATTACK, DECAY, SUSHOLD, SUSTINE, RELEASE, SETTLE, FINISH };
206
207/* Phase incr table for Attack */
208static e_uint32 dphaseARTable[16][16];
209/* Phase incr table for Decay and Release */
210static e_uint32 dphaseDRTable[16][16];
211
212/* KSL + TL Table */
213static e_uint32 tllTable[16][8][1 << TL_BITS][4];
214static e_int32 rksTable[2][8][2];
215
216/* We may not have too much SRAM in rockbox */
217#if !defined(ROCKBOX)
218/* Phase incr table for PG */
219static e_uint32 dphaseTable[512][8][16];
220#endif
221
222/***************************************************
223
224 Create tables
225
226****************************************************/
227INLINE static e_int32
228Min (e_int32 i, e_int32 j)
229{
230 if (i < j)
231 return i;
232 else
233 return j;
234}
235
236/* Table for AR to LogCurve. */
237static void
238makeAdjustTable (void)
239{
240 e_int32 i;
241
242 AR_ADJUST_TABLE[0] = (1 << EG_BITS) - 1;
243 for (i = 1; i < (1<<EG_BITS); i++)
244 #ifdef EMU2413_CALCUL_TABLES
245 AR_ADJUST_TABLE[i] = (e_uint16) ((double) (1<<EG_BITS)-1 - ((1<<EG_BITS)-1)*log(i)/log(127));
246 #else
247 AR_ADJUST_TABLE[i] = ar_adjust_coeff[i];
248 #endif
249}
250
251
252/* Table for dB(0 -- (1<<DB_BITS)-1) to Liner(0 -- DB2LIN_AMP_WIDTH) */
253static void
254makeDB2LinTable (void)
255{
256 e_int32 i;
257 for (i = 0; i < DB_MUTE + DB_MUTE; i++)
258 {
259 #ifdef EMU2413_CALCUL_TABLES
260 DB2LIN_TABLE[i] = (e_int16) ((double) ((1 << DB2LIN_AMP_BITS) - 1) * pow (10, -(double) i * DB_STEP / 20));
261 #else
262 DB2LIN_TABLE[i] = db2lin_coeff[i];
263 #endif
264 if (i >= DB_MUTE) DB2LIN_TABLE[i] = 0;
265 DB2LIN_TABLE[i + DB_MUTE + DB_MUTE] = (e_int16) (-DB2LIN_TABLE[i]);
266 }
267}
268
269#ifdef EMU2413_CALCUL_TABLES
270/* Liner(+0.0 - +1.0) to dB((1<<DB_BITS) - 1 -- 0) */
271static e_int32
272lin2db (double d)
273{
274 if (d == 0)
275 return (DB_MUTE - 1);
276 else
277 return Min (-(e_int32) (20.0 * log10 (d) / DB_STEP), DB_MUTE-1); /* 0 -- 127 */
278}
279#endif
280
281/* Sin Table */
282static void
283makeSinTable (void)
284{
285 e_int32 i;
286
287 for (i = 0; i < PG_WIDTH / 4; i++)
288 #ifdef EMU2413_CALCUL_TABLES
289 fullsintable[i] = (e_uint32) lin2db (sin (2.0 * PI * i / PG_WIDTH) );
290 #else
291 fullsintable[i] = sin_coeff[i];
292 #endif
293
294 for (i = 0; i < PG_WIDTH / 4; i++)
295 {
296 fullsintable[PG_WIDTH / 2 - 1 - i] = fullsintable[i];
297 }
298
299 for (i = 0; i < PG_WIDTH / 2; i++)
300 {
301 fullsintable[PG_WIDTH / 2 + i] = (e_uint32) (DB_MUTE + DB_MUTE + fullsintable[i]);
302 }
303
304 for (i = 0; i < PG_WIDTH / 2; i++)
305 halfsintable[i] = fullsintable[i];
306 for (i = PG_WIDTH / 2; i < PG_WIDTH; i++)
307 halfsintable[i] = fullsintable[0];
308}
309
310static double saw(double phase)
311{
312 if(phase <= PI/2)
313 return phase * 2 / PI ;
314 else if(phase <= PI*3/2)
315 return 2.0 - ( phase * 2 / PI );
316 else
317 return -4.0 + phase * 2 / PI;
318}
319
320/* Table for Pitch Modulator */
321static void
322makePmTable (void)
323{
324 e_int32 i;
325
326 for (i = 0; i < PM_PG_WIDTH; i++)
327 /* pmtable[i] = (e_int32) ((double) PM_AMP * pow (2, (double) PM_DEPTH * sin (2.0 * PI * i / PM_PG_WIDTH) / 1200)); */
328 #ifdef EMU2413_CALCUL_TABLES
329 pmtable[i] = (e_int32) ((double) PM_AMP * pow (2, (double) PM_DEPTH * saw (2.0 * PI * i / PM_PG_WIDTH) / 1200));
330 #else
331 pmtable[i] = pm_coeff[i];
332 #endif
333}
334
335/* Table for Amp Modulator */
336static void
337makeAmTable (void)
338{
339 e_int32 i;
340
341 for (i = 0; i < AM_PG_WIDTH; i++)
342 /* amtable[i] = (e_int32) ((double) AM_DEPTH / 2 / DB_STEP * (1.0 + sin (2.0 * PI * i / PM_PG_WIDTH))); */
343 amtable[i] = (e_int32) ((double) AM_DEPTH / 2 / DB_STEP * (1.0 + saw (2.0 * PI * i / PM_PG_WIDTH)));
344}
345
346#if !defined(ROCKBOX)
347/* Phase increment counter table */
348static void
349makeDphaseTable (void)
350{
351 e_uint32 fnum, block, ML;
352 e_uint32 mltable[16] =
353 { 1, 1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2, 7 * 2, 8 * 2, 9 * 2, 10 * 2, 10 * 2, 12 * 2, 12 * 2, 15 * 2, 15 * 2 };
354
355 for (fnum = 0; fnum < 512; fnum++)
356 for (block = 0; block < 8; block++)
357 for (ML = 0; ML < 16; ML++)
358 dphaseTable[fnum][block][ML] = RATE_ADJUST (((fnum * mltable[ML]) << block) >> (20 - DP_BITS));
359}
360#endif
361
362static void
363makeTllTable (void)
364{
365#define dB2(x) ((x)*2)
366
367 static double kltable[16] = {
368 dB2 (0.000), dB2 (9.000), dB2 (12.000), dB2 (13.875), dB2 (15.000), dB2 (16.125), dB2 (16.875), dB2 (17.625),
369 dB2 (18.000), dB2 (18.750), dB2 (19.125), dB2 (19.500), dB2 (19.875), dB2 (20.250), dB2 (20.625), dB2 (21.000)
370 };
371
372 e_int32 tmp;
373 e_int32 fnum, block, TL, KL;
374
375 for (fnum = 0; fnum < 16; fnum++)
376 for (block = 0; block < 8; block++)
377 for (TL = 0; TL < 64; TL++)
378 for (KL = 0; KL < 4; KL++)
379 {
380 if (KL == 0)
381 {
382 tllTable[fnum][block][TL][KL] = TL2EG (TL);
383 }
384 else
385 {
386 tmp = (e_int32) (kltable[fnum] - dB2 (3.000) * (7 - block));
387 if (tmp <= 0)
388 tllTable[fnum][block][TL][KL] = TL2EG (TL);
389 else
390 tllTable[fnum][block][TL][KL] = (e_uint32) ((tmp >> (3 - KL)) / EG_STEP) + TL2EG (TL);
391 }
392 }
393}
394
395#ifdef USE_SPEC_ENV_SPEED
396static double attacktime[16][4] = {
397 {0, 0, 0, 0},
398 {1730.15, 1400.60, 1153.43, 988.66},
399 {865.08, 700.30, 576.72, 494.33},
400 {432.54, 350.15, 288.36, 247.16},
401 {216.27, 175.07, 144.18, 123.58},
402 {108.13, 87.54, 72.09, 61.79},
403 {54.07, 43.77, 36.04, 30.90},
404 {27.03, 21.88, 18.02, 15.45},
405 {13.52, 10.94, 9.01, 7.72},
406 {6.76, 5.47, 4.51, 3.86},
407 {3.38, 2.74, 2.25, 1.93},
408 {1.69, 1.37, 1.13, 0.97},
409 {0.84, 0.70, 0.60, 0.54},
410 {0.50, 0.42, 0.34, 0.30},
411 {0.28, 0.22, 0.18, 0.14},
412 {0.00, 0.00, 0.00, 0.00}
413};
414
415static double decaytime[16][4] = {
416 {0, 0, 0, 0},
417 {20926.60, 16807.20, 14006.00, 12028.60},
418 {10463.30, 8403.58, 7002.98, 6014.32},
419 {5231.64, 4201.79, 3501.49, 3007.16},
420 {2615.82, 2100.89, 1750.75, 1503.58},
421 {1307.91, 1050.45, 875.37, 751.79},
422 {653.95, 525.22, 437.69, 375.90},
423 {326.98, 262.61, 218.84, 187.95},
424 {163.49, 131.31, 109.42, 93.97},
425 {81.74, 65.65, 54.71, 46.99},
426 {40.87, 32.83, 27.36, 23.49},
427 {20.44, 16.41, 13.68, 11.75},
428 {10.22, 8.21, 6.84, 5.87},
429 {5.11, 4.10, 3.42, 2.94},
430 {2.55, 2.05, 1.71, 1.47},
431 {1.27, 1.27, 1.27, 1.27}
432};
433#endif
434
435/* Rate Table for Attack */
436static void
437makeDphaseARTable (void)
438{
439 e_int32 AR, Rks, RM, RL;
440
441#ifdef USE_SPEC_ENV_SPEED
442 e_uint32 attacktable[16][4];
443
444 for (RM = 0; RM < 16; RM++)
445 for (RL = 0; RL < 4; RL++)
446 {
447 if (RM == 0)
448 attacktable[RM][RL] = 0;
449 else if (RM == 15)
450 attacktable[RM][RL] = EG_DP_WIDTH;
451 else
452 attacktable[RM][RL] = (e_uint32) ((double) (1 << EG_DP_BITS) / (attacktime[RM][RL] * 3579545 / 72000));
453
454 }
455#endif
456
457 for (AR = 0; AR < 16; AR++)
458 for (Rks = 0; Rks < 16; Rks++)
459 {
460 RM = AR + (Rks >> 2);
461 RL = Rks & 3;
462 if (RM > 15)
463 RM = 15;
464 switch (AR)
465 {
466 case 0:
467 dphaseARTable[AR][Rks] = 0;
468 break;
469 case 15:
470 dphaseARTable[AR][Rks] = 0;/*EG_DP_WIDTH;*/
471 break;
472 default:
473#ifdef USE_SPEC_ENV_SPEED
474 dphaseARTable[AR][Rks] = RATE_ADJUST (attacktable[RM][RL]);
475#else
476 dphaseARTable[AR][Rks] = RATE_ADJUST ((3 * (RL + 4) << (RM + 1)));
477#endif
478 break;
479 }
480 }
481}
482
483/* Rate Table for Decay and Release */
484static void
485makeDphaseDRTable (void)
486{
487 e_int32 DR, Rks, RM, RL;
488
489#ifdef USE_SPEC_ENV_SPEED
490 e_uint32 decaytable[16][4];
491
492 for (RM = 0; RM < 16; RM++)
493 for (RL = 0; RL < 4; RL++)
494 if (RM == 0)
495 decaytable[RM][RL] = 0;
496 else
497 decaytable[RM][RL] = (e_uint32) ((double) (1 << EG_DP_BITS) / (decaytime[RM][RL] * 3579545 / 72000));
498#endif
499
500 for (DR = 0; DR < 16; DR++)
501 for (Rks = 0; Rks < 16; Rks++)
502 {
503 RM = DR + (Rks >> 2);
504 RL = Rks & 3;
505 if (RM > 15)
506 RM = 15;
507 switch (DR)
508 {
509 case 0:
510 dphaseDRTable[DR][Rks] = 0;
511 break;
512 default:
513#ifdef USE_SPEC_ENV_SPEED
514 dphaseDRTable[DR][Rks] = RATE_ADJUST (decaytable[RM][RL]);
515#else
516 dphaseDRTable[DR][Rks] = RATE_ADJUST ((RL + 4) << (RM - 1));
517#endif
518 break;
519 }
520 }
521}
522
523static void
524makeRksTable (void)
525{
526
527 e_int32 fnum8, block, KR;
528
529 for (fnum8 = 0; fnum8 < 2; fnum8++)
530 for (block = 0; block < 8; block++)
531 for (KR = 0; KR < 2; KR++)
532 {
533 if (KR != 0)
534 rksTable[fnum8][block][KR] = (block << 1) + fnum8;
535 else
536 rksTable[fnum8][block][KR] = block >> 1;
537 }
538}
539
540void
541OPLL_dump2patch (const e_uint8 * dump, OPLL_PATCH * patch)
542{
543 patch[0].AM = (dump[0] >> 7) & 1;
544 patch[1].AM = (dump[1] >> 7) & 1;
545 patch[0].PM = (dump[0] >> 6) & 1;
546 patch[1].PM = (dump[1] >> 6) & 1;
547 patch[0].EG = (dump[0] >> 5) & 1;
548 patch[1].EG = (dump[1] >> 5) & 1;
549 patch[0].KR = (dump[0] >> 4) & 1;
550 patch[1].KR = (dump[1] >> 4) & 1;
551 patch[0].ML = (dump[0]) & 15;
552 patch[1].ML = (dump[1]) & 15;
553 patch[0].KL = (dump[2] >> 6) & 3;
554 patch[1].KL = (dump[3] >> 6) & 3;
555 patch[0].TL = (dump[2]) & 63;
556 patch[0].FB = (dump[3]) & 7;
557 patch[0].WF = (dump[3] >> 3) & 1;
558 patch[1].WF = (dump[3] >> 4) & 1;
559 patch[0].AR = (dump[4] >> 4) & 15;
560 patch[1].AR = (dump[5] >> 4) & 15;
561 patch[0].DR = (dump[4]) & 15;
562 patch[1].DR = (dump[5]) & 15;
563 patch[0].SL = (dump[6] >> 4) & 15;
564 patch[1].SL = (dump[7] >> 4) & 15;
565 patch[0].RR = (dump[6]) & 15;
566 patch[1].RR = (dump[7]) & 15;
567}
568
569void
570OPLL_getDefaultPatch (e_int32 type, e_int32 num, OPLL_PATCH * patch)
571{
572 OPLL_dump2patch (default_inst[type] + num * 16, patch);
573}
574
575static void
576makeDefaultPatch ( void )
577{
578 e_int32 i, j;
579
580 for (i = 0; i < OPLL_TONE_NUM; i++)
581 for (j = 0; j < 19; j++)
582 OPLL_getDefaultPatch (i, j, &default_patch[i][j * 2]);
583
584}
585
586void
587OPLL_setPatch (OPLL * opll, const e_uint8 * dump)
588{
589 OPLL_PATCH patch[2];
590 int i;
591
592 for (i = 0; i < 19; i++)
593 {
594 OPLL_dump2patch (dump + i * 16, patch);
595 memcpy (&opll->patch[i*2+0], &patch[0], sizeof (OPLL_PATCH));
596 memcpy (&opll->patch[i*2+1], &patch[1], sizeof (OPLL_PATCH));
597 }
598}
599
600void
601OPLL_patch2dump (const OPLL_PATCH * patch, e_uint8 * dump)
602{
603 dump[0] = (e_uint8) ((patch[0].AM << 7) + (patch[0].PM << 6) + (patch[0].EG << 5) + (patch[0].KR << 4) + patch[0].ML);
604 dump[1] = (e_uint8) ((patch[1].AM << 7) + (patch[1].PM << 6) + (patch[1].EG << 5) + (patch[1].KR << 4) + patch[1].ML);
605 dump[2] = (e_uint8) ((patch[0].KL << 6) + patch[0].TL);
606 dump[3] = (e_uint8) ((patch[1].KL << 6) + (patch[1].WF << 4) + (patch[0].WF << 3) + patch[0].FB);
607 dump[4] = (e_uint8) ((patch[0].AR << 4) + patch[0].DR);
608 dump[5] = (e_uint8) ((patch[1].AR << 4) + patch[1].DR);
609 dump[6] = (e_uint8) ((patch[0].SL << 4) + patch[0].RR);
610 dump[7] = (e_uint8) ((patch[1].SL << 4) + patch[1].RR);
611 dump[8] = 0;
612 dump[9] = 0;
613 dump[10] = 0;
614 dump[11] = 0;
615 dump[12] = 0;
616 dump[13] = 0;
617 dump[14] = 0;
618 dump[15] = 0;
619}
620
621/************************************************************
622
623 Calc Parameters
624
625************************************************************/
626
627INLINE static e_uint32
628calc_eg_dphase (OPLL_SLOT * slot)
629{
630
631 switch (slot->eg_mode)
632 {
633 case ATTACK:
634 return dphaseARTable[slot->patch->AR][slot->rks];
635
636 case DECAY:
637 return dphaseDRTable[slot->patch->DR][slot->rks];
638
639 case SUSHOLD:
640 return 0;
641
642 case SUSTINE:
643 return dphaseDRTable[slot->patch->RR][slot->rks];
644
645 case RELEASE:
646 if (slot->sustine)
647 return dphaseDRTable[5][slot->rks];
648 else if (slot->patch->EG)
649 return dphaseDRTable[slot->patch->RR][slot->rks];
650 else
651 return dphaseDRTable[7][slot->rks];
652
653 case SETTLE:
654 return dphaseDRTable[15][0];
655
656 case FINISH:
657 return 0;
658
659 default:
660 return 0;
661 }
662}
663
664/*************************************************************
665
666 OPLL internal interfaces
667
668*************************************************************/
669#define SLOT_BD1 12
670#define SLOT_BD2 13
671#define SLOT_HH 14
672#define SLOT_SD 15
673#define SLOT_TOM 16
674#define SLOT_CYM 17
675
676/* We will set this dinamically, but not sure if this affects playback */
677#if defined(ROCKBOX)
678INLINE static void
679UPDATE_PG(OPLL_SLOT * slot)
680{
681 static const e_uint32 mltable[16] =
682 { 1, 1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2, 7 * 2, 8 * 2, 9 * 2, 10 * 2, 10 * 2, 12 * 2, 12 * 2, 15 * 2, 15 * 2 };
683
684 slot->dphase = RATE_ADJUST (((slot->fnum * mltable[slot->patch->ML]) << slot->block) >> (20 - DP_BITS));
685}
686#else
687#define UPDATE_PG(S) (S)->dphase = dphaseTable[(S)->fnum][(S)->block][(S)->patch->ML]
688#endif
689
690#define UPDATE_TLL(S)\
691(((S)->type==0)?\
692((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->patch->TL][(S)->patch->KL]):\
693((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->volume][(S)->patch->KL]))
694#define UPDATE_RKS(S) (S)->rks = rksTable[((S)->fnum)>>8][(S)->block][(S)->patch->KR]
695#define UPDATE_WF(S) (S)->sintbl = waveform[(S)->patch->WF]
696#define UPDATE_EG(S) (S)->eg_dphase = calc_eg_dphase(S)
697#define UPDATE_ALL(S)\
698 UPDATE_PG(S);\
699 UPDATE_TLL(S);\
700 UPDATE_RKS(S);\
701 UPDATE_WF(S); \
702 UPDATE_EG(S) /* EG should be updated last. */
703
704
705/* Slot key on */
706INLINE static void
707slotOn (OPLL_SLOT * slot)
708{
709 slot->eg_mode = ATTACK;
710 slot->eg_phase = 0;
711 slot->phase = 0;
712 UPDATE_EG(slot);
713}
714
715/* Slot key on without reseting the phase */
716INLINE static void
717slotOn2 (OPLL_SLOT * slot)
718{
719 slot->eg_mode = ATTACK;
720 slot->eg_phase = 0;
721 UPDATE_EG(slot);
722}
723
724/* Slot key off */
725INLINE static void
726slotOff (OPLL_SLOT * slot)
727{
728 if (slot->eg_mode == ATTACK)
729 slot->eg_phase = EXPAND_BITS (AR_ADJUST_TABLE[HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS)], EG_BITS, EG_DP_BITS);
730 slot->eg_mode = RELEASE;
731 UPDATE_EG(slot);
732}
733
734/* Channel key on */
735INLINE static void
736keyOn (OPLL * opll, e_int32 i)
737{
738 if (!opll->slot_on_flag[i * 2])
739 slotOn (MOD(opll,i));
740 if (!opll->slot_on_flag[i * 2 + 1])
741 slotOn (CAR(opll,i));
742 opll->key_status[i] = 1;
743}
744
745/* Channel key off */
746INLINE static void
747keyOff (OPLL * opll, e_int32 i)
748{
749 if (opll->slot_on_flag[i * 2 + 1])
750 slotOff (CAR(opll,i));
751 opll->key_status[i] = 0;
752}
753
754INLINE static void
755keyOn_BD (OPLL * opll)
756{
757 keyOn (opll, 6);
758}
759INLINE static void
760keyOn_SD (OPLL * opll)
761{
762 if (!opll->slot_on_flag[SLOT_SD])
763 slotOn (CAR(opll,7));
764}
765INLINE static void
766keyOn_TOM (OPLL * opll)
767{
768 if (!opll->slot_on_flag[SLOT_TOM])
769 slotOn (MOD(opll,8));
770}
771INLINE static void
772keyOn_HH (OPLL * opll)
773{
774 if (!opll->slot_on_flag[SLOT_HH])
775 slotOn2 (MOD(opll,7));
776}
777INLINE static void
778keyOn_CYM (OPLL * opll)
779{
780 if (!opll->slot_on_flag[SLOT_CYM])
781 slotOn2 (CAR(opll,8));
782}
783
784/* Drum key off */
785INLINE static void
786keyOff_BD (OPLL * opll)
787{
788 keyOff (opll, 6);
789}
790INLINE static void
791keyOff_SD (OPLL * opll)
792{
793 if (opll->slot_on_flag[SLOT_SD])
794 slotOff (CAR(opll,7));
795}
796INLINE static void
797keyOff_TOM (OPLL * opll)
798{
799 if (opll->slot_on_flag[SLOT_TOM])
800 slotOff (MOD(opll,8));
801}
802INLINE static void
803keyOff_HH (OPLL * opll)
804{
805 if (opll->slot_on_flag[SLOT_HH])
806 slotOff (MOD(opll,7));
807}
808INLINE static void
809keyOff_CYM (OPLL * opll)
810{
811 if (opll->slot_on_flag[SLOT_CYM])
812 slotOff (CAR(opll,8));
813}
814
815/* Change a voice */
816INLINE static void
817setPatch (OPLL * opll, e_int32 i, e_int32 num)
818{
819 opll->patch_number[i] = num;
820 MOD(opll,i)->patch = &opll->patch[num * 2 + 0];
821 CAR(opll,i)->patch = &opll->patch[num * 2 + 1];
822}
823
824/* Change a rhythm voice */
825INLINE static void
826setSlotPatch (OPLL_SLOT * slot, OPLL_PATCH * patch)
827{
828 slot->patch = patch;
829}
830
831/* Set sustine parameter */
832INLINE static void
833setSustine (OPLL * opll, e_int32 c, e_int32 sustine)
834{
835 CAR(opll,c)->sustine = sustine;
836 if (MOD(opll,c)->type)
837 MOD(opll,c)->sustine = sustine;
838}
839
840/* Volume : 6bit ( Volume register << 2 ) */
841INLINE static void
842setVolume (OPLL * opll, e_int32 c, e_int32 volume)
843{
844 CAR(opll,c)->volume = volume;
845}
846
847INLINE static void
848setSlotVolume (OPLL_SLOT * slot, e_int32 volume)
849{
850 slot->volume = volume;
851}
852
853/* Set F-Number ( fnum : 9bit ) */
854INLINE static void
855setFnumber (OPLL * opll, e_int32 c, e_int32 fnum)
856{
857 CAR(opll,c)->fnum = fnum;
858 MOD(opll,c)->fnum = fnum;
859}
860
861/* Set Block data (block : 3bit ) */
862INLINE static void
863setBlock (OPLL * opll, e_int32 c, e_int32 block)
864{
865 CAR(opll,c)->block = block;
866 MOD(opll,c)->block = block;
867}
868
869/* Change Rhythm Mode */
870INLINE static void
871update_rhythm_mode (OPLL * opll)
872{
873 if (opll->patch_number[6] & 0x10)
874 {
875 if (!(opll->slot_on_flag[SLOT_BD2] | (opll->reg[0x0e] & 32)))
876 {
877 opll->slot[SLOT_BD1].eg_mode = FINISH;
878 opll->slot[SLOT_BD2].eg_mode = FINISH;
879 setPatch (opll, 6, opll->reg[0x36] >> 4);
880 }
881 }
882 else if (opll->reg[0x0e] & 32)
883 {
884 opll->patch_number[6] = 16;
885 opll->slot[SLOT_BD1].eg_mode = FINISH;
886 opll->slot[SLOT_BD2].eg_mode = FINISH;
887 setSlotPatch (&opll->slot[SLOT_BD1], &opll->patch[16 * 2 + 0]);
888 setSlotPatch (&opll->slot[SLOT_BD2], &opll->patch[16 * 2 + 1]);
889 }
890
891 if (opll->patch_number[7] & 0x10)
892 {
893 if (!((opll->slot_on_flag[SLOT_HH] && opll->slot_on_flag[SLOT_SD]) | (opll->reg[0x0e] & 32)))
894 {
895 opll->slot[SLOT_HH].type = 0;
896 opll->slot[SLOT_HH].eg_mode = FINISH;
897 opll->slot[SLOT_SD].eg_mode = FINISH;
898 setPatch (opll, 7, opll->reg[0x37] >> 4);
899 }
900 }
901 else if (opll->reg[0x0e] & 32)
902 {
903 opll->patch_number[7] = 17;
904 opll->slot[SLOT_HH].type = 1;
905 opll->slot[SLOT_HH].eg_mode = FINISH;
906 opll->slot[SLOT_SD].eg_mode = FINISH;
907 setSlotPatch (&opll->slot[SLOT_HH], &opll->patch[17 * 2 + 0]);
908 setSlotPatch (&opll->slot[SLOT_SD], &opll->patch[17 * 2 + 1]);
909 }
910
911 if (opll->patch_number[8] & 0x10)
912 {
913 if (!((opll->slot_on_flag[SLOT_CYM] && opll->slot_on_flag[SLOT_TOM]) | (opll->reg[0x0e] & 32)))
914 {
915 opll->slot[SLOT_TOM].type = 0;
916 opll->slot[SLOT_TOM].eg_mode = FINISH;
917 opll->slot[SLOT_CYM].eg_mode = FINISH;
918 setPatch (opll, 8, opll->reg[0x38] >> 4);
919 }
920 }
921 else if (opll->reg[0x0e] & 32)
922 {
923 opll->patch_number[8] = 18;
924 opll->slot[SLOT_TOM].type = 1;
925 opll->slot[SLOT_TOM].eg_mode = FINISH;
926 opll->slot[SLOT_CYM].eg_mode = FINISH;
927 setSlotPatch (&opll->slot[SLOT_TOM], &opll->patch[18 * 2 + 0]);
928 setSlotPatch (&opll->slot[SLOT_CYM], &opll->patch[18 * 2 + 1]);
929 }
930}
931
932INLINE static void
933update_key_status (OPLL * opll)
934{
935 int ch;
936
937 for (ch = 0; ch < 9; ch++)
938 opll->slot_on_flag[ch * 2] = opll->slot_on_flag[ch * 2 + 1] = (opll->reg[0x20 + ch]) & 0x10;
939
940 if (opll->reg[0x0e] & 32)
941 {
942 opll->slot_on_flag[SLOT_BD1] |= (opll->reg[0x0e] & 0x10);
943 opll->slot_on_flag[SLOT_BD2] |= (opll->reg[0x0e] & 0x10);
944 opll->slot_on_flag[SLOT_SD] |= (opll->reg[0x0e] & 0x08);
945 opll->slot_on_flag[SLOT_HH] |= (opll->reg[0x0e] & 0x01);
946 opll->slot_on_flag[SLOT_TOM] |= (opll->reg[0x0e] & 0x04);
947 opll->slot_on_flag[SLOT_CYM] |= (opll->reg[0x0e] & 0x02);
948 }
949}
950
951void
952OPLL_copyPatch (OPLL * opll, e_int32 num, OPLL_PATCH * patch)
953{
954 memcpy (&opll->patch[num], patch, sizeof (OPLL_PATCH));
955}
956
957/***********************************************************
958
959 Initializing
960
961***********************************************************/
962
963static void
964OPLL_SLOT_reset (OPLL_SLOT * slot, int type)
965{
966 slot->type = type;
967 slot->sintbl = waveform[0];
968 slot->phase = 0;
969 slot->dphase = 0;
970 slot->output[0] = 0;
971 slot->output[1] = 0;
972 slot->feedback = 0;
973 slot->eg_mode = FINISH;
974 slot->eg_phase = EG_DP_WIDTH;
975 slot->eg_dphase = 0;
976 slot->rks = 0;
977 slot->tll = 0;
978 slot->sustine = 0;
979 slot->fnum = 0;
980 slot->block = 0;
981 slot->volume = 0;
982 slot->pgout = 0;
983 slot->egout = 0;
984 slot->patch = &null_patch;
985}
986
987static void
988internal_refresh (void)
989{
990#if !defined(ROCKBOX)
991 makeDphaseTable ();
992#endif
993 makeDphaseARTable ();
994 makeDphaseDRTable ();
995 pm_dphase = (e_uint32) RATE_ADJUST (PM_SPEED * PM_DP_WIDTH / (clk / 72));
996 am_dphase = (e_uint32) RATE_ADJUST (AM_SPEED * AM_DP_WIDTH / (clk / 72));
997}
998
999static void
1000maketables (e_uint32 c, e_uint32 r)
1001{
1002 if (c != clk)
1003 {
1004 clk = c;
1005 makePmTable ();
1006 makeAmTable ();
1007 makeDB2LinTable ();
1008 makeAdjustTable ();
1009 makeTllTable ();
1010 makeRksTable ();
1011 makeSinTable ();
1012 makeDefaultPatch ();
1013 }
1014
1015 if (r != rate)
1016 {
1017 rate = r;
1018 internal_refresh ();
1019 }
1020}
1021
1022void
1023OPLL_new (OPLL *opll, e_uint32 clk, e_uint32 rate)
1024{
1025 e_int32 i;
1026
1027 maketables (clk, rate);
1028
1029 memset(opll, 0, sizeof (OPLL));
1030 for (i = 0; i < 19 * 2; i++)
1031 memcpy(&opll->patch[i],&null_patch,sizeof(OPLL_PATCH));
1032
1033 opll->mask = 0;
1034
1035 OPLL_reset (opll);
1036 OPLL_reset_patch (opll, 0);
1037}
1038
1039
1040void
1041OPLL_delete (OPLL * opll)
1042{
1043 (void) opll;
1044}
1045
1046
1047/* Reset patch datas by system default. */
1048void
1049OPLL_reset_patch (OPLL * opll, e_int32 type)
1050{
1051 e_int32 i;
1052
1053 for (i = 0; i < 19 * 2; i++)
1054 OPLL_copyPatch (opll, i, &default_patch[type % OPLL_TONE_NUM][i]);
1055}
1056
1057/* Reset whole of OPLL except patch datas. */
1058void
1059OPLL_reset (OPLL * opll)
1060{
1061 e_int32 i;
1062
1063 if (!opll)
1064 return;
1065
1066 opll->adr = 0;
1067 opll->out = 0;
1068
1069 opll->pm_phase = 0;
1070 opll->am_phase = 0;
1071
1072 opll->noise_seed = 0xffff;
1073 opll->mask = 0;
1074
1075 for (i = 0; i <18; i++)
1076 OPLL_SLOT_reset(&opll->slot[i], i%2);
1077
1078 for (i = 0; i < 9; i++)
1079 {
1080 opll->key_status[i] = 0;
1081 setPatch (opll, i, 0);
1082 }
1083
1084 for (i = 0; i < 0x40; i++)
1085 OPLL_writeReg (opll, i, 0);
1086
1087#ifndef EMU2413_COMPACTION
1088 opll->realstep = (e_uint32) ((1 << 31) / rate);
1089 opll->opllstep = (e_uint32) ((1 << 31) / (clk / 72));
1090 opll->oplltime = 0;
1091 for (i = 0; i < 14; i++)
1092 opll->pan[i] = 2;
1093 opll->sprev[0] = opll->sprev[1] = 0;
1094 opll->snext[0] = opll->snext[1] = 0;
1095#endif
1096}
1097
1098/* Force Refresh (When external program changes some parameters). */
1099void
1100OPLL_forceRefresh (OPLL * opll)
1101{
1102 e_int32 i;
1103
1104 if (opll == NULL)
1105 return;
1106
1107 for (i = 0; i < 9; i++)
1108 setPatch(opll,i,opll->patch_number[i]);
1109
1110 for (i = 0; i < 18; i++)
1111 {
1112 UPDATE_PG (&opll->slot[i]);
1113 UPDATE_RKS (&opll->slot[i]);
1114 UPDATE_TLL (&opll->slot[i]);
1115 UPDATE_WF (&opll->slot[i]);
1116 UPDATE_EG (&opll->slot[i]);
1117 }
1118}
1119
1120void
1121OPLL_set_rate (OPLL * opll, e_uint32 r)
1122{
1123 if (rate == r) return;
1124 if (opll->quality)
1125 rate = 49716;
1126 else
1127 rate = r;
1128 internal_refresh ();
1129 rate = r;
1130}
1131
1132void
1133OPLL_set_quality (OPLL * opll, e_uint32 q)
1134{
1135 opll->quality = q;
1136 OPLL_set_rate (opll, rate);
1137}
1138
1139/*********************************************************
1140
1141 Generate wave data
1142
1143*********************************************************/
1144/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 2PI). */
1145#if ( SLOT_AMP_BITS - PG_BITS ) > 0
1146#define wave2_2pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS ))
1147#else
1148#define wave2_2pi(e) ( (e) << ( PG_BITS - SLOT_AMP_BITS ))
1149#endif
1150
1151/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 4PI). */
1152#if ( SLOT_AMP_BITS - PG_BITS - 1 ) == 0
1153#define wave2_4pi(e) (e)
1154#elif ( SLOT_AMP_BITS - PG_BITS - 1 ) > 0
1155#define wave2_4pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS - 1 ))
1156#else
1157#define wave2_4pi(e) ( (e) << ( 1 + PG_BITS - SLOT_AMP_BITS ))
1158#endif
1159
1160/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 8PI). */
1161#if ( SLOT_AMP_BITS - PG_BITS - 2 ) == 0
1162#define wave2_8pi(e) (e)
1163#elif ( SLOT_AMP_BITS - PG_BITS - 2 ) > 0
1164#define wave2_8pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS - 2 ))
1165#else
1166#define wave2_8pi(e) ( (e) << ( 2 + PG_BITS - SLOT_AMP_BITS ))
1167#endif
1168
1169/* Update AM, PM unit */
1170static void
1171update_ampm (OPLL * opll)
1172{
1173 opll->pm_phase = (opll->pm_phase + pm_dphase) & (PM_DP_WIDTH - 1);
1174 opll->am_phase = (opll->am_phase + am_dphase) & (AM_DP_WIDTH - 1);
1175 opll->lfo_am = amtable[HIGHBITS (opll->am_phase, AM_DP_BITS - AM_PG_BITS)];
1176 opll->lfo_pm = pmtable[HIGHBITS (opll->pm_phase, PM_DP_BITS - PM_PG_BITS)];
1177}
1178
1179/* PG */
1180INLINE static void
1181calc_phase (OPLL_SLOT * slot, e_int32 lfo)
1182{
1183 if (slot->patch->PM)
1184 slot->phase += (slot->dphase * lfo) >> PM_AMP_BITS;
1185 else
1186 slot->phase += slot->dphase;
1187
1188 slot->phase &= (DP_WIDTH - 1);
1189
1190 slot->pgout = HIGHBITS (slot->phase, DP_BASE_BITS);
1191}
1192
1193/* Update Noise unit */
1194static void
1195update_noise (OPLL * opll)
1196{
1197 if(opll->noise_seed&1) opll->noise_seed ^= 0x8003020;
1198 opll->noise_seed >>= 1;
1199}
1200
1201/* EG */
1202static void
1203calc_envelope (OPLL_SLOT * slot, e_int32 lfo)
1204{
1205#define S2E(x) (SL2EG((e_int32)(x/SL_STEP))<<(EG_DP_BITS-EG_BITS))
1206
1207 static e_uint32 SL[16] = {
1208 S2E (0.0), S2E (3.0), S2E (6.0), S2E (9.0), S2E (12.0), S2E (15.0), S2E (18.0), S2E (21.0),
1209 S2E (24.0), S2E (27.0), S2E (30.0), S2E (33.0), S2E (36.0), S2E (39.0), S2E (42.0), S2E (48.0)
1210 };
1211
1212 e_uint32 egout;
1213
1214 switch (slot->eg_mode)
1215 {
1216 case ATTACK:
1217 egout = AR_ADJUST_TABLE[HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS)];
1218 slot->eg_phase += slot->eg_dphase;
1219 if((EG_DP_WIDTH & slot->eg_phase)||(slot->patch->AR==15))
1220 {
1221 egout = 0;
1222 slot->eg_phase = 0;
1223 slot->eg_mode = DECAY;
1224 UPDATE_EG (slot);
1225 }
1226 break;
1227
1228 case DECAY:
1229 egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS);
1230 slot->eg_phase += slot->eg_dphase;
1231 if (slot->eg_phase >= SL[slot->patch->SL])
1232 {
1233 if (slot->patch->EG)
1234 {
1235 slot->eg_phase = SL[slot->patch->SL];
1236 slot->eg_mode = SUSHOLD;
1237 UPDATE_EG (slot);
1238 }
1239 else
1240 {
1241 slot->eg_phase = SL[slot->patch->SL];
1242 slot->eg_mode = SUSTINE;
1243 UPDATE_EG (slot);
1244 }
1245 }
1246 break;
1247
1248 case SUSHOLD:
1249 egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS);
1250 if (slot->patch->EG == 0)
1251 {
1252 slot->eg_mode = SUSTINE;
1253 UPDATE_EG (slot);
1254 }
1255 break;
1256
1257 case SUSTINE:
1258 case RELEASE:
1259 egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS);
1260 slot->eg_phase += slot->eg_dphase;
1261 if (egout >= (1 << EG_BITS))
1262 {
1263 slot->eg_mode = FINISH;
1264 egout = (1 << EG_BITS) - 1;
1265 }
1266 break;
1267
1268 case SETTLE:
1269 egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS);
1270 slot->eg_phase += slot->eg_dphase;
1271 if (egout >= (1 << EG_BITS))
1272 {
1273 slot->eg_mode = ATTACK;
1274 egout = (1 << EG_BITS) - 1;
1275 UPDATE_EG(slot);
1276 }
1277 break;
1278
1279 case FINISH:
1280 egout = (1 << EG_BITS) - 1;
1281 break;
1282
1283 default:
1284 egout = (1 << EG_BITS) - 1;
1285 break;
1286 }
1287
1288 if (slot->patch->AM)
1289 egout = EG2DB (egout + slot->tll) + lfo;
1290 else
1291 egout = EG2DB (egout + slot->tll);
1292
1293 if (egout >= DB_MUTE)
1294 egout = DB_MUTE - 1;
1295
1296 slot->egout = egout | 3;
1297}
1298
1299/* CARRIOR */
1300INLINE static e_int32
1301calc_slot_car (OPLL_SLOT * slot, e_int32 fm)
1302{
1303 if (slot->egout >= (DB_MUTE - 1))
1304 {
1305 slot->output[0] = 0;
1306 }
1307 else
1308 {
1309 slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout+wave2_8pi(fm))&(PG_WIDTH-1)] + slot->egout];
1310 }
1311
1312 slot->output[1] = (slot->output[1] + slot->output[0]) >> 1;
1313 return slot->output[1];
1314}
1315
1316/* MODULATOR */
1317INLINE static e_int32
1318calc_slot_mod (OPLL_SLOT * slot)
1319{
1320 e_int32 fm;
1321
1322 slot->output[1] = slot->output[0];
1323
1324 if (slot->egout >= (DB_MUTE - 1))
1325 {
1326 slot->output[0] = 0;
1327 }
1328 else if (slot->patch->FB != 0)
1329 {
1330 fm = wave2_4pi (slot->feedback) >> (7 - slot->patch->FB);
1331 slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout+fm)&(PG_WIDTH-1)] + slot->egout];
1332 }
1333 else
1334 {
1335 slot->output[0] = DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout];
1336 }
1337
1338 slot->feedback = (slot->output[1] + slot->output[0]) >> 1;
1339
1340 return slot->feedback;
1341
1342}
1343
1344/* TOM */
1345INLINE static e_int32
1346calc_slot_tom (OPLL_SLOT * slot)
1347{
1348 if (slot->egout >= (DB_MUTE - 1))
1349 return 0;
1350
1351 return DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout];
1352
1353}
1354
1355/* SNARE */
1356INLINE static e_int32
1357calc_slot_snare (OPLL_SLOT * slot, e_uint32 noise)
1358{
1359 if(slot->egout>=(DB_MUTE-1))
1360 return 0;
1361
1362 if(BIT(slot->pgout,7))
1363 return DB2LIN_TABLE[(noise?DB_POS(0.0):DB_POS(15.0))+slot->egout];
1364 else
1365 return DB2LIN_TABLE[(noise?DB_NEG(0.0):DB_NEG(15.0))+slot->egout];
1366}
1367
1368/*
1369 TOP-CYM
1370 */
1371INLINE static e_int32
1372calc_slot_cym (OPLL_SLOT * slot, e_uint32 pgout_hh)
1373{
1374 e_uint32 dbout;
1375
1376 if (slot->egout >= (DB_MUTE - 1))
1377 return 0;
1378 else if(
1379 /* the same as fmopl.c */
1380 ((BIT(pgout_hh,PG_BITS-8)^BIT(pgout_hh,PG_BITS-1))|BIT(pgout_hh,PG_BITS-7)) ^
1381 /* different from fmopl.c */
1382 (BIT(slot->pgout,PG_BITS-7)&!BIT(slot->pgout,PG_BITS-5))
1383 )
1384 dbout = DB_NEG(3.0);
1385 else
1386 dbout = DB_POS(3.0);
1387
1388 return DB2LIN_TABLE[dbout + slot->egout];
1389}
1390
1391/*
1392 HI-HAT
1393*/
1394INLINE static e_int32
1395calc_slot_hat (OPLL_SLOT *slot, e_int32 pgout_cym, e_uint32 noise)
1396{
1397 e_uint32 dbout;
1398
1399 if (slot->egout >= (DB_MUTE - 1))
1400 return 0;
1401 else if(
1402 /* the same as fmopl.c */
1403 ((BIT(slot->pgout,PG_BITS-8)^BIT(slot->pgout,PG_BITS-1))|BIT(slot->pgout,PG_BITS-7)) ^
1404 /* different from fmopl.c */
1405 (BIT(pgout_cym,PG_BITS-7)&!BIT(pgout_cym,PG_BITS-5))
1406 )
1407 {
1408 if(noise)
1409 dbout = DB_NEG(12.0);
1410 else
1411 dbout = DB_NEG(24.0);
1412 }
1413 else
1414 {
1415 if(noise)
1416 dbout = DB_POS(12.0);
1417 else
1418 dbout = DB_POS(24.0);
1419 }
1420
1421 return DB2LIN_TABLE[dbout + slot->egout];
1422}
1423
1424static e_int16
1425calc (OPLL * opll)
1426{
1427 e_int32 i;
1428
1429 update_ampm (opll);
1430 update_noise (opll);
1431
1432 for (i = 0; i < 18; i++)
1433 {
1434 calc_phase(&opll->slot[i],opll->lfo_pm);
1435 calc_envelope(&opll->slot[i],opll->lfo_am);
1436 }
1437
1438 e_uint32 channel_mask = opll->mask;
1439 for (i = 0; i < 9; i++) {
1440 if (CAR(opll,i)->eg_mode != FINISH)
1441 channel_mask |= (1 << i);
1442 }
1443
1444 e_int32 mix = 0;
1445
1446 /* CH6 */
1447 if (opll->patch_number[6] & 0x10) {
1448 if (channel_mask & OPLL_MASK_CH (6)) {
1449 mix += calc_slot_car (CAR(opll,6), calc_slot_mod(MOD(opll,6)));
1450 channel_mask &= ~(1 << 6);
1451 }
1452 }
1453
1454 /* CH7 */
1455 if (opll->patch_number[7] & 0x10) {
1456 if (MOD(opll,7)->eg_mode != FINISH)
1457 mix += calc_slot_hat (MOD(opll,7), CAR(opll,8)->pgout, opll->noise_seed&1);
1458 if (channel_mask & OPLL_MASK_SD) {
1459 mix -= calc_slot_snare (CAR(opll,7), opll->noise_seed&1);
1460 channel_mask &= ~OPLL_MASK_SD;
1461 }
1462 }
1463
1464 /* CH8 */
1465 if (opll->patch_number[8] & 0x10) {
1466 if (MOD(opll,8)->eg_mode != FINISH)
1467 mix += calc_slot_tom (MOD(opll,8));
1468 if (channel_mask & OPLL_MASK_CYM) {
1469 mix -= calc_slot_cym (CAR(opll,8), MOD(opll,7)->pgout);
1470 channel_mask &= ~OPLL_MASK_CYM;
1471 }
1472 }
1473
1474 mix <<= 1;
1475
1476 opll->current_mask = channel_mask;
1477 for (i = 0; channel_mask; channel_mask >>= 1, ++i) {
1478 if (channel_mask & 1) {
1479 mix += calc_slot_car (CAR(opll,i), calc_slot_mod(MOD(opll,i)));
1480 }
1481 }
1482
1483 return (e_int16) mix << 3;
1484}
1485
1486void
1487OPLL_set_internal_mute(OPLL * opll, e_uint32 mute)
1488{
1489 opll->internal_mute = mute;
1490}
1491
1492e_uint32
1493OPLL_is_internal_muted(OPLL * opll)
1494{
1495 return opll->internal_mute;
1496}
1497
1498e_uint32
1499check_mute_helper(OPLL * opll)
1500{
1501 for (int i = 0; i < 6; i++) {
1502 /* if (ch[i].car.eg_mode != FINISH) return 0; */
1503 if (!(opll->current_mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) return 0;
1504 }
1505
1506 if (!(opll->reg[0x0e] & 0x20)) {
1507 for(int i = 6; i < 9; i++) {
1508 /* if (ch[i].car.eg_mode != FINISH) return 0; */
1509 if (!(opll->current_mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) return 0;
1510 }
1511 } else {
1512 /* if (ch[6].car.eg_mode != FINISH) return false;
1513 if (ch[7].mod.eg_mode != FINISH) return false;
1514 if (ch[7].car.eg_mode != FINISH) return false;
1515 if (ch[8].mod.eg_mode != FINISH) return false;
1516 if (ch[8].car.eg_mode != FINISH) return false; */
1517 if (!(opll->current_mask & OPLL_MASK_CH (6)) && (CAR(opll,6)->eg_mode != FINISH)) return 0;
1518 if (!(opll->current_mask & OPLL_MASK_CH (7)) && (MOD(opll,7)->eg_mode != FINISH)) return 0;
1519 if (!(opll->current_mask & OPLL_MASK_CH (7)) && (CAR(opll,7)->eg_mode != FINISH)) return 0;
1520 if (!(opll->current_mask & OPLL_MASK_CH (8)) && (MOD(opll,8)->eg_mode != FINISH)) return 0;
1521 if (!(opll->current_mask & OPLL_MASK_CH (8)) && (CAR(opll,8)->eg_mode != FINISH)) return 0;
1522 }
1523
1524 return 1; /* nothing is playing, then mute */
1525}
1526
1527void
1528check_mute(OPLL * opll)
1529{
1530 OPLL_set_internal_mute (opll, check_mute_helper (opll));
1531}
1532
1533EMU2413_API e_int16 *OPLL_update_buffer(OPLL * opll, e_uint32 length)
1534{
1535 e_int16* buf = opll->buffer;
1536 while (length--) {
1537 *(buf++) = calc (opll);
1538 }
1539 check_mute (opll);
1540
1541 return opll->buffer;
1542}
1543
1544#ifdef EMU2413_COMPACTION
1545e_int16
1546OPLL_calc (OPLL * opll)
1547{
1548 return calc (opll);
1549}
1550#else
1551e_int16
1552OPLL_calc (OPLL * opll)
1553{
1554 if (!opll->quality)
1555 return calc (opll);
1556
1557 while (opll->realstep > opll->oplltime)
1558 {
1559 opll->oplltime += opll->opllstep;
1560 opll->prev = opll->next;
1561 opll->next = calc (opll);
1562 }
1563
1564 opll->oplltime -= opll->realstep;
1565 opll->out = (e_int16) (((double) opll->next * (opll->opllstep - opll->oplltime)
1566 + (double) opll->prev * opll->oplltime) / opll->opllstep);
1567
1568 return (e_int16) opll->out;
1569}
1570#endif
1571
1572e_uint32
1573OPLL_setMask (OPLL * opll, e_uint32 mask)
1574{
1575 e_uint32 ret;
1576
1577 if (opll)
1578 {
1579 ret = opll->mask;
1580 opll->mask = mask;
1581 return ret;
1582 }
1583 else
1584 return 0;
1585}
1586
1587e_uint32
1588OPLL_toggleMask (OPLL * opll, e_uint32 mask)
1589{
1590 e_uint32 ret;
1591
1592 if (opll)
1593 {
1594 ret = opll->mask;
1595 opll->mask ^= mask;
1596 return ret;
1597 }
1598 else
1599 return 0;
1600}
1601
1602/****************************************************
1603
1604 I/O Ctrl
1605
1606*****************************************************/
1607
1608void
1609OPLL_writeReg (OPLL * opll, e_uint32 reg, e_uint32 data)
1610{
1611 e_int32 i, v, ch;
1612
1613 data = data & 0xff;
1614 reg = reg & 0x3f;
1615 opll->reg[reg] = (e_uint8) data;
1616
1617 switch (reg)
1618 {
1619 case 0x00:
1620 opll->patch[0].AM = (data >> 7) & 1;
1621 opll->patch[0].PM = (data >> 6) & 1;
1622 opll->patch[0].EG = (data >> 5) & 1;
1623 opll->patch[0].KR = (data >> 4) & 1;
1624 opll->patch[0].ML = (data) & 15;
1625 for (i = 0; i < 9; i++)
1626 {
1627 if (opll->patch_number[i] == 0)
1628 {
1629 UPDATE_PG (MOD(opll,i));
1630 UPDATE_RKS (MOD(opll,i));
1631 UPDATE_EG (MOD(opll,i));
1632 }
1633 }
1634 break;
1635
1636 case 0x01:
1637 opll->patch[1].AM = (data >> 7) & 1;
1638 opll->patch[1].PM = (data >> 6) & 1;
1639 opll->patch[1].EG = (data >> 5) & 1;
1640 opll->patch[1].KR = (data >> 4) & 1;
1641 opll->patch[1].ML = (data) & 15;
1642 for (i = 0; i < 9; i++)
1643 {
1644 if (opll->patch_number[i] == 0)
1645 {
1646 UPDATE_PG (CAR(opll,i));
1647 UPDATE_RKS (CAR(opll,i));
1648 UPDATE_EG (CAR(opll,i));
1649 }
1650 }
1651 break;
1652
1653 case 0x02:
1654 opll->patch[0].KL = (data >> 6) & 3;
1655 opll->patch[0].TL = (data) & 63;
1656 for (i = 0; i < 9; i++)
1657 {
1658 if (opll->patch_number[i] == 0)
1659 {
1660 UPDATE_TLL(MOD(opll,i));
1661 }
1662 }
1663 break;
1664
1665 case 0x03:
1666 opll->patch[1].KL = (data >> 6) & 3;
1667 opll->patch[1].WF = (data >> 4) & 1;
1668 opll->patch[0].WF = (data >> 3) & 1;
1669 opll->patch[0].FB = (data) & 7;
1670 for (i = 0; i < 9; i++)
1671 {
1672 if (opll->patch_number[i] == 0)
1673 {
1674 UPDATE_WF(MOD(opll,i));
1675 UPDATE_WF(CAR(opll,i));
1676 }
1677 }
1678 break;
1679
1680 case 0x04:
1681 opll->patch[0].AR = (data >> 4) & 15;
1682 opll->patch[0].DR = (data) & 15;
1683 for (i = 0; i < 9; i++)
1684 {
1685 if (opll->patch_number[i] == 0)
1686 {
1687 UPDATE_EG (MOD(opll,i));
1688 }
1689 }
1690 break;
1691
1692 case 0x05:
1693 opll->patch[1].AR = (data >> 4) & 15;
1694 opll->patch[1].DR = (data) & 15;
1695 for (i = 0; i < 9; i++)
1696 {
1697 if (opll->patch_number[i] == 0)
1698 {
1699 UPDATE_EG(CAR(opll,i));
1700 }
1701 }
1702 break;
1703
1704 case 0x06:
1705 opll->patch[0].SL = (data >> 4) & 15;
1706 opll->patch[0].RR = (data) & 15;
1707 for (i = 0; i < 9; i++)
1708 {
1709 if (opll->patch_number[i] == 0)
1710 {
1711 UPDATE_EG (MOD(opll,i));
1712 }
1713 }
1714 break;
1715
1716 case 0x07:
1717 opll->patch[1].SL = (data >> 4) & 15;
1718 opll->patch[1].RR = (data) & 15;
1719 for (i = 0; i < 9; i++)
1720 {
1721 if (opll->patch_number[i] == 0)
1722 {
1723 UPDATE_EG (CAR(opll,i));
1724 }
1725 }
1726 break;
1727
1728 case 0x0e:
1729 update_rhythm_mode (opll);
1730 if (data & 32)
1731 {
1732 if (data & 0x10)
1733 keyOn_BD (opll);
1734 else
1735 keyOff_BD (opll);
1736 if (data & 0x8)
1737 keyOn_SD (opll);
1738 else
1739 keyOff_SD (opll);
1740 if (data & 0x4)
1741 keyOn_TOM (opll);
1742 else
1743 keyOff_TOM (opll);
1744 if (data & 0x2)
1745 keyOn_CYM (opll);
1746 else
1747 keyOff_CYM (opll);
1748 if (data & 0x1)
1749 keyOn_HH (opll);
1750 else
1751 keyOff_HH (opll);
1752 }
1753 update_key_status (opll);
1754
1755 UPDATE_ALL (MOD(opll,6));
1756 UPDATE_ALL (CAR(opll,6));
1757 UPDATE_ALL (MOD(opll,7));
1758 UPDATE_ALL (CAR(opll,7));
1759 UPDATE_ALL (MOD(opll,8));
1760 UPDATE_ALL (CAR(opll,8));
1761
1762 break;
1763
1764 case 0x0f:
1765 break;
1766
1767 case 0x10:
1768 case 0x11:
1769 case 0x12:
1770 case 0x13:
1771 case 0x14:
1772 case 0x15:
1773 case 0x16:
1774 case 0x17:
1775 case 0x18:
1776 ch = reg - 0x10;
1777 setFnumber (opll, ch, data + ((opll->reg[0x20 + ch] & 1) << 8));
1778 UPDATE_ALL (MOD(opll,ch));
1779 UPDATE_ALL (CAR(opll,ch));
1780 break;
1781
1782 case 0x20:
1783 case 0x21:
1784 case 0x22:
1785 case 0x23:
1786 case 0x24:
1787 case 0x25:
1788 case 0x26:
1789 case 0x27:
1790 case 0x28:
1791 ch = reg - 0x20;
1792 setFnumber (opll, ch, ((data & 1) << 8) + opll->reg[0x10 + ch]);
1793 setBlock (opll, ch, (data >> 1) & 7);
1794 setSustine (opll, ch, (data >> 5) & 1);
1795 if (data & 0x10)
1796 keyOn (opll, ch);
1797 else
1798 keyOff (opll, ch);
1799 UPDATE_ALL (MOD(opll,ch));
1800 UPDATE_ALL (CAR(opll,ch));
1801 update_key_status (opll);
1802 update_rhythm_mode (opll);
1803 break;
1804
1805 case 0x30:
1806 case 0x31:
1807 case 0x32:
1808 case 0x33:
1809 case 0x34:
1810 case 0x35:
1811 case 0x36:
1812 case 0x37:
1813 case 0x38:
1814 i = (data >> 4) & 15;
1815 v = data & 15;
1816 if ((opll->reg[0x0e] & 32) && (reg >= 0x36))
1817 {
1818 switch (reg)
1819 {
1820 case 0x37:
1821 setSlotVolume (MOD(opll,7), i << 2);
1822 break;
1823 case 0x38:
1824 setSlotVolume (MOD(opll,8), i << 2);
1825 break;
1826 default:
1827 break;
1828 }
1829 }
1830 else
1831 {
1832 setPatch (opll, reg - 0x30, i);
1833 }
1834 setVolume (opll, reg - 0x30, v << 2);
1835 UPDATE_ALL (MOD(opll,reg - 0x30));
1836 UPDATE_ALL (CAR(opll,reg - 0x30));
1837 break;
1838
1839 default:
1840 break;
1841
1842 }
1843}
1844
1845void
1846OPLL_writeIO (OPLL * opll, e_uint32 adr, e_uint32 val)
1847{
1848 if (adr & 1)
1849 OPLL_writeReg (opll, opll->adr, val);
1850 else
1851 opll->adr = val;
1852}
1853
1854e_uint32
1855OPLL_read(OPLL * opll, e_uint32 a)
1856{
1857 if( !(a&1) )
1858 {
1859 /* status port */
1860 return opll->status;
1861 }
1862 return 0xff;
1863}
1864
1865#ifndef EMU2413_COMPACTION
1866/* STEREO MODE (OPT) */
1867void
1868OPLL_set_pan (OPLL * opll, e_uint32 ch, e_uint32 pan)
1869{
1870 opll->pan[ch & 15] = pan & 3;
1871}
1872
1873static void
1874calc_stereo (OPLL * opll, e_int32 out[2])
1875{
1876 e_int32 b[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */
1877 e_int32 r[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */
1878 e_int32 i;
1879
1880 update_ampm (opll);
1881 update_noise (opll);
1882
1883 for(i=0;i<18;i++)
1884 {
1885 calc_phase(&opll->slot[i],opll->lfo_pm);
1886 calc_envelope(&opll->slot[i],opll->lfo_am);
1887 }
1888
1889 for (i = 0; i < 6; i++)
1890 if (!(opll->mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH))
1891 b[opll->pan[i]] += calc_slot_car (CAR(opll,i), calc_slot_mod (MOD(opll,i)));
1892
1893
1894 if (opll->patch_number[6] <= 15)
1895 {
1896 if (!(opll->mask & OPLL_MASK_CH (6)) && (CAR(opll,6)->eg_mode != FINISH))
1897 b[opll->pan[6]] += calc_slot_car (CAR(opll,6), calc_slot_mod (MOD(opll,6)));
1898 }
1899 else
1900 {
1901 if (!(opll->mask & OPLL_MASK_BD) && (CAR(opll,6)->eg_mode != FINISH))
1902 r[opll->pan[9]] += calc_slot_car (CAR(opll,6), calc_slot_mod (MOD(opll,6)));
1903 }
1904
1905 if (opll->patch_number[7] <= 15)
1906 {
1907 if (!(opll->mask & OPLL_MASK_CH (7)) && (CAR (opll,7)->eg_mode != FINISH))
1908 b[opll->pan[7]] += calc_slot_car (CAR (opll,7), calc_slot_mod (MOD (opll,7)));
1909 }
1910 else
1911 {
1912 if (!(opll->mask & OPLL_MASK_HH) && (MOD (opll,7)->eg_mode != FINISH))
1913 r[opll->pan[10]] += calc_slot_hat (MOD (opll,7), CAR(opll,8)->pgout, opll->noise_seed&1);
1914 if (!(opll->mask & OPLL_MASK_SD) && (CAR (opll,7)->eg_mode != FINISH))
1915 r[opll->pan[11]] -= calc_slot_snare (CAR (opll,7), opll->noise_seed&1);
1916 }
1917
1918 if (opll->patch_number[8] <= 15)
1919 {
1920 if (!(opll->mask & OPLL_MASK_CH (8)) && (CAR (opll,8)->eg_mode != FINISH))
1921 b[opll->pan[8]] += calc_slot_car (CAR (opll,8), calc_slot_mod (MOD (opll,8)));
1922 }
1923 else
1924 {
1925 if (!(opll->mask & OPLL_MASK_TOM) && (MOD (opll,8)->eg_mode != FINISH))
1926 r[opll->pan[12]] += calc_slot_tom (MOD (opll,8));
1927 if (!(opll->mask & OPLL_MASK_CYM) && (CAR (opll,8)->eg_mode != FINISH))
1928 r[opll->pan[13]] -= calc_slot_cym (CAR (opll,8), MOD(opll,7)->pgout);
1929 }
1930
1931 out[1] = (b[1] + b[3] + ((r[1] + r[3]) << 1)) <<3;
1932 out[0] = (b[2] + b[3] + ((r[2] + r[3]) << 1)) <<3;
1933}
1934
1935void
1936OPLL_calc_stereo (OPLL * opll, e_int32 out[2])
1937{
1938 if (!opll->quality)
1939 {
1940 calc_stereo (opll, out);
1941 return;
1942 }
1943
1944 while (opll->realstep > opll->oplltime)
1945 {
1946 opll->oplltime += opll->opllstep;
1947 opll->sprev[0] = opll->snext[0];
1948 opll->sprev[1] = opll->snext[1];
1949 calc_stereo (opll, opll->snext);
1950 }
1951
1952 opll->oplltime -= opll->realstep;
1953 out[0] = (e_int16) (((double) opll->snext[0] * (opll->opllstep - opll->oplltime)
1954 + (double) opll->sprev[0] * opll->oplltime) / opll->opllstep);
1955 out[1] = (e_int16) (((double) opll->snext[1] * (opll->opllstep - opll->oplltime)
1956 + (double) opll->sprev[1] * opll->oplltime) / opll->opllstep);
1957}
1958#endif /* EMU2413_COMPACTION */
diff --git a/apps/codecs/libgme/emu2413.h b/apps/codecs/libgme/emu2413.h
new file mode 100644
index 0000000000..9ee4513ff3
--- /dev/null
+++ b/apps/codecs/libgme/emu2413.h
@@ -0,0 +1,164 @@
1#ifndef _EMU2413_H_
2#define _EMU2413_H_
3
4#include "blargg_common.h"
5#include "emutypes.h"
6
7#ifdef EMU2413_DLL_EXPORTS
8 #define EMU2413_API __declspec(dllexport)
9#elif defined(EMU2413_DLL_IMPORTS)
10 #define EMU2413_API __declspec(dllimport)
11#else
12 #define EMU2413_API
13#endif
14
15#ifdef __cplusplus
16extern "C" {
17#endif
18
19#define AUDIO_MONO_BUFFER_SIZE 1024
20
21#define PI 3.14159265358979323846
22
23enum OPLL_TONE_ENUM {OPLL_2413_TONE=0, OPLL_VRC7_TONE=1, OPLL_281B_TONE=2} ;
24
25/* voice data */
26typedef struct __OPLL_PATCH {
27 e_uint32 TL,FB,EG,ML,AR,DR,SL,RR,KR,KL,AM,PM,WF ;
28} OPLL_PATCH ;
29
30/* slot */
31typedef struct __OPLL_SLOT {
32
33 OPLL_PATCH *patch;
34
35 e_int32 type ; /* 0 : modulator 1 : carrier */
36
37 /* OUTPUT */
38 e_int32 feedback ;
39 e_int32 output[2] ; /* Output value of slot */
40
41 /* for Phase Generator (PG) */
42 e_uint16 *sintbl ; /* Wavetable */
43 e_uint32 phase ; /* Phase */
44 e_uint32 dphase ; /* Phase increment amount */
45 e_uint32 pgout ; /* output */
46
47 /* for Envelope Generator (EG) */
48 e_int32 fnum ; /* F-Number */
49 e_int32 block ; /* Block */
50 e_int32 volume ; /* Current volume */
51 e_int32 sustine ; /* Sustine 1 = ON, 0 = OFF */
52 e_uint32 tll ; /* Total Level + Key scale level*/
53 e_uint32 rks ; /* Key scale offset (Rks) */
54 e_int32 eg_mode ; /* Current state */
55 e_uint32 eg_phase ; /* Phase */
56 e_uint32 eg_dphase ; /* Phase increment amount */
57 e_uint32 egout ; /* output */
58
59} OPLL_SLOT ;
60
61/* Mask */
62#define OPLL_MASK_CH(x) (1<<(x))
63#define OPLL_MASK_HH (1<<(9))
64#define OPLL_MASK_CYM (1<<(10))
65#define OPLL_MASK_TOM (1<<(11))
66#define OPLL_MASK_SD (1<<(12))
67#define OPLL_MASK_BD (1<<(13))
68#define OPLL_MASK_RHYTHM ( OPLL_MASK_HH | OPLL_MASK_CYM | OPLL_MASK_TOM | OPLL_MASK_SD | OPLL_MASK_BD )
69
70/* opll */
71typedef struct __OPLL {
72
73 e_uint32 adr ;
74 e_int32 out ;
75
76#ifndef EMU2413_COMPACTION
77 e_uint32 realstep ;
78 e_uint32 oplltime ;
79 e_uint32 opllstep ;
80 e_int32 prev, next ;
81 e_int32 sprev[2],snext[2];
82 e_uint32 pan[16];
83#endif
84
85 /* Register */
86 e_uint8 reg[0x40] ;
87 e_int32 slot_on_flag[18] ;
88
89 /* Pitch Modulator */
90 e_uint32 pm_phase ;
91 e_int32 lfo_pm ;
92
93 /* Amp Modulator */
94 e_int32 am_phase ;
95 e_int32 lfo_am ;
96
97 e_uint32 quality;
98
99 /* Noise Generator */
100 e_uint32 noise_seed ;
101
102 /* Channel Data */
103 e_int32 patch_number[9];
104 e_int32 key_status[9] ;
105
106 /* Slot */
107 OPLL_SLOT slot[18] ;
108
109 /* Voice Data */
110 OPLL_PATCH patch[19*2] ;
111 e_int32 patch_update[2] ; /* flag for check patch update */
112
113 e_uint32 mask ;
114 e_uint32 current_mask;
115 e_uint32 status;
116
117 e_uint32 internal_mute;
118 e_int16 buffer[AUDIO_MONO_BUFFER_SIZE];
119} OPLL ;
120
121/* Create Object */
122EMU2413_API void OPLL_new(OPLL *, e_uint32 clk, e_uint32 rate) ;
123EMU2413_API void OPLL_delete(OPLL *) ;
124
125/* Setup */
126EMU2413_API void OPLL_reset(OPLL *) ;
127EMU2413_API void OPLL_reset_patch(OPLL *, e_int32) ;
128EMU2413_API void OPLL_set_rate(OPLL *opll, e_uint32 r) ;
129EMU2413_API void OPLL_set_quality(OPLL *opll, e_uint32 q) ;
130EMU2413_API void OPLL_set_pan(OPLL *, e_uint32 ch, e_uint32 pan);
131EMU2413_API void OPLL_set_internal_mute(OPLL *, e_uint32 mute);
132EMU2413_API e_uint32 OPLL_is_internal_muted(OPLL *);
133
134/* Port/Register access */
135EMU2413_API void OPLL_writeIO(OPLL *, e_uint32 reg, e_uint32 val); ICODE_ATTR
136EMU2413_API void OPLL_writeReg(OPLL *, e_uint32 reg, e_uint32 val); ICODE_ATTR
137EMU2413_API e_uint32 OPLL_read(OPLL *, e_uint32 port);
138
139/* Synthsize */
140EMU2413_API e_int16 OPLL_calc(OPLL *) ; ICODE_ATTR
141EMU2413_API void OPLL_calc_stereo(OPLL *, e_int32 out[2]) ; ICODE_ATTR
142EMU2413_API e_int16 *OPLL_update_buffer(OPLL *, e_uint32 length) ; ICODE_ATTR
143
144/* Misc */
145EMU2413_API void OPLL_setPatch(OPLL *, const e_uint8 *dump) ;
146EMU2413_API void OPLL_copyPatch(OPLL *, e_int32, OPLL_PATCH *) ;
147EMU2413_API void OPLL_forceRefresh(OPLL *) ;
148/* Utility */
149EMU2413_API void OPLL_dump2patch(const e_uint8 *dump, OPLL_PATCH *patch) ;
150EMU2413_API void OPLL_patch2dump(const OPLL_PATCH *patch, e_uint8 *dump) ;
151EMU2413_API void OPLL_getDefaultPatch(e_int32 type, e_int32 num, OPLL_PATCH *) ;
152
153/* Channel Mask */
154EMU2413_API e_uint32 OPLL_setMask(OPLL *, e_uint32 mask) ;
155EMU2413_API e_uint32 OPLL_toggleMask(OPLL *, e_uint32 mask) ;
156
157#define dump2patch OPLL_dump2patch
158
159#ifdef __cplusplus
160}
161#endif
162
163#endif
164
diff --git a/apps/codecs/libgme/emu8950.c b/apps/codecs/libgme/emu8950.c
new file mode 100644
index 0000000000..2198239004
--- /dev/null
+++ b/apps/codecs/libgme/emu8950.c
@@ -0,0 +1,1198 @@
1/*
2 * This file is based on:
3 * Y8950.cc -- Y8950 emulator from the openMSX team
4 * ported to c by gama
5 *
6 * The openMSX version is based on:
7 * emu8950.c -- Y8950 emulator written by Mitsutaka Okazaki 2001
8 * heavily rewritten to fit openMSX structure
9 */
10
11#include <math.h>
12#include "emu8950.h"
13
14#ifdef _MSC_VER
15#pragma warning( disable : 4355 )
16#endif
17
18#if !defined(ROCKBOX)
19 #define EMU8950_CALCUL_TABLES
20#else
21 #include "opltables.h"
22#endif
23
24// dB to Liner table
25static short dB2LinTab[(2*DB_MUTE)*2];
26// Dynamic range
27static unsigned int dphaseNoiseTable[1024][8];
28// LFO Table
29int pmtable[2][PM_PG_WIDTH];
30int amtable[2][AM_PG_WIDTH];
31
32/** WaveTable for each envelope amp. */
33static int sintable[PG_WIDTH];
34 /** Phase incr table for Attack. */
35static unsigned int dphaseARTable[16][16];
36/** Phase incr table for Decay and Release. */
37static unsigned int dphaseDRTable[16][16];
38/** KSL + TL Table. */
39static int tllTable[16][8][1<<TL_BITS][4];
40static int rksTable[2][8][2];
41/** Since we wont change clock rate in rockbox we can
42 skip this table */
43#if !defined(ROCKBOX)
44/** Phase incr table for PG. */
45static unsigned int dphaseTable[1024][8][16];
46#endif
47
48/** Liner to Log curve conversion table (for Attack rate). */
49static int AR_ADJUST_TABLE[1<<EG_BITS];
50
51//**************************************************//
52// //
53// Helper functions //
54// //
55//**************************************************//
56
57#define ALIGN(d, SS, SD) (d*(int)(SS/SD))
58
59inline static int DB_POS(int x)
60{
61 return (int)(x/DB_STEP);
62}
63
64inline static int DB_NEG(int x)
65{
66 return (int)(2*DB_MUTE+x/DB_STEP);
67}
68
69// Cut the lower b bits off
70inline static int HIGHBITS(int c, int b)
71{
72 return c >> b;
73}
74// Leave the lower b bits
75inline static int LOWBITS(int c, int b)
76{
77 return c & ((1<<b)-1);
78}
79// Expand x which is s bits to d bits
80inline static int EXPAND_BITS(int x, int s, int d)
81{
82 return x << (d-s);
83}
84
85//**************************************************//
86// //
87// Create tables //
88// //
89//**************************************************//
90
91// Table for AR to LogCurve.
92static void makeAdjustTable(void)
93{
94 AR_ADJUST_TABLE[0] = 1 << EG_BITS;
95 for (int i = 1; i < (1 << EG_BITS); i++)
96 #ifdef EMU8950_CALCUL_TABLES
97 AR_ADJUST_TABLE[i] = (int)((double)(1 << EG_BITS) - 1 -
98 (1 << EG_BITS) * log((double)i) / log((double)(1 << EG_BITS))) >> 1;
99 #else
100 AR_ADJUST_TABLE[i] = ar_adjust_coeff[i-1];
101 #endif
102}
103
104// Table for dB(0 -- (1<<DB_BITS)) to Liner(0 -- DB2LIN_AMP_WIDTH)
105static void makeDB2LinTable(void)
106{
107 int i;
108 for (i=0; i < 2*DB_MUTE; i++) {
109 dB2LinTab[i] = (i<DB_MUTE) ?
110 #ifdef EMU8950_CALCUL_TABLES
111 (int)((double)((1<<DB2LIN_AMP_BITS)-1)*pow((double)10,-(double)i*DB_STEP/20)) :
112 #else
113 db2lin_coeff[i] :
114 #endif
115 0;
116 dB2LinTab[i + 2*DB_MUTE] = -dB2LinTab[i];
117 }
118}
119
120// Sin Table
121static void makeSinTable(void)
122{
123 int i;
124 for (i=0; i < PG_WIDTH/4; i++)
125 #ifdef EMU8950_CALCUL_TABLES
126 sintable[i] = lin2db(sin(2.0*MPI*i/PG_WIDTH));
127 #else
128 sintable[i] = sin_coeff[i];
129 #endif
130 for (int i=0; i < PG_WIDTH/4; i++)
131 sintable[PG_WIDTH/2 - 1 - i] = sintable[i];
132 for (int i=0; i < PG_WIDTH/2; i++)
133 sintable[PG_WIDTH/2 + i] = 2*DB_MUTE + sintable[i];
134}
135
136void makeDphaseNoiseTable(int sampleRate, int clockRate)
137{
138 for (int i=0; i<1024; i++)
139 for (int j=0; j<8; j++)
140 dphaseNoiseTable[i][j] = rate_adjust(i<<j, sampleRate, clockRate);
141}
142
143// Table for Pitch Modulator
144void makePmTable(void)
145{
146 int i;
147 for (i=0; i < PM_PG_WIDTH; i++)
148 #ifdef EMU8950_CALCUL_TABLES
149 pmtable[0][i] = (int)((double)PM_AMP * pow(2.,(double)PM_DEPTH*sin(2.0*MPI*i/PM_PG_WIDTH)/1200));
150 #else
151 pmtable[0][i] = pm0_coeff[i];
152 #endif
153 for (i=0; i < PM_PG_WIDTH; i++)
154 #ifdef EMU8950_CALCUL_TABLES
155 pmtable[1][i] = (int)((double)PM_AMP * pow(2.,(double)PM_DEPTH2*sin(2.0*MPI*i/PM_PG_WIDTH)/1200));
156 #else
157 pmtable[1][i] = pm1_coeff[i];
158 #endif
159}
160
161// Table for Amp Modulator
162void makeAmTable(void)
163{
164 int i;
165 for (i=0; i<AM_PG_WIDTH; i++)
166 #ifdef EMU8950_CALCUL_TABLES
167 amtable[0][i] = (int)((double)AM_DEPTH/2/DB_STEP * (1.0 + sin(2.0*MPI*i/PM_PG_WIDTH)));
168 #else
169 amtable[0][i] = am0_coeff[i];
170 #endif
171 for (i=0; i<AM_PG_WIDTH; i++)
172 #ifdef EMU8950_CALCUL_TABLES
173 amtable[1][i] = (int)((double)AM_DEPTH2/2/DB_STEP * (1.0 + sin(2.0*MPI*i/PM_PG_WIDTH)));
174 #else
175 amtable[1][i] = am1_coeff[i];
176 #endif
177}
178
179#if !defined(ROCKBOX)
180// Phase increment counter table
181static void makeDphaseTable(int sampleRate, int clockRate)
182{
183 int mltable[16] = {
184 1,1*2,2*2,3*2,4*2,5*2,6*2,7*2,8*2,9*2,10*2,10*2,12*2,12*2,15*2,15*2
185 };
186
187 int fnum, block, ML;
188 for (fnum=0; fnum<1024; fnum++)
189 for (block=0; block<8; block++)
190 for (ML=0; ML<16; ML++)
191 dphaseTable[fnum][block][ML] =
192 rate_adjust((((fnum * mltable[ML]) << block) >> (21 - DP_BITS)), sampleRate, clockRate);
193}
194#endif
195
196static void makeTllTable(void)
197{
198 #define dB2(x) (int)((x)*2)
199 static int kltable[16] = {
200 dB2( 0.000),dB2( 9.000),dB2(12.000),dB2(13.875),
201 dB2(15.000),dB2(16.125),dB2(16.875),dB2(17.625),
202 dB2(18.000),dB2(18.750),dB2(19.125),dB2(19.500),
203 dB2(19.875),dB2(20.250),dB2(20.625),dB2(21.000)
204 };
205
206 int fnum, block, TL, KL;
207 for (fnum=0; fnum<16; fnum++)
208 for (block=0; block<8; block++)
209 for (TL=0; TL<64; TL++)
210 for (KL=0; KL<4; KL++) {
211 if (KL==0) {
212 tllTable[fnum][block][TL][KL] = ALIGN(TL, TL_STEP, EG_STEP);
213 } else {
214 int tmp = kltable[fnum] - dB2(3.000) * (7 - block);
215 if (tmp <= 0)
216 tllTable[fnum][block][TL][KL] = ALIGN(TL, TL_STEP, EG_STEP);
217 else
218 tllTable[fnum][block][TL][KL] = (int)((tmp>>(3-KL))/EG_STEP) + ALIGN(TL, TL_STEP, EG_STEP);
219 }
220 }
221}
222
223
224// Rate Table for Attack
225static void makeDphaseARTable(int sampleRate, int clockRate)
226{
227 int AR, Rks;
228 for (AR=0; AR<16; AR++)
229 for (Rks=0; Rks<16; Rks++) {
230 int RM = AR + (Rks>>2);
231 int RL = Rks&3;
232 if (RM>15) RM=15;
233 switch (AR) {
234 case 0:
235 dphaseARTable[AR][Rks] = 0;
236 break;
237 case 15:
238 dphaseARTable[AR][Rks] = EG_DP_WIDTH;
239 break;
240 default:
241 dphaseARTable[AR][Rks] = rate_adjust((3*(RL+4) << (RM+1)), sampleRate, clockRate);
242 break;
243 }
244 }
245}
246
247// Rate Table for Decay
248static void makeDphaseDRTable(int sampleRate, int clockRate)
249{
250 int DR, Rks;
251 for (DR=0; DR<16; DR++)
252 for (Rks=0; Rks<16; Rks++) {
253 int RM = DR + (Rks>>2);
254 int RL = Rks&3;
255 if (RM>15) RM=15;
256 switch (DR) {
257 case 0:
258 dphaseDRTable[DR][Rks] = 0;
259 break;
260 default:
261 dphaseDRTable[DR][Rks] = rate_adjust((RL+4) << (RM-1), sampleRate, clockRate);
262 break;
263 }
264 }
265}
266
267static void makeRksTable(void)
268{
269 int fnum9, block, KR;
270 for (fnum9=0; fnum9<2; fnum9++)
271 for (block=0; block<8; block++)
272 for (KR=0; KR<2; KR++) {
273 rksTable[fnum9][block][KR] = (KR != 0) ?
274 (block<<1) + fnum9:
275 block>>1;
276 }
277}
278
279//**********************************************************//
280// //
281// Patch //
282// //
283//**********************************************************//
284
285
286void patchReset(struct Patch* patch)
287{
288 patch->AM = patch->PM = patch->EG = false;
289 patch->KR = patch->ML = patch->KL = patch->TL =
290 patch->FB = patch->AR = patch->DR = patch->SL = patch->RR = 0;
291}
292
293
294//**********************************************************//
295// //
296// Slot //
297// //
298//**********************************************************//
299
300
301static inline void slotUpdatePG(struct Slot* slot)
302{
303#if defined(ROCKBOX)
304 static const int mltable[16] = {
305 1,1*2,2*2,3*2,4*2,5*2,6*2,7*2,8*2,9*2,10*2,10*2,12*2,12*2,15*2,15*2
306 };
307
308 slot->dphase = ((slot->fnum * mltable[slot->patch.ML]) << slot->block) >> (21 - DP_BITS);
309#else
310 slot->dphase = dphaseTable[slot->fnum][slot->block][slot->patch.ML];
311#endif
312}
313
314static inline void slotUpdateTLL(struct Slot* slot)
315{
316 slot->tll = tllTable[slot->fnum>>6][slot->block][slot->patch.TL][slot->patch.KL];
317}
318
319static inline void slotUpdateRKS(struct Slot* slot)
320{
321 slot->rks = rksTable[slot->fnum>>9][slot->block][slot->patch.KR];
322}
323
324static inline void slotUpdateEG(struct Slot* slot)
325{
326 switch (slot->eg_mode) {
327 case ATTACK:
328 slot->eg_dphase = dphaseARTable[slot->patch.AR][slot->rks];
329 break;
330 case DECAY:
331 slot->eg_dphase = dphaseDRTable[slot->patch.DR][slot->rks];
332 break;
333 case SUSTINE:
334 slot->eg_dphase = dphaseDRTable[slot->patch.RR][slot->rks];
335 break;
336 case RELEASE:
337 slot->eg_dphase = slot->patch.EG ?
338 dphaseDRTable[slot->patch.RR][slot->rks]:
339 dphaseDRTable[7] [slot->rks];
340 break;
341 case SUSHOLD:
342 case FINISH:
343 slot->eg_dphase = 0;
344 break;
345 }
346}
347
348static inline void slotUpdateAll(struct Slot* slot)
349{
350 slotUpdatePG(slot);
351 slotUpdateTLL(slot);
352 slotUpdateRKS(slot);
353 slotUpdateEG(slot); // EG should be last
354}
355
356void slotReset(struct Slot* slot)
357{
358 slot->phase = 0;
359 slot->dphase = 0;
360 slot->output[0] = 0;
361 slot->output[1] = 0;
362 slot->feedback = 0;
363 slot->eg_mode = FINISH;
364 slot->eg_phase = EG_DP_WIDTH;
365 slot->eg_dphase = 0;
366 slot->rks = 0;
367 slot->tll = 0;
368 slot->fnum = 0;
369 slot->block = 0;
370 slot->pgout = 0;
371 slot->egout = 0;
372 slot->slotStatus = false;
373 patchReset(&slot->patch);
374 slotUpdateAll(slot);
375}
376
377// Slot key on
378static inline void slotOn(struct Slot* slot)
379{
380 if (!slot->slotStatus) {
381 slot->slotStatus = true;
382 slot->eg_mode = ATTACK;
383 slot->phase = 0;
384 slot->eg_phase = 0;
385 }
386}
387
388// Slot key off
389static inline void slotOff(struct Slot* slot)
390{
391 if (slot->slotStatus) {
392 slot->slotStatus = false;
393 if (slot->eg_mode == ATTACK)
394 slot->eg_phase = EXPAND_BITS(AR_ADJUST_TABLE[HIGHBITS(slot->eg_phase, EG_DP_BITS-EG_BITS)], EG_BITS, EG_DP_BITS);
395 slot->eg_mode = RELEASE;
396 }
397}
398
399
400//**********************************************************//
401// //
402// OPLChannel //
403// //
404//**********************************************************//
405
406
407void channelReset(struct OPLChannel* ch)
408{
409 slotReset(&ch->mod);
410 slotReset(&ch->car);
411 ch->alg = false;
412}
413
414// Set F-Number ( fnum : 10bit )
415static void channelSetFnumber(struct OPLChannel* ch, int fnum)
416{
417 ch->car.fnum = fnum;
418 ch->mod.fnum = fnum;
419}
420
421// Set Block data (block : 3bit )
422static void channelSetBlock(struct OPLChannel* ch, int block)
423{
424 ch->car.block = block;
425 ch->mod.block = block;
426}
427
428// OPLChannel key on
429static void keyOn(struct OPLChannel* ch)
430{
431 slotOn(&ch->mod);
432 slotOn(&ch->car);
433}
434
435// OPLChannel key off
436static void keyOff(struct OPLChannel* ch)
437{
438 slotOff(&ch->mod);
439 slotOff(&ch->car);
440}
441
442
443//**********************************************************//
444// //
445// Y8950 //
446// //
447//**********************************************************//
448
449void OPL_init(struct Y8950* this, byte* ramBank, int sampleRam)
450{
451 this->clockRate = CLK_FREQ;
452
453 ADPCM_init(&this->adpcm, this, ramBank, sampleRam);
454
455 makePmTable();
456 makeAmTable();
457
458 makeAdjustTable();
459 makeDB2LinTable();
460 makeTllTable();
461 makeRksTable();
462 makeSinTable();
463
464 int i;
465 for (i=0; i<9; i++) {
466 // TODO cleanup
467 this->slot[i*2+0] = &(this->ch[i].mod);
468 this->slot[i*2+1] = &(this->ch[i].car);
469 this->ch[i].mod.plfo_am = &this->lfo_am;
470 this->ch[i].mod.plfo_pm = &this->lfo_pm;
471 this->ch[i].car.plfo_am = &this->lfo_am;
472 this->ch[i].car.plfo_pm = &this->lfo_pm;
473 }
474
475 OPL_reset(this);
476}
477
478void OPL_setSampleRate(struct Y8950* this, int sampleRate, int clockRate)
479{
480 this->clockRate = clockRate;
481 ADPCM_setSampleRate(&this->adpcm, sampleRate, clockRate);
482
483#if !defined(ROCKBOX)
484 makeDphaseTable(sampleRate, clockRate);
485#endif
486 makeDphaseARTable(sampleRate, clockRate);
487 makeDphaseDRTable(sampleRate, clockRate);
488 makeDphaseNoiseTable(sampleRate, clockRate);
489 this->pm_dphase = rate_adjust(PM_SPEED * PM_DP_WIDTH / (clockRate/72), sampleRate, clockRate);
490 this->am_dphase = rate_adjust(AM_SPEED * AM_DP_WIDTH / (clockRate/72), sampleRate, clockRate);
491}
492
493// Reset whole of opl except patch datas.
494void OPL_reset(struct Y8950* this)
495{
496 int i;
497 for (i=0; i<9; i++)
498 channelReset(&this->ch[i]);
499 this->output[0] = 0;
500 this->output[1] = 0;
501
502
503 this->dacSampleVolume = 0;
504 this->dacOldSampleVolume = 0;
505 this->dacSampleVolumeSum = 0;
506 this->dacCtrlVolume = 0;
507 this->dacDaVolume = 0;
508 this->dacEnabled = 0;
509
510 this->rythm_mode = false;
511 this->am_mode = 0;
512 this->pm_mode = 0;
513 this->pm_phase = 0;
514 this->am_phase = 0;
515 this->noise_seed = 0xffff;
516 this->noiseA = 0;
517 this->noiseB = 0;
518 this->noiseA_phase = 0;
519 this->noiseB_phase = 0;
520 this->noiseA_dphase = 0;
521 this->noiseB_dphase = 0;
522
523 for (i = 0; i < 0x100; ++i)
524 this->reg[i] = 0x00;
525
526 this->reg[0x04] = 0x18;
527 this->reg[0x19] = 0x0F; // fixes 'Thunderbirds are Go'
528 this->status = 0x00;
529 this->statusMask = 0;
530 /* irq.reset(); */
531
532 ADPCM_reset(&this->adpcm);
533 OPL_setInternalMute(this, true); // muted
534}
535
536
537// Drum key on
538static inline void keyOn_BD(struct Y8950* this) { keyOn(&this->ch[6]); }
539static inline void keyOn_HH(struct Y8950* this) { slotOn(&this->ch[7].mod); }
540static inline void keyOn_SD(struct Y8950* this) { slotOn(&this->ch[7].car); }
541static inline void keyOn_TOM(struct Y8950* this) { slotOn(&this->ch[8].mod); }
542static inline void keyOn_CYM(struct Y8950* this) { slotOn(&this->ch[8].car); }
543
544// Drum key off
545static inline void keyOff_BD(struct Y8950* this) { keyOff(&this->ch[6]); }
546static inline void keyOff_HH(struct Y8950* this) { slotOff(&this->ch[7].mod); }
547static inline void keyOff_SD(struct Y8950* this) { slotOff(&this->ch[7].car); }
548static inline void keyOff_TOM(struct Y8950* this){ slotOff(&this->ch[8].mod); }
549static inline void keyOff_CYM(struct Y8950* this){ slotOff(&this->ch[8].car); }
550
551// Change Rhythm Mode
552inline void setRythmMode(struct Y8950* this, int data)
553{
554 bool newMode = (data & 32) != 0;
555 if (this->rythm_mode != newMode) {
556 this->rythm_mode = newMode;
557 if (!this->rythm_mode) {
558 // ON->OFF
559 this->ch[6].mod.eg_mode = FINISH; // BD1
560 this->ch[6].mod.slotStatus = false;
561 this->ch[6].car.eg_mode = FINISH; // BD2
562 this->ch[6].car.slotStatus = false;
563 this->ch[7].mod.eg_mode = FINISH; // HH
564 this->ch[7].mod.slotStatus = false;
565 this->ch[7].car.eg_mode = FINISH; // SD
566 this->ch[7].car.slotStatus = false;
567 this->ch[8].mod.eg_mode = FINISH; // TOM
568 this->ch[8].mod.slotStatus = false;
569 this->ch[8].car.eg_mode = FINISH; // CYM
570 this->ch[8].car.slotStatus = false;
571 }
572 }
573}
574
575//********************************************************//
576// //
577// Generate wave data //
578// //
579//********************************************************//
580
581// Convert Amp(0 to EG_HEIGHT) to Phase(0 to 4PI).
582inline static int wave2_4pi(int e)
583{
584 int shift = SLOT_AMP_BITS - PG_BITS - 1;
585 if (shift > 0)
586 return e >> shift;
587 else
588 return e << -shift;
589}
590
591// Convert Amp(0 to EG_HEIGHT) to Phase(0 to 8PI).
592inline static int wave2_8pi(int e)
593{
594 int shift = SLOT_AMP_BITS - PG_BITS - 2;
595 if (shift > 0)
596 return e >> shift;
597 else
598 return e << -shift;
599}
600
601static inline void update_noise(struct Y8950* this)
602{
603 if (this->noise_seed & 1)
604 this->noise_seed ^= 0x24000;
605 this->noise_seed >>= 1;
606 this->whitenoise = this->noise_seed&1 ? DB_POS(6) : DB_NEG(6);
607
608 this->noiseA_phase += this->noiseA_dphase;
609 this->noiseB_phase += this->noiseB_dphase;
610
611 this->noiseA_phase &= (0x40<<11) - 1;
612 if ((this->noiseA_phase>>11)==0x3f)
613 this->noiseA_phase = 0;
614 this->noiseA = this->noiseA_phase&(0x03<<11)?DB_POS(6):DB_NEG(6);
615
616 this->noiseB_phase &= (0x10<<11) - 1;
617 this->noiseB = this->noiseB_phase&(0x0A<<11)?DB_POS(6):DB_NEG(6);
618}
619
620static inline void update_ampm(struct Y8950* this)
621{
622 this->pm_phase = (this->pm_phase + this->pm_dphase)&(PM_DP_WIDTH - 1);
623 this->am_phase = (this->am_phase + this->am_dphase)&(AM_DP_WIDTH - 1);
624 this->lfo_am = amtable[this->am_mode][HIGHBITS(this->am_phase, AM_DP_BITS - AM_PG_BITS)];
625 this->lfo_pm = pmtable[this->pm_mode][HIGHBITS(this->pm_phase, PM_DP_BITS - PM_PG_BITS)];
626}
627
628static inline void calc_phase(struct Slot* slot)
629{
630 if (slot->patch.PM)
631 slot->phase += (slot->dphase * (*slot->plfo_pm)) >> PM_AMP_BITS;
632 else
633 slot->phase += slot->dphase;
634 slot->phase &= (DP_WIDTH - 1);
635 slot->pgout = HIGHBITS(slot->phase, DP_BASE_BITS);
636}
637
638static inline void calc_envelope(struct Slot* slot)
639{
640 #define S2E(x) (ALIGN((unsigned int)(x/SL_STEP),SL_STEP,EG_STEP)<<(EG_DP_BITS-EG_BITS))
641 static unsigned int SL[16] = {
642 S2E( 0), S2E( 3), S2E( 6), S2E( 9), S2E(12), S2E(15), S2E(18), S2E(21),
643 S2E(24), S2E(27), S2E(30), S2E(33), S2E(36), S2E(39), S2E(42), S2E(93)
644 };
645
646 switch (slot->eg_mode) {
647 case ATTACK:
648 slot->eg_phase += slot->eg_dphase;
649 if (EG_DP_WIDTH & slot->eg_phase) {
650 slot->egout = 0;
651 slot->eg_phase= 0;
652 slot->eg_mode = DECAY;
653 slotUpdateEG(slot);
654 } else {
655 slot->egout = AR_ADJUST_TABLE[HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS)];
656 }
657 break;
658
659 case DECAY:
660 slot->eg_phase += slot->eg_dphase;
661 slot->egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS);
662 if (slot->eg_phase >= SL[slot->patch.SL]) {
663 if (slot->patch.EG) {
664 slot->eg_phase = SL[slot->patch.SL];
665 slot->eg_mode = SUSHOLD;
666 slotUpdateEG(slot);
667 } else {
668 slot->eg_phase = SL[slot->patch.SL];
669 slot->eg_mode = SUSTINE;
670 slotUpdateEG(slot);
671 }
672 slot->egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS);
673 }
674 break;
675
676 case SUSHOLD:
677 slot->egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS);
678 if (!slot->patch.EG) {
679 slot->eg_mode = SUSTINE;
680 slotUpdateEG(slot);
681 }
682 break;
683
684 case SUSTINE:
685 case RELEASE:
686 slot->eg_phase += slot->eg_dphase;
687 slot->egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS);
688 if (slot->egout >= (1<<EG_BITS)) {
689 slot->eg_mode = FINISH;
690 slot->egout = (1<<EG_BITS) - 1;
691 }
692 break;
693
694 case FINISH:
695 slot->egout = (1<<EG_BITS) - 1;
696 break;
697 }
698
699 if (slot->patch.AM)
700 slot->egout = ALIGN(slot->egout+slot->tll,EG_STEP,DB_STEP) + (*slot->plfo_am);
701 else
702 slot->egout = ALIGN(slot->egout+slot->tll,EG_STEP,DB_STEP);
703 if (slot->egout >= DB_MUTE)
704 slot->egout = DB_MUTE-1;
705}
706
707inline static int calc_slot_car(struct Slot* slot, int fm)
708{
709 calc_envelope(slot);
710 calc_phase(slot);
711 if (slot->egout>=(DB_MUTE-1))
712 return 0;
713 return dB2LinTab[sintable[(slot->pgout+wave2_8pi(fm))&(PG_WIDTH-1)] + slot->egout];
714}
715
716inline static int calc_slot_mod(struct Slot* slot)
717{
718 slot->output[1] = slot->output[0];
719 calc_envelope(slot);
720 calc_phase(slot);
721
722 if (slot->egout>=(DB_MUTE-1)) {
723 slot->output[0] = 0;
724 } else if (slot->patch.FB!=0) {
725 int fm = wave2_4pi(slot->feedback) >> (7-slot->patch.FB);
726 slot->output[0] = dB2LinTab[sintable[(slot->pgout+fm)&(PG_WIDTH-1)] + slot->egout];
727 } else
728 slot->output[0] = dB2LinTab[sintable[slot->pgout] + slot->egout];
729
730 slot->feedback = (slot->output[1] + slot->output[0])>>1;
731 return slot->feedback;
732}
733
734// TOM
735inline static int calc_slot_tom(struct Slot* slot)
736{
737 calc_envelope(slot);
738 calc_phase(slot);
739 if (slot->egout>=(DB_MUTE-1))
740 return 0;
741 return dB2LinTab[sintable[slot->pgout] + slot->egout];
742}
743
744// SNARE
745inline static int calc_slot_snare(struct Slot* slot, int whitenoise)
746{
747 calc_envelope(slot);
748 calc_phase(slot);
749 if (slot->egout>=(DB_MUTE-1))
750 return 0;
751 if (slot->pgout & (1<<(PG_BITS-1))) {
752 return (dB2LinTab[slot->egout] + dB2LinTab[slot->egout+whitenoise]) >> 1;
753 } else {
754 return (dB2LinTab[2*DB_MUTE + slot->egout] + dB2LinTab[slot->egout+whitenoise]) >> 1;
755 }
756}
757
758// TOP-CYM
759inline static int calc_slot_cym(struct Slot* slot, int a, int b)
760{
761 calc_envelope(slot);
762 if (slot->egout>=(DB_MUTE-1)) {
763 return 0;
764 } else {
765 return (dB2LinTab[slot->egout+a] + dB2LinTab[slot->egout+b]) >> 1;
766 }
767}
768
769// HI-HAT
770inline static int calc_slot_hat(struct Slot* slot, int a, int b, int whitenoise)
771{
772 calc_envelope(slot);
773 if (slot->egout>=(DB_MUTE-1)) {
774 return 0;
775 } else {
776 return (dB2LinTab[slot->egout+whitenoise] + dB2LinTab[slot->egout+a] + dB2LinTab[slot->egout+b]) >>2;
777 }
778}
779
780
781static inline int calcSample(struct Y8950* this, int channelMask)
782{
783 // while muted update_ampm() and update_noise() aren't called, probably ok
784 update_ampm(this);
785 update_noise(this);
786
787 int mix = 0;
788
789 if (this->rythm_mode) {
790 // TODO wasn't in original source either
791 calc_phase(&this->ch[7].mod);
792 calc_phase(&this->ch[8].car);
793
794 if (channelMask & (1 << 6))
795 mix += calc_slot_car(&this->ch[6].car, calc_slot_mod(&this->ch[6].mod));
796 if (this->ch[7].mod.eg_mode != FINISH)
797 mix += calc_slot_hat(&this->ch[7].mod, this->noiseA, this->noiseB, this->whitenoise);
798 if (channelMask & (1 << 7))
799 mix += calc_slot_snare(&this->ch[7].car, this->whitenoise);
800 if (this->ch[8].mod.eg_mode != FINISH)
801 mix += calc_slot_tom(&this->ch[8].mod);
802 if (channelMask & (1 << 8))
803 mix += calc_slot_cym(&this->ch[8].car, this->noiseA, this->noiseB);
804
805 channelMask &= (1<< 6) - 1;
806 mix *= 2;
807 }
808 struct OPLChannel *cp;
809 for (cp = this->ch; channelMask; channelMask >>=1, cp++) {
810 if (channelMask & 1) {
811 if (cp->alg)
812 mix += calc_slot_car(&cp->car, 0) +
813 calc_slot_mod(&cp->mod);
814 else
815 mix += calc_slot_car(&cp->car,
816 calc_slot_mod(&cp->mod));
817 }
818 }
819
820 mix += ADPCM_calcSample(&this->adpcm);
821
822 return (mix*this->maxVolume) >> (DB2LIN_AMP_BITS - 1);
823}
824
825bool checkMuteHelper(struct Y8950* this)
826{
827 int i;
828 struct OPLChannel *ch = this->ch;
829 for (i = 0; i < 6; i++) {
830 if (ch[i].car.eg_mode != FINISH) return false;
831 }
832 if (!this->rythm_mode) {
833 for(i = 6; i < 9; i++) {
834 if (ch[i].car.eg_mode != FINISH) return false;
835 }
836 } else {
837 if (ch[6].car.eg_mode != FINISH) return false;
838 if (ch[7].mod.eg_mode != FINISH) return false;
839 if (ch[7].car.eg_mode != FINISH) return false;
840 if (ch[8].mod.eg_mode != FINISH) return false;
841 if (ch[8].car.eg_mode != FINISH) return false;
842 }
843
844 return ADPCM_muted(&this->adpcm);
845}
846
847void checkMute(struct Y8950* this)
848{
849 bool mute = checkMuteHelper(this);
850 //PRT_DEBUG("Y8950: muted " << mute);
851 OPL_setInternalMute(this, mute);
852}
853
854int* OPL_updateBuffer(struct Y8950* this, int length)
855{
856 //PRT_DEBUG("Y8950: update buffer");
857
858 if (OPL_isInternalMuted(this) && !this->dacEnabled) {
859 return 0;
860 }
861
862 this->dacCtrlVolume = this->dacSampleVolume - this->dacOldSampleVolume + 0x3fe7 * this->dacCtrlVolume / 0x4000;
863 this->dacOldSampleVolume = this->dacSampleVolume;
864
865 int channelMask = 0, i;
866 struct OPLChannel *ch = this->ch;
867 for (i = 9; i--; ) {
868 channelMask <<= 1;
869 if (ch[i].car.eg_mode != FINISH) channelMask |= 1;
870 }
871
872 int* buf = this->buffer;
873 while (length--) {
874 int sample = calcSample(this, channelMask);
875
876 this->dacCtrlVolume = 0x3fe7 * this->dacCtrlVolume / 0x4000;
877 this->dacDaVolume += 2 * (this->dacCtrlVolume - this->dacDaVolume) / 3;
878 sample += 48 * this->dacDaVolume;
879 *(buf++) = sample;
880 }
881
882 this->dacEnabled = this->dacDaVolume;
883
884 checkMute(this);
885 return this->buffer;
886}
887
888void OPL_setInternalVolume(struct Y8950* this, short newVolume)
889{
890 this->maxVolume = newVolume;
891}
892
893//**************************************************//
894// //
895// I/O Ctrl //
896// //
897//**************************************************//
898
899void OPL_writeReg(struct Y8950* this, byte rg, byte data)
900{
901 //PRT_DEBUG("Y8950 write " << (int)rg << " " << (int)data);
902 int stbl[32] = {
903 0, 2, 4, 1, 3, 5,-1,-1,
904 6, 8,10, 7, 9,11,-1,-1,
905 12,14,16,13,15,17,-1,-1,
906 -1,-1,-1,-1,-1,-1,-1,-1
907 };
908
909 //TODO only for registers that influence sound
910 //TODO also ADPCM
911
912 switch (rg & 0xe0) {
913 case 0x00: {
914 switch (rg) {
915 case 0x01: // TEST
916 // TODO
917 // Y8950 MSX-AUDIO Test register $01 (write only)
918 //
919 // Bit Description
920 //
921 // 7 Reset LFOs - seems to force the LFOs to their initial values (eg.
922 // maximum amplitude, zero phase deviation)
923 //
924 // 6 something to do with ADPCM - bit 0 of the status register is
925 // affected by setting this bit (PCM BSY)
926 //
927 // 5 No effect? - Waveform select enable in YM3812 OPL2 so seems
928 // reasonable that this bit wouldn't have been used in OPL
929 //
930 // 4 No effect?
931 //
932 // 3 Faster LFOs - increases the frequencies of the LFOs and (maybe)
933 // the timers (cf. YM2151 test register)
934 //
935 // 2 Reset phase generators - No phase generator output, but envelope
936 // generators still work (can hear a transient when they are gated)
937 //
938 // 1 No effect?
939 //
940 // 0 Reset envelopes - Envelope generator outputs forced to maximum,
941 // so all enabled voices sound at maximum
942 this->reg[rg] = data;
943 break;
944
945 case 0x02: // TIMER1 (reso. 80us)
946 this->reg[rg] = data;
947 break;
948
949 case 0x03: // TIMER2 (reso. 320us)
950 this->reg[rg] = data;
951 break;
952
953 case 0x04: // FLAG CONTROL
954 if (data & R04_IRQ_RESET) {
955 OPL_resetStatus(this, 0x78); // reset all flags
956 } else {
957 OPL_changeStatusMask(this, (~data) & 0x78);
958 this->reg[rg] = data;
959 }
960 break;
961
962 case 0x06: // (KEYBOARD OUT)
963 this->reg[rg] = data;
964 break;
965
966 case 0x07: // START/REC/MEM DATA/REPEAT/SP-OFF/-/-/RESET
967 case 0x08: // CSM/KEY BOARD SPLIT/-/-/SAMPLE/DA AD/64K/ROM
968 case 0x09: // START ADDRESS (L)
969 case 0x0A: // START ADDRESS (H)
970 case 0x0B: // STOP ADDRESS (L)
971 case 0x0C: // STOP ADDRESS (H)
972 case 0x0D: // PRESCALE (L)
973 case 0x0E: // PRESCALE (H)
974 case 0x0F: // ADPCM-DATA
975 case 0x10: // DELTA-N (L)
976 case 0x11: // DELTA-N (H)
977 case 0x12: // ENVELOP CONTROL
978 case 0x1A: // PCM-DATA
979 this->reg[rg] = data;
980 ADPCM_writeReg(&this->adpcm, rg, data);
981 break;
982
983 case 0x15: // DAC-DATA (bit9-2)
984 this->reg[rg] = data;
985 if (this->reg[0x08] & 0x04) {
986 static int damp[] = { 256, 279, 304, 332, 362, 395, 431, 470 };
987 int sample = (short)(256 * this->reg[0x15] + this->reg[0x16]) * 128 / damp[this->reg[0x17]];
988 this->dacSampleVolume = sample;
989 this->dacEnabled = 1;
990 }
991 break;
992 case 0x16: // (bit1-0)
993 this->reg[rg] = data & 0xC0;
994 break;
995 case 0x17: // (exponent)
996 this->reg[rg] = data & 0x07;
997 break;
998
999 case 0x18: // I/O-CONTROL (bit3-0)
1000 // TODO
1001 // 0 -> input
1002 // 1 -> output
1003 this->reg[rg] = data;
1004 break;
1005
1006 case 0x19: // I/O-DATA (bit3-0)
1007 // TODO
1008 this->reg[rg] = data;
1009 break;
1010 }
1011
1012 break;
1013 }
1014 case 0x20: {
1015 int s = stbl[rg&0x1f];
1016 if (s >= 0) {
1017 this->slot[s]->patch.AM = (data>>7)&1;
1018 this->slot[s]->patch.PM = (data>>6)&1;
1019 this->slot[s]->patch.EG = (data>>5)&1;
1020 this->slot[s]->patch.KR = (data>>4)&1;
1021 this->slot[s]->patch.ML = (data)&15;
1022 slotUpdateAll(this->slot[s]);
1023 }
1024 this->reg[rg] = data;
1025 break;
1026 }
1027 case 0x40: {
1028 int s = stbl[rg&0x1f];
1029 if (s >= 0) {
1030 this->slot[s]->patch.KL = (data>>6)&3;
1031 this->slot[s]->patch.TL = (data)&63;
1032 slotUpdateAll(this->slot[s]);
1033 }
1034 this->reg[rg] = data;
1035 break;
1036 }
1037 case 0x60: {
1038 int s = stbl[rg&0x1f];
1039 if (s >= 0) {
1040 this->slot[s]->patch.AR = (data>>4)&15;
1041 this->slot[s]->patch.DR = (data)&15;
1042 slotUpdateEG(this->slot[s]);
1043 }
1044 this->reg[rg] = data;
1045 break;
1046 }
1047 case 0x80: {
1048 int s = stbl[rg&0x1f];
1049 if (s >= 0) {
1050 this->slot[s]->patch.SL = (data>>4)&15;
1051 this->slot[s]->patch.RR = (data)&15;
1052 slotUpdateEG(this->slot[s]);
1053 }
1054 this->reg[rg] = data;
1055 break;
1056 }
1057 case 0xa0: {
1058 if (rg==0xbd) {
1059 this->am_mode = (data>>7)&1;
1060 this->pm_mode = (data>>6)&1;
1061
1062 setRythmMode(this, data);
1063 if (this->rythm_mode) {
1064 if (data&0x10) keyOn_BD(this); else keyOff_BD(this);
1065 if (data&0x08) keyOn_SD(this); else keyOff_SD(this);
1066 if (data&0x04) keyOn_TOM(this); else keyOff_TOM(this);
1067 if (data&0x02) keyOn_CYM(this); else keyOff_CYM(this);
1068 if (data&0x01) keyOn_HH(this); else keyOff_HH(this);
1069 }
1070 slotUpdateAll(&this->ch[6].mod);
1071 slotUpdateAll(&this->ch[6].car);
1072 slotUpdateAll(&this->ch[7].mod);
1073 slotUpdateAll(&this->ch[7].car);
1074 slotUpdateAll(&this->ch[8].mod);
1075 slotUpdateAll(&this->ch[8].car);
1076
1077 this->reg[rg] = data;
1078 break;
1079 }
1080 if ((rg&0xf) > 8) {
1081 // 0xa9-0xaf 0xb9-0xbf
1082 break;
1083 }
1084 if (!(rg&0x10)) {
1085 // 0xa0-0xa8
1086 int c = rg-0xa0;
1087 int fNum = data + ((this->reg[rg+0x10]&3)<<8);
1088 int block = (this->reg[rg+0x10]>>2)&7;
1089 channelSetFnumber(&this->ch[c], fNum);
1090 switch (c) {
1091 case 7: this->noiseA_dphase = dphaseNoiseTable[fNum][block];
1092 break;
1093 case 8: this->noiseB_dphase = dphaseNoiseTable[fNum][block];
1094 break;
1095 }
1096 slotUpdateAll(&this->ch[c].car);
1097 slotUpdateAll(&this->ch[c].mod);
1098 this->reg[rg] = data;
1099 } else {
1100 // 0xb0-0xb8
1101 int c = rg-0xb0;
1102 int fNum = ((data&3)<<8) + this->reg[rg-0x10];
1103 int block = (data>>2)&7;
1104 channelSetFnumber(&this->ch[c], fNum);
1105 channelSetBlock(&this->ch[c], block);
1106 switch (c) {
1107 case 7: this->noiseA_dphase = dphaseNoiseTable[fNum][block];
1108 break;
1109 case 8: this->noiseB_dphase = dphaseNoiseTable[fNum][block];
1110 break;
1111 }
1112 if (data&0x20)
1113 keyOn(&this->ch[c]);
1114 else
1115 keyOff(&this->ch[c]);
1116 slotUpdateAll(&this->ch[c].mod);
1117 slotUpdateAll(&this->ch[c].car);
1118 this->reg[rg] = data;
1119 }
1120 break;
1121 }
1122 case 0xc0: {
1123 if (rg > 0xc8)
1124 break;
1125 int c = rg-0xC0;
1126 this->slot[c*2]->patch.FB = (data>>1)&7;
1127 this->ch[c].alg = data&1;
1128 this->reg[rg] = data;
1129 }
1130 }
1131
1132 //TODO only for registers that influence sound
1133 checkMute(this);
1134}
1135
1136byte OPL_readReg(struct Y8950* this, byte rg)
1137{
1138 byte result;
1139 switch (rg) {
1140 case 0x05: // (KEYBOARD IN)
1141 result = 0xff;
1142 break;
1143
1144 case 0x0f: // ADPCM-DATA
1145 case 0x13: // ???
1146 case 0x14: // ???
1147 case 0x1a: // PCM-DATA
1148 result = ADPCM_readReg(&this->adpcm, rg);
1149 break;
1150
1151 case 0x19: // I/O DATA TODO
1152 /* result = ~(switchGetAudio() ? 0 : 0x04); */
1153 result = 0;
1154 break;
1155 default:
1156 result = 255;
1157 }
1158 //PRT_DEBUG("Y8950 read " << (int)rg<<" "<<(int)result);
1159 return result;
1160}
1161
1162byte OPL_readStatus(struct Y8950* this)
1163{
1164 OPL_setStatus(this, STATUS_BUF_RDY); // temp hack
1165 byte tmp = this->status & (0x80 | this->statusMask);
1166 //PRT_DEBUG("Y8950 read status " << (int)tmp);
1167 return tmp | 0x06; // bit 1 and 2 are always 1
1168}
1169
1170
1171void OPL_setStatus(struct Y8950* this, byte flags)
1172{
1173 this->status |= flags;
1174 if (this->status & this->statusMask) {
1175 this->status |= 0x80;
1176 /* irq.set(); */
1177 }
1178}
1179void OPL_resetStatus(struct Y8950* this, byte flags)
1180{
1181 this->status &= ~flags;
1182 if (!(this->status & this->statusMask)) {
1183 this->status &= 0x7f;
1184 /* irq.reset(); */
1185 }
1186}
1187void OPL_changeStatusMask(struct Y8950* this, byte newMask)
1188{
1189 this->statusMask = newMask;
1190 this->status &= this->statusMask;
1191 if (this->status) {
1192 this->status |= 0x80;
1193 /* irq.set(); */
1194 } else {
1195 this->status &= 0x7f;
1196 /* irq.reset(); */
1197 }
1198}
diff --git a/apps/codecs/libgme/emu8950.h b/apps/codecs/libgme/emu8950.h
new file mode 100644
index 0000000000..88d17b956e
--- /dev/null
+++ b/apps/codecs/libgme/emu8950.h
@@ -0,0 +1,248 @@
1#ifndef __Y8950_HH__
2#define __Y8950_HH__
3
4#include "blargg_common.h"
5#include "emuadpcm.h"
6
7#define AUDIO_MONO_BUFFER_SIZE 1024
8
9// Dynamic range of envelope
10static const double EG_STEP = 0.1875;
11#define EG_BITS 9
12#define EG_MUTE (1<<EG_BITS)
13// Dynamic range of sustine level
14static const double SL_STEP = 3.0;
15static const int SL_BITS = 4;
16#define SL_MUTE (1<<SL_BITS)
17// Size of Sintable ( 1 -- 18 can be used, but 7 -- 14 recommended.)
18#define PG_BITS 10
19#define PG_WIDTH (1<<PG_BITS)
20// Phase increment counter
21static const int DP_BITS = 19;
22#define DP_WIDTH (1<<DP_BITS)
23#define DP_BASE_BITS (DP_BITS - PG_BITS)
24// Bits for envelope phase incremental counter
25static const int EG_DP_BITS = 23;
26#define EG_DP_WIDTH (1<<EG_DP_BITS)
27// Dynamic range of total level
28static const double TL_STEP = 0.75;
29#define TL_BITS 6
30#define TL_MUTE (1<<TL_BITS)
31
32static const double DB_STEP = 0.1875;
33#define DB_BITS 9
34#define DB_MUTE (1<<DB_BITS)
35// PM table is calcurated by PM_AMP * pow(2,PM_DEPTH*sin(x)/1200)
36static const int PM_AMP_BITS = 8;
37#define PM_AMP (1<<PM_AMP_BITS)
38
39
40
41static const int CLK_FREQ = 3579545;
42static const double MPI = 3.14159265358979;
43// PM speed(Hz) and depth(cent)
44static const double PM_SPEED = 6.4;
45static const double PM_DEPTH = (13.75/2);
46static const double PM_DEPTH2 = 13.75;
47// AM speed(Hz) and depth(dB)
48static const double AM_SPEED = 3.7;
49static const double AM_DEPTH = 1.0;
50static const double AM_DEPTH2 = 4.8;
51// Bits for liner value
52static const int DB2LIN_AMP_BITS = 11;
53#define SLOT_AMP_BITS DB2LIN_AMP_BITS
54
55// Bits for Pitch and Amp modulator
56#define PM_PG_BITS 8
57#define PM_PG_WIDTH (1<<PM_PG_BITS)
58static const int PM_DP_BITS = 16;
59#define PM_DP_WIDTH (1<<PM_DP_BITS)
60#define AM_PG_BITS 8
61#define AM_PG_WIDTH (1<<AM_PG_BITS)
62static const int AM_DP_BITS = 16;
63#define AM_DP_WIDTH (1<<AM_DP_BITS)
64
65// Bitmask for register 0x04
66/** Timer1 Start. */
67static const int R04_ST1 = 0x01;
68/** Timer2 Start. */
69static const int R04_ST2 = 0x02;
70// not used
71//static const int R04 = 0x04;
72/** Mask 'Buffer Ready'. */
73static const int R04_MASK_BUF_RDY = 0x08;
74/** Mask 'End of sequence'. */
75static const int R04_MASK_EOS = 0x10;
76/** Mask Timer2 flag. */
77static const int R04_MASK_T2 = 0x20;
78/** Mask Timer1 flag. */
79static const int R04_MASK_T1 = 0x40;
80/** IRQ RESET. */
81static const int R04_IRQ_RESET = 0x80;
82
83// Bitmask for status register
84#define STATUS_EOS (R04_MASK_EOS)
85#define STATUS_BUF_RDY (R04_MASK_BUF_RDY)
86#define STATUS_T2 (R04_MASK_T2)
87#define STATUS_T1 (R04_MASK_T1)
88
89// Definition of envelope mode
90enum { ATTACK,DECAY,SUSHOLD,SUSTINE,RELEASE,FINISH };
91
92struct Patch {
93 bool AM, PM, EG;
94 byte KR; // 0-1
95 byte ML; // 0-15
96 byte KL; // 0-3
97 byte TL; // 0-63
98 byte FB; // 0-7
99 byte AR; // 0-15
100 byte DR; // 0-15
101 byte SL; // 0-15
102 byte RR; // 0-15
103};
104
105void patchReset(struct Patch* p);
106
107struct Slot {
108 // OUTPUT
109 int feedback;
110 /** Output value of slot. */
111 int output[5];
112
113 // for Phase Generator (PG)
114 /** Phase. */
115 unsigned int phase;
116 /** Phase increment amount. */
117 unsigned int dphase;
118 /** Output. */
119 int pgout;
120
121 // for Envelope Generator (EG)
122 /** F-Number. */
123 int fnum;
124 /** Block. */
125 int block;
126 /** Total Level + Key scale level. */
127 int tll;
128 /** Key scale offset (Rks). */
129 int rks;
130 /** Current state. */
131 int eg_mode;
132 /** Phase. */
133 unsigned int eg_phase;
134 /** Phase increment amount. */
135 unsigned int eg_dphase;
136 /** Output. */
137 int egout;
138
139 bool slotStatus;
140 struct Patch patch;
141
142 // refer to Y8950->
143 int *plfo_pm;
144 int *plfo_am;
145};
146
147void slotReset(struct Slot* slot);
148
149
150struct OPLChannel {
151 bool alg;
152 struct Slot mod, car;
153};
154
155void channelReset(struct OPLChannel* ch);
156
157
158struct Y8950
159{
160 int adr;
161 int output[2];
162 // Register
163 byte reg[0x100];
164 bool rythm_mode;
165 // Pitch Modulator
166 int pm_mode;
167 unsigned int pm_phase;
168 // Amp Modulator
169 int am_mode;
170 unsigned int am_phase;
171
172 // Noise Generator
173 int noise_seed;
174 int whitenoise;
175 int noiseA;
176 int noiseB;
177 unsigned int noiseA_phase;
178 unsigned int noiseB_phase;
179 unsigned int noiseA_dphase;
180 unsigned int noiseB_dphase;
181
182 // Channel & Slot
183 struct OPLChannel ch[9];
184 struct Slot *slot[18];
185
186 unsigned int pm_dphase;
187 int lfo_pm;
188 unsigned int am_dphase;
189 int lfo_am;
190
191 int maxVolume;
192 bool internalMuted;
193
194 int clockRate;
195
196 /** STATUS Register. */
197 byte status;
198 /** bit=0 -> masked. */
199 byte statusMask;
200 /* MsxAudioIRQHelper irq; */
201
202 // ADPCM
203 struct Y8950Adpcm adpcm;
204
205 /** 13-bit (exponential) DAC. */
206 /* DACSound16S dac13; */
207
208 // DAC stuff
209 int dacSampleVolume;
210 int dacOldSampleVolume;
211 int dacSampleVolumeSum;
212 int dacCtrlVolume;
213 int dacDaVolume;
214 int dacEnabled;
215
216 // Internal buffer
217 int buffer[AUDIO_MONO_BUFFER_SIZE];
218};
219
220void OPL_init(struct Y8950* this_, byte* ramBank, int sampleRam);
221
222void OPL_reset(struct Y8950* this_);
223void OPL_writeReg(struct Y8950* this_, byte reg, byte data);
224byte OPL_readReg(struct Y8950* this_, byte reg);
225byte OPL_readStatus(struct Y8950* this_);
226static inline void OPL_setInternalMute(struct Y8950* this_, bool muted) { this_->internalMuted = muted; }
227static inline bool OPL_isInternalMuted(struct Y8950* this_) { return this_->internalMuted; }
228
229void OPL_setSampleRate(struct Y8950* this_, int sampleRate, int clockRate);
230int* OPL_updateBuffer(struct Y8950* this_, int length);
231
232// SoundDevice
233void OPL_setInternalVolume(struct Y8950* this_, short maxVolume);
234
235void OPL_setStatus(struct Y8950* this_, byte flags);
236void OPL_resetStatus(struct Y8950* this_, byte flags);
237void OPL_changeStatusMask(struct Y8950* this_, byte newMask);
238
239
240// Adjust envelope speed which depends on sampling rate
241static inline unsigned int rate_adjust(double x, int rate, int clk)
242{
243 double tmp = x * clk / 72 / rate + 0.5; // +0.5 to round
244// assert (tmp <= 4294967295U);
245 return (unsigned int)tmp;
246}
247
248#endif
diff --git a/apps/codecs/libgme/emuadpcm.c b/apps/codecs/libgme/emuadpcm.c
new file mode 100644
index 0000000000..1f2d5aefa5
--- /dev/null
+++ b/apps/codecs/libgme/emuadpcm.c
@@ -0,0 +1,298 @@
1/*
2 * This file is based on:
3 * Y8950Adpcm.cc -- Y8950 ADPCM emulator from the openMSX team
4 * ported to c by gama
5 *
6 * The openMSX version is based on:
7 * emuadpcm.c -- Y8950 ADPCM emulator written by Mitsutaka Okazaki 2001
8 * heavily rewritten to fit openMSX structure
9 */
10
11#include <string.h>
12
13#include "emuadpcm.h"
14#include "emu8950.h"
15
16// Relative volume between ADPCM part and FM part,
17// value experimentally found by Manuel Bilderbeek
18const int ADPCM_VOLUME = 356;
19
20// Bitmask for register 0x07
21static const int R07_RESET = 0x01;
22//static const int R07 = 0x02;. // not used
23//static const int R07 = 0x04;. // not used
24const int R07_SP_OFF = 0x08;
25const int R07_REPEAT = 0x10;
26const int R07_MEMORY_DATA = 0x20;
27const int R07_REC = 0x40;
28const int R07_START = 0x80;
29
30//Bitmask for register 0x08
31const int R08_ROM = 0x01;
32const int R08_64K = 0x02;
33const int R08_DA_AD = 0x04;
34const int R08_SAMPL = 0x08;
35//const int R08 = 0x10;. // not used
36//const int R08 = 0x20;. // not used
37const int R08_NOTE_SET = 0x40;
38const int R08_CSM = 0x80;
39
40const int DMAX = 0x6000;
41const int DMIN = 0x7F;
42const int DDEF = 0x7F;
43
44const int DECODE_MAX = 32767;
45const int DECODE_MIN = -32768;
46
47#define GETA_BITS 14
48#define MAX_STEP (1<<(16+GETA_BITS))
49
50
51//**************************************************//
52// //
53// Helper functions //
54// //
55//**************************************************//
56
57int CLAP(int min, int x, int max)
58{
59 return (x < min) ? min : ((max < x) ? max : x);
60}
61
62//**********************************************************//
63// //
64// Y8950Adpcm //
65// //
66//**********************************************************//
67
68
69void ADPCM_init(struct Y8950Adpcm* this_, struct Y8950* y8950_, byte* ramBank, int sampleRam)
70
71{
72 this_->y8950 = y8950_;
73 this_->ramBank = ramBank;
74 this_->ramSize = sampleRam;
75 memset(this_->ramBank, 0xFF, this_->ramSize);
76 this_->volume = 0;
77}
78
79void restart(struct Y8950Adpcm* this_);
80void ADPCM_reset(struct Y8950Adpcm* this_)
81{
82 this_->playing = false;
83 this_->startAddr = 0;
84 this_->stopAddr = 7;
85 this_->memPntr = 0;
86 this_->delta = 0;
87 this_->step = 0;
88 this_->addrMask = (1 << 19) - 1;
89 this_->reg7 = 0;
90 this_->reg15 = 0;
91 ADPCM_writeReg(this_, 0x12, 255); // volume
92 restart(this_);
93}
94
95void ADPCM_setSampleRate(struct Y8950Adpcm* this_, int sr, int clk)
96{
97 this_->sampleRate = sr;
98 this_->clockRate = clk;
99}
100
101bool ADPCM_muted(struct Y8950Adpcm* this_)
102{
103 return (!this_->playing) || (this_->reg7 & R07_SP_OFF);
104}
105
106//**************************************************//
107// //
108// I/O Ctrl //
109// //
110//**************************************************//
111
112void restart(struct Y8950Adpcm* this_)
113{
114 this_->playAddr = this_->startAddr & this_->addrMask;
115 this_->nowStep = MAX_STEP - this_->step;
116 this_->out = this_->output = 0;
117 this_->diff = DDEF;
118 this_->nextLeveling = 0;
119 this_->sampleStep = 0;
120 this_->volumeWStep = (int)((double)this_->volume * this_->step / MAX_STEP);
121}
122
123void ADPCM_writeReg(struct Y8950Adpcm* this_, byte rg, byte data)
124{
125 switch (rg) {
126 case 0x07: // START/REC/MEM DATA/REPEAT/SP-OFF/-/-/RESET
127 this_->reg7 = data;
128 if (this_->reg7 & R07_RESET) {
129 this_->playing = false;
130 } else if (data & R07_START) {
131 this_->playing = true;
132 restart(this_);
133 }
134 break;
135
136 case 0x08: // CSM/KEY BOARD SPLIT/-/-/SAMPLE/DA AD/64K/ROM
137 this_->romBank = data & R08_ROM;
138 this_->addrMask = data & R08_64K ? (1<<17)-1 : (1<<19)-1;
139 break;
140
141 case 0x09: // START ADDRESS (L)
142 this_->startAddr = (this_->startAddr & 0x7F800) | (data << 3);
143 this_->memPntr = 0;
144 break;
145 case 0x0A: // START ADDRESS (H)
146 this_->startAddr = (this_->startAddr & 0x007F8) | (data << 11);
147 this_->memPntr = 0;
148 break;
149
150 case 0x0B: // STOP ADDRESS (L)
151 this_->stopAddr = (this_->stopAddr & 0x7F807) | (data << 3);
152 break;
153 case 0x0C: // STOP ADDRESS (H)
154 this_->stopAddr = (this_->stopAddr & 0x007FF) | (data << 11);
155 break;
156
157
158 case 0x0F: // ADPCM-DATA
159 // TODO check this
160 //if ((reg7 & R07_REC) && (reg7 & R07_MEMORY_DATA)) {
161 {
162 int tmp = ((this_->startAddr + this_->memPntr) & this_->addrMask) / 2;
163 tmp = (tmp < this_->ramSize) ? tmp : (tmp & (this_->ramSize - 1));
164 if (!this_->romBank) {
165 this_->ramBank[tmp] = data;
166 }
167 //PRT_DEBUG("Y8950Adpcm: mem " << tmp << " " << (int)data);
168 this_->memPntr += 2;
169 if ((this_->startAddr + this_->memPntr) > this_->stopAddr) {
170 OPL_setStatus(this_->y8950, STATUS_EOS);
171 }
172 }
173 OPL_setStatus(this_->y8950, STATUS_BUF_RDY);
174 break;
175
176 case 0x10: // DELTA-N (L)
177 this_->delta = (this_->delta & 0xFF00) | data;
178 this_->step = rate_adjust(this_->delta<<GETA_BITS, this_->sampleRate, this_->clockRate);
179 this_->volumeWStep = (int)((double)this_->volume * this_->step / MAX_STEP);
180 break;
181 case 0x11: // DELTA-N (H)
182 this_->delta = (this_->delta & 0x00FF) | (data << 8);
183 this_->step = rate_adjust(this_->delta<<GETA_BITS, this_->sampleRate, this_->clockRate);
184 this_->volumeWStep = (int)((double)this_->volume * this_->step / MAX_STEP);
185 break;
186
187 case 0x12: { // ENVELOP CONTROL
188 int oldVol = this_->volume;
189 this_->volume = (data * ADPCM_VOLUME) >> 8;
190 if (oldVol != 0) {
191 double factor = (double)this_->volume / (double)oldVol;
192 this_->output = (int)((double)this_->output * factor);
193 this_->sampleStep = (int)((double)this_->sampleStep * factor);
194 }
195 this_->volumeWStep = (int)((double)this_->volume * this_->step / MAX_STEP);
196 break;
197 }
198 case 0x0D: // PRESCALE (L)
199 case 0x0E: // PRESCALE (H)
200 case 0x15: // DAC-DATA (bit9-2)
201 case 0x16: // (bit1-0)
202 case 0x17: // (exponent)
203 case 0x1A: // PCM-DATA
204 // not implemented
205 break;
206 }
207}
208
209byte ADPCM_readReg(struct Y8950Adpcm* this_, byte rg)
210{
211 byte result;
212 switch (rg) {
213 case 0x0F: { // ADPCM-DATA
214 // TODO don't advance pointer when playing???
215 int adr = ((this_->startAddr + this_->memPntr) & this_->addrMask) / 2;
216 if (this_->romBank || (adr >= this_->ramSize)) {
217 result = 0xFF;
218 } else {
219 result = this_->ramBank[adr];
220 }
221 this_->memPntr += 2;
222 if ((this_->startAddr + this_->memPntr) > this_->stopAddr) {
223 OPL_setStatus(this_->y8950, STATUS_EOS);
224 }
225 break;
226 }
227 case 0x13: // TODO check
228 result = this_->out & 0xFF;
229 break;
230 case 0x14: // TODO check
231 result = this_->out / 256;
232 break;
233 default:
234 result = 255;
235 }
236 //PRT_DEBUG("Y8950Adpcm: read "<<(int)rg<<" "<<(int)result);
237 return result;
238}
239
240int ADPCM_calcSample(struct Y8950Adpcm* this_)
241{
242 // This table values are from ymdelta.c by Tatsuyuki Satoh.
243 static const int F1[16] = { 1, 3, 5, 7, 9, 11, 13, 15,
244 -1, -3, -5, -7, -9, -11, -13, -15};
245 static const int F2[16] = {57, 57, 57, 57, 77, 102, 128, 153,
246 57, 57, 57, 57, 77, 102, 128, 153};
247
248 if (ADPCM_muted(this_)) {
249 return 0;
250 }
251 this_->nowStep += this_->step;
252 if (this_->nowStep >= MAX_STEP) {
253 int nowLeveling;
254 do {
255 this_->nowStep -= MAX_STEP;
256 unsigned long val;
257 if (!(this_->playAddr & 1)) {
258 // n-th nibble
259 int tmp = this_->playAddr / 2;
260 if (this_->romBank || (tmp >= this_->ramSize)) {
261 this_->reg15 = 0xFF;
262 } else {
263 this_->reg15 = this_->ramBank[tmp];
264 }
265 val = this_->reg15 >> 4;
266 } else {
267 // (n+1)-th nibble
268 val = this_->reg15 & 0x0F;
269 }
270 int prevOut = this_->out;
271 this_->out = CLAP(DECODE_MIN, this_->out + (this_->diff * F1[val]) / 8,
272 DECODE_MAX);
273 this_->diff = CLAP(DMIN, (this_->diff * F2[val]) / 64, DMAX);
274 int deltaNext = this_->out - prevOut;
275 nowLeveling = this_->nextLeveling;
276 this_->nextLeveling = prevOut + deltaNext / 2;
277
278 this_->playAddr++;
279 if (this_->playAddr > this_->stopAddr) {
280 if (this_->reg7 & R07_REPEAT) {
281 restart(this_);
282 } else {
283 this_->playing = false;
284 //y8950.setStatus(Y8950::STATUS_EOS);
285 }
286 }
287 } while (this_->nowStep >= MAX_STEP);
288 this_->sampleStep = (this_->nextLeveling - nowLeveling) * this_->volumeWStep;
289 this_->output = nowLeveling * this_->volume;
290
291 /* TODO: Used fixed point math here */
292 #if !defined(ROCKBOX)
293 this_->output += (int)((double)this_->sampleStep * ((double)this_->nowStep/(double)this_->step));
294 #endif
295 }
296 this_->output += this_->sampleStep;
297 return this_->output >> 12;
298}
diff --git a/apps/codecs/libgme/emuadpcm.h b/apps/codecs/libgme/emuadpcm.h
new file mode 100644
index 0000000000..0fc39a1709
--- /dev/null
+++ b/apps/codecs/libgme/emuadpcm.h
@@ -0,0 +1,52 @@
1#ifndef __Y8950ADPCM_HH__
2#define __Y8950ADPCM_HH__
3
4#include "blargg_common.h"
5#include "blargg_source.h"
6#include "msxtypes.h"
7
8typedef unsigned short word;
9typedef unsigned __int64 uint64;
10struct Y8950;
11
12struct Y8950Adpcm
13{
14 struct Y8950* y8950;
15
16 int sampleRate;
17 int clockRate;
18
19 int ramSize;
20 int startAddr;
21 int stopAddr;
22 int playAddr;
23 int addrMask;
24 int memPntr;
25 bool romBank;
26 byte* ramBank;
27
28 bool playing;
29 int volume;
30 word delta;
31 unsigned int nowStep, step;
32 int out, output;
33 int diff;
34 int nextLeveling;
35 int sampleStep;
36 int volumeWStep;
37
38 byte reg7;
39 byte reg15;
40};
41
42
43void ADPCM_init(struct Y8950Adpcm* this_, struct Y8950* y8950, byte* ramBank, int sampleRam);
44void ADPCM_reset(struct Y8950Adpcm* this_);
45void ADPCM_setSampleRate(struct Y8950Adpcm* this_, int sr, int clk);
46bool ADPCM_muted(struct Y8950Adpcm* this_);
47void ADPCM_writeReg(struct Y8950Adpcm* this_, byte rg, byte data);
48byte ADPCM_readReg(struct Y8950Adpcm* this_, byte rg);
49int ADPCM_calcSample(struct Y8950Adpcm* this_);
50
51
52#endif
diff --git a/apps/codecs/libgme/emutables.h b/apps/codecs/libgme/emutables.h
new file mode 100644
index 0000000000..53fb324cdd
--- /dev/null
+++ b/apps/codecs/libgme/emutables.h
@@ -0,0 +1,170 @@
1#ifndef _EMUTABLES_H_
2#define _EMUTABLES_H_
3
4/* Precalculated emu2413 tables for use in Rockbox,
5 Calculated for 44Khz sampling rate */
6
7#include "emutypes.h"
8
9static const e_uint16 sin_coeff[] ICONST_ATTR = {
10 255, 203, 171, 152, 139, 129, 120,
11 113, 107, 102, 97, 92, 88, 85,
12 81, 78, 75, 72, 70, 67, 65,
13 63, 61, 59, 57, 55, 53, 52,
14 50, 48, 47, 45, 44, 43, 41,
15 40, 39, 38, 37, 35, 34, 33,
16 32, 31, 30, 29, 28, 28, 27,
17 26, 25, 24, 23, 23, 22, 21,
18 21, 20, 19, 19, 18, 17, 17,
19 16, 16, 15, 14, 14, 13, 13,
20 12, 12, 11, 11, 11, 10, 10,
21 9, 9, 8, 8, 8, 7, 7,
22 7, 6, 6, 6, 5, 5, 5,
23 4, 4, 4, 4, 3, 3, 3,
24 3, 2, 2, 2, 2, 2, 2,
25 1, 1, 1, 1, 1, 1, 1,
26 0, 0, 0, 0, 0, 0, 0,
27 0, 0, 0, 0, 0, 0, 0,
28 0, 0,
29};
30
31static const e_int32 pm_coeff[] ICONST_ATTR = {
32 256, 256, 256, 256, 256, 256, 256,
33 256, 256, 256, 256, 256, 256, 256,
34 256, 256, 256, 256, 256, 256, 256,
35 256, 256, 256, 256, 256, 256, 256,
36 256, 256, 256, 256, 257, 257, 257,
37 257, 257, 257, 257, 257, 257, 257,
38 257, 257, 257, 257, 257, 257, 257,
39 257, 257, 257, 257, 257, 257, 257,
40 257, 257, 257, 257, 257, 257, 257,
41 258, 258, 258, 257, 257, 257, 257,
42 257, 257, 257, 257, 257, 257, 257,
43 257, 257, 257, 257, 257, 257, 257,
44 257, 257, 257, 257, 257, 257, 257,
45 257, 257, 257, 257, 257, 257, 256,
46 256, 256, 256, 256, 256, 256, 256,
47 256, 256, 256, 256, 256, 256, 256,
48 256, 256, 256, 256, 256, 256, 256,
49 256, 256, 256, 256, 256, 256, 256,
50 256, 256, 256, 255, 255, 255, 255,
51 255, 255, 255, 255, 255, 255, 255,
52 255, 255, 255, 255, 255, 255, 255,
53 255, 255, 255, 255, 255, 255, 255,
54 255, 255, 255, 255, 255, 255, 254,
55 254, 254, 254, 254, 254, 254, 254,
56 254, 254, 254, 254, 254, 254, 254,
57 254, 254, 254, 254, 254, 254, 254,
58 254, 254, 254, 254, 254, 254, 254,
59 254, 254, 254, 253, 254, 254, 254,
60 254, 254, 254, 254, 254, 254, 254,
61 254, 254, 254, 254, 254, 254, 254,
62 254, 254, 254, 254, 254, 254, 254,
63 254, 254, 254, 254, 254, 254, 254,
64 254, 255, 255, 255, 255, 255, 255,
65 255, 255, 255, 255, 255, 255, 255,
66 255, 255, 255, 255, 255, 255, 255,
67 255, 255, 255, 255, 255, 255, 255,
68 255, 255, 255, 255,
69};
70
71static const e_int16 db2lin_coeff[] ICONST_ATTR = {
72 255, 249, 244, 239, 233, 228, 224,
73 219, 214, 209, 205, 201, 196, 192,
74 188, 184, 180, 176, 172, 169, 165,
75 162, 158, 155, 151, 148, 145, 142,
76 139, 136, 133, 130, 127, 125, 122,
77 119, 117, 114, 112, 109, 107, 105,
78 102, 100, 98, 96, 94, 92, 90,
79 88, 86, 84, 82, 81, 79, 77,
80 76, 74, 72, 71, 69, 68, 66,
81 65, 64, 62, 61, 60, 58, 57,
82 56, 55, 53, 52, 51, 50, 49,
83 48, 47, 46, 45, 44, 43, 42,
84 41, 40, 39, 38, 38, 37, 36,
85 35, 34, 34, 33, 32, 32, 31,
86 30, 30, 29, 28, 28, 27, 27,
87 26, 25, 25, 24, 24, 23, 23,
88 22, 22, 21, 21, 20, 20, 19,
89 19, 19, 18, 18, 17, 17, 17,
90 16, 16, 16, 15, 15, 15, 14,
91 14, 14, 13, 13, 13, 12, 12,
92 12, 12, 11, 11, 11, 11, 10,
93 10, 10, 10, 10, 9, 9, 9,
94 9, 8, 8, 8, 8, 8, 8,
95 7, 7, 7, 7, 7, 7, 6,
96 6, 6, 6, 6, 6, 6, 5,
97 5, 5, 5, 5, 5, 5, 5,
98 5, 4, 4, 4, 4, 4, 4,
99 4, 4, 4, 4, 3, 3, 3,
100 3, 3, 3, 3, 3, 3, 3,
101 3, 3, 3, 2, 2, 2, 2,
102 2, 2, 2, 2, 2, 2, 2,
103 2, 2, 2, 2, 2, 2, 2,
104 2, 1, 1, 1, 1, 1, 1,
105 1, 1, 1, 1, 1, 1, 1,
106 1, 1, 1, 1, 1, 1, 1,
107 1, 1, 1, 1, 1, 1, 1,
108 1, 1, 1, 1, 1, 0, 0,
109 0, 0, 0, 0, 0, 0, 0,
110 0, 0, 0, 0, 0, 0, 0,
111 0, 0, 0, 0, 0, 0, 0,
112 0, 0, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0, 0, 0,
114 0, 0, 0, 0, 0, 0, 0,
115 0, 0, 0, 0, 0, 0, 0,
116 0, 0, 0, 0, 0, 0, 0,
117 0, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 0, 0,
119 0, 0, 0, 0, 0, 0, 0,
120 0, 0, 0, 0, 0, 0, 0,
121 0, 0, 0, 0, 0, 0, 0,
122 0, 0, 0, 0, 0, 0, 0,
123 0, 0, 0, 0, 0, 0, 0,
124 0, 0, 0, 0, 0, 0, 0,
125 0, 0, 0, 0, 0, 0, 0,
126 0, 0, 0, 0, 0, 0, 0,
127 0, 0, 0, 0, 0, 0, 0,
128 0, 0, 0, 0, 0, 0, 0,
129 0, 0, 0, 0, 0, 0, 0,
130 0, 0, 0, 0, 0, 0, 0,
131 0, 0, 0, 0, 0, 0, 0,
132 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0,
134 0, 0, 0, 0, 0, 0, 0,
135 0, 0, 0, 0, 0, 0, 0,
136 0, 0, 0, 0, 0, 0, 0,
137 0, 0, 0, 0, 0, 0, 0,
138 0, 0, 0, 0, 0, 0, 0,
139 0, 0, 0, 0, 0, 0, 0,
140 0, 0, 0, 0, 0, 0, 0,
141 0, 0, 0, 0, 0, 0, 0,
142 0, 0, 0, 0, 0, 0, 0,
143 0, 0, 0, 0, 0, 0, 0,
144 0, 0, 0, 0, 0, 0, 0,
145 0,
146};
147
148static const e_uint16 ar_adjust_coeff[] ICONST_ATTR = {
149 127, 108, 98, 90, 84, 80, 75,
150 72, 69, 66, 64, 61, 59, 57,
151 56, 54, 52, 51, 49, 48, 47,
152 45, 44, 43, 42, 41, 40, 39,
153 38, 37, 36, 36, 35, 34, 33,
154 33, 32, 31, 30, 30, 29, 29,
155 28, 27, 27, 26, 26, 25, 24,
156 24, 23, 23, 22, 22, 21, 21,
157 21, 20, 20, 19, 19, 18, 18,
158 17, 17, 17, 16, 16, 15, 15,
159 15, 14, 14, 14, 13, 13, 13,
160 12, 12, 12, 11, 11, 11, 10,
161 10, 10, 9, 9, 9, 9, 8,
162 8, 8, 7, 7, 7, 7, 6,
163 6, 6, 6, 5, 5, 5, 4,
164 4, 4, 4, 4, 3, 3, 3,
165 3, 2, 2, 2, 2, 1, 1,
166 1, 1, 1, 0, 0, 0, 0,
167 0,
168};
169
170#endif
diff --git a/apps/codecs/libgme/emutypes.h b/apps/codecs/libgme/emutypes.h
new file mode 100644
index 0000000000..bf5d7e1bf2
--- /dev/null
+++ b/apps/codecs/libgme/emutypes.h
@@ -0,0 +1,41 @@
1#ifndef _EMUTYPES_H_
2#define _EMUTYPES_H_
3
4#if defined(_MSC_VER)
5#define INLINE __forceinline
6#elif defined(__GNUC__)
7#define INLINE __inline__
8#elif defined(_MWERKS_)
9#define INLINE inline
10#else
11#define INLINE
12#endif
13
14#if defined(EMU_DLL_IMPORTS)
15#define EMU2149_DLL_IMPORTS
16#define EMU2212_DLL_IMPORTS
17#define EMU2413_DLL_IMPORTS
18#define EMU8950_DLL_IMPORTS
19#define EMU76489_DLL_IMPORTS
20#endif
21
22#ifdef __cplusplus
23extern "C" {
24#endif
25
26typedef unsigned int e_uint;
27typedef signed int e_int;
28
29typedef unsigned char e_uint8 ;
30typedef signed char e_int8 ;
31
32typedef unsigned short e_uint16 ;
33typedef signed short e_int16 ;
34
35typedef unsigned int e_uint32 ;
36typedef signed int e_int32 ;
37
38#ifdef __cplusplus
39}
40#endif
41#endif
diff --git a/apps/codecs/libgme/gb_apu.c b/apps/codecs/libgme/gb_apu.c
new file mode 100644
index 0000000000..a441645e3e
--- /dev/null
+++ b/apps/codecs/libgme/gb_apu.c
@@ -0,0 +1,410 @@
1// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/
2
3#include "gb_apu.h"
4
5//#include "gb_apu_logger.h"
6
7/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
8can redistribute it and/or modify it under the terms of the GNU Lesser
9General Public License as published by the Free Software Foundation; either
10version 2.1 of the License, or (at your option) any later version. This
11module is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14details. You should have received a copy of the GNU Lesser General Public
15License along with this module; if not, write to the Free Software Foundation,
16Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17
18#include "blargg_source.h"
19
20int const vol_reg = 0xFF24;
21int const stereo_reg = 0xFF25;
22int const status_reg = 0xFF26;
23int const wave_ram = 0xFF30;
24
25int const power_mask = 0x80;
26
27inline int calc_output( struct Gb_Apu* this, int osc )
28{
29 int bits = this->regs [stereo_reg - io_addr] >> osc;
30 return (bits >> 3 & 2) | (bits & 1);
31}
32
33void Apu_set_output( struct Gb_Apu* this, int i, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right )
34{
35 // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL)
36 require( !center || (center && !left && !right) || (center && left && right) );
37 require( (unsigned) i < osc_count ); // fails if you pass invalid osc index
38
39 if ( !center || !left || !right )
40 {
41 left = center;
42 right = center;
43 }
44
45 struct Gb_Osc* o = this->oscs [i];
46 o->outputs [1] = right;
47 o->outputs [2] = left;
48 o->outputs [3] = center;
49 o->output = o->outputs [calc_output( this, i )];
50}
51
52void synth_volume( struct Gb_Apu* this, int iv )
53{
54 double v = this->volume_ * 0.60 / osc_count / 15 /*steps*/ / 8 /*master vol range*/ * iv;
55 Synth_volume( &this->synth, v );
56}
57
58void apply_volume( struct Gb_Apu* this )
59{
60 // TODO: Doesn't handle differing left and right volumes (panning).
61 // Not worth the complexity.
62 int data = this->regs [vol_reg - io_addr];
63 int left = data >> 4 & 7;
64 int right = data & 7;
65 //if ( data & 0x88 ) dprintf( "Vin: %02X\n", data & 0x88 );
66 //if ( left != right ) dprintf( "l: %d r: %d\n", left, right );
67 synth_volume( this, max( left, right ) + 1 );
68}
69
70void Apu_volume( struct Gb_Apu* this, double v )
71{
72 if ( this->volume_ != v )
73 {
74 this->volume_ = v;
75 apply_volume( this );
76 }
77}
78
79void reset_regs( struct Gb_Apu* this )
80{
81 int i;
82 for ( i = 0; i < 0x20; i++ )
83 this->regs [i] = 0;
84
85 Sweep_reset ( &this->square1 );
86 Square_reset( &this->square2 );
87 Wave_reset ( &this->wave );
88 Noise_reset ( &this->noise );
89
90 apply_volume( this );
91}
92
93void reset_lengths( struct Gb_Apu* this )
94{
95 this->square1.osc.length_ctr = 64;
96 this->square2.osc.length_ctr = 64;
97 this->wave .osc.length_ctr = 256;
98 this->noise .osc.length_ctr = 64;
99}
100
101void Apu_reduce_clicks( struct Gb_Apu* this, bool reduce )
102{
103 this->reduce_clicks_ = reduce;
104
105 // Click reduction makes DAC off generate same output as volume 0
106 int dac_off_amp = 0;
107 if ( reduce && this->wave.osc.mode != mode_agb ) // AGB already eliminates clicks
108 dac_off_amp = -dac_bias;
109
110 int i;
111 for ( i = 0; i < osc_count; i++ )
112 this->oscs [i]->dac_off_amp = dac_off_amp;
113
114 // AGB always eliminates clicks on wave channel using same method
115 if ( this->wave.osc.mode == mode_agb )
116 this->wave.osc.dac_off_amp = -dac_bias;
117}
118
119void Apu_reset( struct Gb_Apu* this, enum gb_mode_t mode, bool agb_wave )
120{
121 // Hardware mode
122 if ( agb_wave )
123 mode = mode_agb; // using AGB wave features implies AGB hardware
124 this->wave.agb_mask = agb_wave ? 0xFF : 0;
125 int i;
126 for ( i = 0; i < osc_count; i++ )
127 this->oscs [i]->mode = mode;
128 Apu_reduce_clicks( this, this->reduce_clicks_ );
129
130 // Reset state
131 this->frame_time = 0;
132 this->last_time = 0;
133 this->frame_phase = 0;
134
135 reset_regs( this );
136 reset_lengths( this );
137
138 // Load initial wave RAM
139 static byte const initial_wave [2] [16] ICONST_ATTR = {
140 {0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C,0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA},
141 {0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF},
142 };
143 int b;
144 for ( b = 2; --b >= 0; )
145 {
146 // Init both banks (does nothing if not in AGB mode)
147 // TODO: verify that this works
148 Apu_write_register( this, 0, 0xFF1A, b * 0x40 );
149 unsigned i;
150 for ( i = 0; i < sizeof initial_wave [0]; i++ )
151 Apu_write_register( this, 0, i + wave_ram, initial_wave [(mode != mode_dmg)] [i] );
152 }
153}
154
155void Apu_set_tempo( struct Gb_Apu* this, double t )
156{
157 this->frame_period = 4194304 / 512; // 512 Hz
158 if ( t != 1.0 )
159 this->frame_period = t ? (blip_time_t) (this->frame_period / t) : (blip_time_t) (0);
160}
161
162void Apu_init( struct Gb_Apu* this )
163{
164 this->wave.wave_ram = &this->regs [wave_ram - io_addr];
165
166 Synth_init( &this->synth );
167
168 this->oscs [0] = &this->square1.osc;
169 this->oscs [1] = &this->square2.osc;
170 this->oscs [2] = &this->wave.osc;
171 this->oscs [3] = &this->noise.osc;
172
173 int i;
174 for ( i = osc_count; --i >= 0; )
175 {
176 struct Gb_Osc* o = this->oscs [i];
177 o->regs = &this->regs [i * 5];
178 o->output = NULL;
179 o->outputs [0] = NULL;
180 o->outputs [1] = NULL;
181 o->outputs [2] = NULL;
182 o->outputs [3] = NULL;
183 o->synth = &this->synth;
184 }
185
186 this->reduce_clicks_ = false;
187 Apu_set_tempo( this, 1.0 );
188 this->volume_ = 1.0;
189 Apu_reset( this, mode_cgb, false );
190}
191
192void run_until_( struct Gb_Apu* this, blip_time_t end_time )
193{
194 if ( !this->frame_period )
195 this->frame_time += end_time - this->last_time;
196
197 while ( true )
198 {
199 // run oscillators
200 blip_time_t time = end_time;
201 if ( time > this->frame_time )
202 time = this->frame_time;
203
204 Square_run( &this->square1, this->last_time, time );
205 Square_run( &this->square2, this->last_time, time );
206 Wave_run ( &this->wave, this->last_time, time );
207 Noise_run ( &this->noise, this->last_time, time );
208 this->last_time = time;
209
210 if ( time == end_time )
211 break;
212
213 // run frame sequencer
214 assert( this->frame_period );
215 this->frame_time += this->frame_period * clk_mul;
216 switch ( this->frame_phase++ )
217 {
218 case 2:
219 case 6:
220 // 128 Hz
221 clock_sweep( &this->square1 );
222 case 0:
223 case 4:
224 // 256 Hz
225 Osc_clock_length( &this->square1.osc );
226 Osc_clock_length( &this->square2.osc);
227 Osc_clock_length( &this->wave.osc);
228 Osc_clock_length( &this->noise.osc);
229 break;
230
231 case 7:
232 // 64 Hz
233 this->frame_phase = 0;
234 Square_clock_envelope( &this->square1 );
235 Square_clock_envelope( &this->square2 );
236 Noise_clock_envelope( &this->noise );
237 }
238 }
239}
240
241inline void run_until( struct Gb_Apu* this, blip_time_t time )
242{
243 require( time >= this->last_time ); // end_time must not be before previous time
244 if ( time > this->last_time )
245 run_until_( this, time );
246}
247
248void Apu_end_frame( struct Gb_Apu* this, blip_time_t end_time )
249{
250 #ifdef LOG_FRAME
251 LOG_FRAME( end_time );
252 #endif
253
254 if ( end_time > this->last_time )
255 run_until( this, end_time );
256
257 this->frame_time -= end_time;
258 assert( this->frame_time >= 0 );
259
260 this->last_time -= end_time;
261 assert( this->last_time >= 0 );
262}
263
264void silence_osc( struct Gb_Apu* this, struct Gb_Osc* o )
265{
266 int delta = -o->last_amp;
267 if ( this->reduce_clicks_ )
268 delta += o->dac_off_amp;
269
270 if ( delta )
271 {
272 o->last_amp = o->dac_off_amp;
273 if ( o->output )
274 {
275 Blip_set_modified( o->output );
276 Synth_offset( &this->synth, this->last_time, delta, o->output );
277 }
278 }
279}
280
281void apply_stereo( struct Gb_Apu* this )
282{
283 int i;
284 for ( i = osc_count; --i >= 0; )
285 {
286 struct Gb_Osc* o = this->oscs [i];
287 struct Blip_Buffer* out = o->outputs [calc_output( this, i )];
288 if ( o->output != out )
289 {
290 silence_osc( this, o );
291 o->output = out;
292 }
293 }
294}
295
296void Apu_write_register( struct Gb_Apu* this, blip_time_t time, int addr, int data )
297{
298 require( (unsigned) data < 0x100 );
299
300 int reg = addr - io_addr;
301 if ( (unsigned) reg >= io_size )
302 {
303 require( false );
304 return;
305 }
306
307 #ifdef LOG_WRITE
308 LOG_WRITE( time, addr, data );
309 #endif
310
311 if ( addr < status_reg && !(this->regs [status_reg - io_addr] & power_mask) )
312 {
313 // Power is off
314
315 // length counters can only be written in DMG mode
316 if ( this->wave.osc.mode != mode_dmg || (reg != 1 && reg != 5+1 && reg != 10+1 && reg != 15+1) )
317 return;
318
319 if ( reg < 10 )
320 data &= 0x3F; // clear square duty
321 }
322
323 run_until( this, time );
324
325 if ( addr >= wave_ram )
326 {
327 Wave_write( &this->wave, addr, data );
328 }
329 else
330 {
331 int old_data = this->regs [reg];
332 this->regs [reg] = data;
333
334 if ( addr < vol_reg )
335 {
336 // Oscillator
337 write_osc( this, reg, old_data, data );
338 }
339 else if ( addr == vol_reg && data != old_data )
340 {
341 // Master volume
342 int i;
343 for ( i = osc_count; --i >= 0; )
344 silence_osc( this, this->oscs [i] );
345
346 apply_volume( this );
347 }
348 else if ( addr == stereo_reg )
349 {
350 // Stereo panning
351 apply_stereo( this );
352 }
353 else if ( addr == status_reg && (data ^ old_data) & power_mask )
354 {
355 // Power control
356 this->frame_phase = 0;
357 int i;
358 for ( i = osc_count; --i >= 0; )
359 silence_osc( this, this->oscs [i] );
360
361 reset_regs( this );
362 if ( this->wave.osc.mode != mode_dmg )
363 reset_lengths( this );
364
365 this->regs [status_reg - io_addr] = data;
366 }
367 }
368}
369
370int Apu_read_register( struct Gb_Apu* this, blip_time_t time, int addr )
371{
372 if ( addr >= status_reg )
373 run_until( this, time );
374
375 int reg = addr - io_addr;
376 if ( (unsigned) reg >= io_size )
377 {
378 require( false );
379 return 0;
380 }
381
382 if ( addr >= wave_ram )
383 return Wave_read( &this->wave, addr );
384
385 // Value read back has some bits always set
386 static byte const masks [] ICONST_ATTR = {
387 0x80,0x3F,0x00,0xFF,0xBF,
388 0xFF,0x3F,0x00,0xFF,0xBF,
389 0x7F,0xFF,0x9F,0xFF,0xBF,
390 0xFF,0xFF,0x00,0x00,0xBF,
391 0x00,0x00,0x70,
392 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
393 };
394 int mask = masks [reg];
395 if ( this->wave.agb_mask && (reg == 10 || reg == 12) )
396 mask = 0x1F; // extra implemented bits in wave regs on AGB
397 int data = this->regs [reg] | mask;
398
399 // Status register
400 if ( addr == status_reg )
401 {
402 data &= 0xF0;
403 data |= (int) this->square1.osc.enabled << 0;
404 data |= (int) this->square2.osc.enabled << 1;
405 data |= (int) this->wave .osc.enabled << 2;
406 data |= (int) this->noise .osc.enabled << 3;
407 }
408
409 return data;
410}
diff --git a/apps/codecs/libgme/gb_apu.h b/apps/codecs/libgme/gb_apu.h
new file mode 100644
index 0000000000..f1457a2bbe
--- /dev/null
+++ b/apps/codecs/libgme/gb_apu.h
@@ -0,0 +1,85 @@
1// Nintendo Game Boy sound hardware emulator with save state support
2
3// Gb_Snd_Emu 0.1.4
4#ifndef GB_APU_H
5#define GB_APU_H
6
7#include "gb_oscs.h"
8
9// Clock rate sound hardware runs at
10enum { clock_rate = 4194304 * GB_APU_OVERCLOCK };
11
12// Registers are at io_addr to io_addr+io_size-1
13enum { io_addr = 0xFF10 };
14enum { io_size = 0x30 };
15enum { regs_size = io_size + 0x10 };
16
17enum gb_mode_t {
18 mode_dmg, // Game Boy monochrome
19 mode_cgb, // Game Boy Color
20 mode_agb // Game Boy Advance
21};
22
23// 0: Square 1, 1: Square 2, 2: Wave, 3: Noise
24enum { osc_count = 4 }; // 0 <= chan < osc_count
25
26struct Gb_Apu {
27 struct Gb_Osc* oscs [osc_count];
28 blip_time_t last_time; // time sound emulator has been run to
29 blip_time_t frame_period; // clocks between each frame sequencer step
30 double volume_;
31 bool reduce_clicks_;
32
33 struct Gb_Square square1;
34 struct Gb_Square square2;
35 struct Gb_Wave wave;
36 struct Gb_Noise noise;
37 blip_time_t frame_time; // time of next frame sequencer action
38 int frame_phase; // phase of next frame sequencer step
39
40 uint8_t regs [regs_size];// last values written to registers
41
42 // large objects after everything else
43 struct Blip_Synth synth;
44};
45
46// Basics
47
48// Initializes apu
49void Apu_init( struct Gb_Apu* this );
50
51// Emulates to time t, then writes data to addr
52void Apu_write_register( struct Gb_Apu* this, blip_time_t t, int addr, int data ) ICODE_ATTR;
53
54// Emulates to time t, then subtracts t from the current time.
55// OK if previous write call had time slightly after t.
56void Apu_end_frame( struct Gb_Apu* this,blip_time_t t ) ICODE_ATTR;
57
58// More features
59
60// Emulates to time t, then reads from addr
61int Apu_read_register( struct Gb_Apu* this, blip_time_t t, int addr ) ICODE_ATTR;
62
63// Resets hardware to state after power, BEFORE boot ROM runs. Mode selects
64// sound hardware. If agb_wave is true, enables AGB's extra wave features.
65void Apu_reset( struct Gb_Apu* this, enum gb_mode_t mode, bool agb_wave );
66
67// Same as set_output(), but for a particular channel
68void Apu_set_output( struct Gb_Apu* this, int chan, struct Blip_Buffer* center,
69 struct Blip_Buffer* left, struct Blip_Buffer* right );
70
71// Sets overall volume, where 1.0 is normal
72void Apu_volume( struct Gb_Apu* this, double v );
73
74// If true, reduces clicking by disabling DAC biasing. Note that this reduces
75// emulation accuracy, since the clicks are authentic.
76void Apu_reduce_clicks( struct Gb_Apu* this, bool reduce );
77
78// Sets frame sequencer rate, where 1.0 is normal. Meant for adjusting the
79// tempo in a music player.
80void Apu_set_tempo( struct Gb_Apu* this, double t );
81
82
83void write_osc( struct Gb_Apu* this, int reg, int old_data, int data ) ICODE_ATTR;
84
85#endif
diff --git a/apps/codecs/libgme/gb_cpu.c b/apps/codecs/libgme/gb_cpu.c
new file mode 100644
index 0000000000..ae19cc06c1
--- /dev/null
+++ b/apps/codecs/libgme/gb_cpu.c
@@ -0,0 +1,53 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "gb_cpu.h"
4
5#include "blargg_endian.h"
6
7/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
8can redistribute it and/or modify it under the terms of the GNU Lesser
9General Public License as published by the Free Software Foundation; either
10version 2.1 of the License, or (at your option) any later version. This
11module is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14details. You should have received a copy of the GNU Lesser General Public
15License along with this module; if not, write to the Free Software Foundation,
16Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17
18#include "blargg_source.h"
19
20inline void set_code_page( struct Gb_Cpu* this, int i, void* p )
21{
22 byte* p2 = STATIC_CAST(byte*,p) - GB_CPU_OFFSET( i * page_size );
23 this->cpu_state_.code_map [i] = p2;
24 this->cpu_state->code_map [i] = p2;
25}
26
27void Cpu_reset( struct Gb_Cpu* this, void* unmapped )
28{
29 check( this->cpu_state == &this->cpu_state_ );
30 this->cpu_state = &this->cpu_state_;
31
32 this->cpu_state_.time = 0;
33
34 int i;
35 for ( i = 0; i < page_count + 1; ++i )
36 set_code_page( this, i, unmapped );
37
38 memset( &this->r, 0, sizeof this->r );
39
40 blargg_verify_byte_order();
41}
42
43void Cpu_map_code( struct Gb_Cpu* this, addr_t start, int size, void* data )
44{
45 // address range must begin and end on page boundaries
46 require( start % page_size == 0 );
47 require( size % page_size == 0 );
48 require( start + size <= mem_size );
49
50 int offset;
51 for ( offset = 0; offset < size; offset += page_size )
52 set_code_page( this, (start + offset) >> page_bits, STATIC_CAST(char*,data) + offset );
53}
diff --git a/apps/codecs/libgme/gb_cpu.h b/apps/codecs/libgme/gb_cpu.h
new file mode 100644
index 0000000000..3a3b1d6101
--- /dev/null
+++ b/apps/codecs/libgme/gb_cpu.h
@@ -0,0 +1,80 @@
1// Nintendo Game Boy CPU emulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef GB_CPU_H
5#define GB_CPU_H
6
7#include "blargg_common.h"
8#include "blargg_source.h"
9
10typedef int addr_t;
11
12// Emulator reads this many bytes past end of a page
13enum { cpu_padding = 8 };
14enum { mem_size = 0x10000 };
15enum { page_bits = 13 };
16enum { page_size = 1 << page_bits };
17enum { page_count = mem_size >> page_bits };
18
19// Game Boy Z-80 registers. NOT kept updated during emulation.
20struct core_regs_t {
21 uint16_t bc, de, hl, fa;
22};
23
24struct registers_t {
25 int pc; // more than 16 bits to allow overflow detection
26 uint16_t sp;
27
28 struct core_regs_t rp;
29};
30
31struct cpu_state_t {
32 byte* code_map [page_count + 1];
33 int time;
34};
35
36struct Gb_Cpu {
37 // Base address for RST vectors, to simplify GBS player (normally 0)
38 addr_t rst_base;
39
40 struct registers_t r;
41 struct cpu_state_t* cpu_state; // points to state_ or a local copy within run()
42 struct cpu_state_t cpu_state_;
43};
44
45// Initializes Gb cpu
46static inline void Cpu_init( struct Gb_Cpu* this )
47{
48 this->rst_base = 0;
49 this->cpu_state = &this->cpu_state_;
50}
51
52// Clears registers and map all pages to unmapped
53void Cpu_reset( struct Gb_Cpu* this, void* unmapped );
54
55// Maps code memory (memory accessed via the program counter). Start and size
56// must be multiple of page_size.
57void Cpu_map_code( struct Gb_Cpu* this, addr_t start, int size, void* code ) ICODE_ATTR;
58
59// Current time.
60static inline int Cpu_time( struct Gb_Cpu* this ) { return this->cpu_state->time; }
61
62// Changes time. Must not be called during emulation.
63// Should be negative, because emulation stops once it becomes >= 0.
64static inline void Cpu_set_time( struct Gb_Cpu* this, int t ) { this->cpu_state->time = t; }
65
66#define GB_CPU_PAGE( addr ) ((unsigned) (addr) >> page_bits)
67
68#ifdef BLARGG_NONPORTABLE
69 #define GB_CPU_OFFSET( addr ) (addr)
70#else
71 #define GB_CPU_OFFSET( addr ) ((addr) & (page_size - 1))
72#endif
73
74// Accesses emulated memory as CPU does
75static inline uint8_t* Cpu_get_code( struct Gb_Cpu* this, addr_t addr )
76{
77 return this->cpu_state_.code_map [GB_CPU_PAGE( addr )] + GB_CPU_OFFSET( addr );
78}
79
80#endif
diff --git a/apps/codecs/libgme/gb_cpu_run.h b/apps/codecs/libgme/gb_cpu_run.h
new file mode 100644
index 0000000000..86f06fa859
--- /dev/null
+++ b/apps/codecs/libgme/gb_cpu_run.h
@@ -0,0 +1,1187 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#if 0
4/* Define these macros in the source file before #including this file.
5- Parameters might be expressions, so they are best evaluated only once,
6though they NEVER have side-effects, so multiple evaluation is OK.
7- Output parameters might be a multiple-assignment expression like "a=x",
8so they must NOT be parenthesized.
9- Macros "returning" void may use a {} statement block. */
10
11 // 0 <= addr <= 0xFFFF + page_size
12 // time functions can be used
13 int READ_MEM( addr_t );
14 void WRITE_MEM( addr_t, int data );
15
16 // Access of 0xFF00 + offset
17 // 0 <= offset <= 0xFF
18 int READ_IO( int offset );
19 void WRITE_IO( int offset, int data );
20
21 // Often-used instructions use this instead of READ_MEM
22 void READ_FAST( addr_t, int& out );
23
24// The following can be used within macros:
25
26 // Current time
27 cpu_time_t TIME();
28#endif
29
30/* Copyright (C) 2003-2009 Shay Green. This module is free software; you
31can redistribute it and/or modify it under the terms of the GNU Lesser
32General Public License as published by the Free Software Foundation; either
33version 2.1 of the License, or (at your option) any later version. This
34module is distributed in the hope that it will be useful, but WITHOUT ANY
35WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
36FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
37details. You should have received a copy of the GNU Lesser General Public
38License along with this module; if not, write to the Free Software Foundation,
39Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
40
41// Common instructions:
42//
43// 365880 FA LD A,(nn)
44// 355863 20 JR NZ
45// 313655 21 LD HL,nn
46// 274580 28 JR Z
47// 252878 FE CP n
48// 230541 7E LD A,(HL)
49// 226209 2A LD A,(HL+)
50// 217467 CD CALL
51// 212034 C9 RET
52// 208376 CB CB prefix
53//
54// 27486 CB 7E BIT 7,(HL)
55// 15925 CB 76 BIT 6,(HL)
56// 13035 CB 19 RR C
57// 11557 CB 7F BIT 7,A
58// 10898 CB 37 SWAP A
59// 10208 CB 66 BIT 4,(HL)
60
61// Allows MWCW debugger to step through code properly
62#ifdef CPU_BEGIN
63 CPU_BEGIN
64#endif
65
66#define TIME() s.time
67
68#define CODE_PAGE( addr ) s.code_map [GB_CPU_PAGE( addr )]
69#define READ_CODE( addr ) (CODE_PAGE( addr ) [GB_CPU_OFFSET( addr )])
70
71// Flags with hex value for clarity when used as mask.
72// Stored in indicated variable during emulation.
73int const z80 = 0x80; // cz
74int const n40 = 0x40; // ph
75int const h20 = 0x20; // ph
76int const c10 = 0x10; // cz
77
78#define SET_FLAGS( in )\
79{\
80 cz = ((in) << 4 & 0x100) + (~(in) >> 7 & 1);\
81 ph = (~(in) << 2 & 0x100) + ((in) >> 1 & 0x10);\
82}
83
84// random bits in cz to catch misuse of them
85#define SET_FLAGS_DEBUG( in )\
86{\
87 cz = ((in) << 4 & 0x100) | (rand() & ~0x1FF) | ((in) & 0x80 ? 0 : (rand() & 0xFF) | 1);\
88 ph = (~(in) << 2 & 0x100) | (((in) >> 1 & 0x10) ^ BYTE( cz ));\
89}
90
91#define GET_FLAGS( out )\
92{\
93 out = (cz >> 4 & c10);\
94 out += ~ph >> 2 & n40;\
95 out += (ph ^ cz) << 1 & h20;\
96 if ( !BYTE( cz ) )\
97 out += z80;\
98}
99
100#define CC_NZ() ( BYTE( cz ))
101#define CC_Z() (!BYTE( cz ))
102#define CC_NC() (!(cz & 0x100))
103#define CC_C() ( cz & 0x100 )
104
105// Truncation
106#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */
107#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */
108#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */
109
110{
111 struct cpu_state_t s;
112 cpu->cpu_state = &s;
113 memcpy( &s, &cpu->cpu_state_, sizeof s );
114
115 union {
116 struct {
117 #ifdef BLARGG_BIG_ENDIAN
118 byte b, c, d, e, h, l, flags, a;
119 #else
120 byte c, b, e, d, l, h, a, flags;
121 #endif
122 } rg; // individual registers
123 struct core_regs_t rp; // pairs
124
125 byte r8_ [8]; // indexed registers (use R8 macro due to endian dependence)
126 uint16_t r16 [4]; // indexed pairs
127 } reg;
128 BOOST_STATIC_ASSERT( sizeof reg.rg == 8 && sizeof reg.rp == 8 );
129
130 #ifdef BLARGG_BIG_ENDIAN
131 #define R8( n ) (reg.r8_ [n])
132 #elif BLARGG_LITTLE_ENDIAN
133 #define R8( n ) (reg.r8_ [(n) ^ 1])
134 #else
135 // Be sure "blargg_endian.h" has been #included in the file that #includes this
136 #error "Byte order of CPU must be known"
137 #endif
138
139 #define R16( n ) (reg.r16 [n])
140 #define RG (reg.rg)
141 #define RP (reg.rp)
142
143 RP = cpu->r.rp;
144 int pc = cpu->r.pc;
145 int sp = cpu->r.sp;
146 int ph;
147 int cz;
148 SET_FLAGS( RG.flags );
149
150 int time = s.time;
151
152loop:
153
154 check( (unsigned) pc < 0x10000 + 1 ); // +1 so emulator can catch wrap-around
155 check( (unsigned) sp < 0x10000 );
156
157 byte const* instr = CODE_PAGE( pc );
158 int op;
159
160 if ( GB_CPU_OFFSET(~0) == ~0 )
161 {
162 op = instr [pc];
163 pc++;
164 instr += pc;
165 }
166 else
167 {
168 instr += GB_CPU_OFFSET( pc );
169 op = *instr++;
170 pc++;
171 }
172
173#define GET_ADDR() GET_LE16( instr )
174
175 static byte const instr_times [256*2] ICONST_ATTR = {
176 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
177 4,12, 8, 8, 4, 4, 8, 4,20, 8, 8, 8, 4, 4, 8, 4,// 0
178 4,12, 8, 8, 4, 4, 8, 4,12, 8, 8, 8, 4, 4, 8, 4,// 1
179 8,12, 8, 8, 4, 4, 8, 4, 8, 8, 8, 8, 4, 4, 8, 4,// 2
180 8,12, 8, 8,12,12,12, 4, 8, 8, 8, 8, 4, 4, 8, 4,// 3
181 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// 4
182 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// 5
183 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// 6
184 8, 8, 8, 8, 8, 8, 0, 8, 4, 4, 4, 4, 4, 4, 8, 4,// 7
185 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// 8
186 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// 9
187 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// A
188 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// B
189 8,12,16,16,12,16, 8,16, 8,16,16, 0,12,24, 8,16,// C
190 8,12,16, 0,12,16, 8,16, 8,16,16, 0,12, 0, 8,16,// D
191 12,12, 8, 0, 0,16, 8,16,16, 4,16, 0, 0, 0, 8,16,// E
192 12,12, 8, 4, 0,16, 8,16,12, 8,16, 4, 0, 0, 8,16,// F
193
194 // CB prefixed
195 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
196 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 0
197 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 1
198 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 2
199 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 3
200 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,// 4
201 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,// 5
202 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,// 6
203 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,// 7
204 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 8
205 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 9
206 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// A
207 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// B
208 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// C
209 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// D
210 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// E
211 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// F
212 };
213
214 if ( time >= 0 )
215 goto stop;
216
217 time += instr_times [op];
218
219 int data;
220 data = *instr;
221 s.time = time;
222
223 #ifdef CPU_INSTR_HOOK
224 { CPU_INSTR_HOOK( (pc-1), (instr-1), rg.a, rp.bc, rp.de, rp.hl, sp ); }
225 #endif
226
227 switch ( op )
228 {
229
230// TODO: more efficient way to handle negative branch that wraps PC around
231#define BRANCH_( cond, clocks )\
232{\
233 pc++;\
234 if ( !(cond) )\
235 goto loop;\
236 pc = WORD( pc + SBYTE( data ) );\
237 time += clocks;\
238 goto loop;\
239}
240
241#define BRANCH( cond ) BRANCH_( cond, 4 )
242
243// Most Common
244
245 case 0x20: // JR NZ
246 BRANCH( CC_NZ() )
247
248 case 0x21: // LD HL,IMM (common)
249 RP.hl = GET_ADDR();
250 pc += 2;
251 goto loop;
252
253 case 0x28: // JR Z
254 BRANCH( CC_Z() )
255
256 case 0xF2: // LD A,(0xFF00+C)
257 READ_IO( this, RG.c, RG.a );
258 goto loop;
259
260 case 0xF0: // LD A,(0xFF00+imm)
261 pc++;
262 READ_IO( this, data, RG.a );
263 goto loop;
264
265 {
266 int temp;
267 case 0x0A: // LD A,(BC)
268 temp = RP.bc;
269 goto ld_a_ind_comm;
270
271 case 0x3A: // LD A,(HL-)
272 temp = RP.hl;
273 RP.hl = temp - 1;
274 goto ld_a_ind_comm;
275
276 case 0x1A: // LD A,(DE)
277 temp = RP.de;
278 goto ld_a_ind_comm;
279
280 case 0x2A: // LD A,(HL+) (common)
281 temp = RP.hl;
282 RP.hl = temp + 1;
283 goto ld_a_ind_comm;
284
285 case 0xFA: // LD A,IND16 (common)
286 temp = GET_ADDR();
287 pc += 2;
288 ld_a_ind_comm:
289 READ_FAST( this, temp, RG.a );
290 goto loop;
291 }
292
293 {
294 int temp;
295 case 0xBE: // CP (HL)
296 temp = READ_MEM( this, RP.hl );
297 goto cmp_comm;
298
299 case 0xB8: // CP B
300 case 0xB9: // CP C
301 case 0xBA: // CP D
302 case 0xBB: // CP E
303 case 0xBC: // CP H
304 case 0xBD: // CP L
305 case 0xBF: // CP A
306 temp = R8( op & 7 );
307 cmp_comm:
308 ph = RG.a ^ temp; // N=1 H=*
309 cz = RG.a - temp; // C=* Z=*
310 goto loop;
311 }
312
313 case 0xFE: // CP IMM
314 pc++;
315 ph = RG.a ^ data; // N=1 H=*
316 cz = RG.a - data; // C=* Z=*
317 goto loop;
318
319 case 0x46: // LD B,(HL)
320 case 0x4E: // LD C,(HL)
321 case 0x56: // LD D,(HL)
322 case 0x5E: // LD E,(HL)
323 case 0x66: // LD H,(HL)
324 case 0x6E: // LD L,(HL)
325 case 0x7E:{// LD A,(HL)
326 int addr = RP.hl;
327 READ_FAST( this, addr, R8( op >> 3 & 7 ) );
328 goto loop;
329 }
330
331 case 0xC4: // CNZ (next-most-common)
332 pc += 2;
333 if ( CC_Z() )
334 goto loop;
335 call:
336 time += 12;
337 pc -= 2;
338 case 0xCD: // CALL (most-common)
339 data = pc + 2;
340 pc = GET_ADDR();
341 push: {
342 int addr = WORD( sp - 1 );
343 WRITE_MEM( this, addr, (data >> 8) );
344 sp = WORD( sp - 2 );
345 WRITE_MEM( this, sp, data );
346 goto loop;
347 }
348
349 case 0xC8: // RET Z (next-most-common)
350 if ( CC_NZ() )
351 goto loop;
352 ret:
353 time += 12;
354 case 0xD9: // RETI
355 case 0xC9:{// RET (most common)
356 pc = READ_MEM( this, sp );
357 int addr = sp + 1;
358 sp = WORD( sp + 2 );
359 pc += 0x100 * READ_MEM( this, addr );
360 goto loop;
361 }
362
363 case 0x00: // NOP
364 case 0x40: // LD B,B
365 case 0x49: // LD C,C
366 case 0x52: // LD D,D
367 case 0x5B: // LD E,E
368 case 0x64: // LD H,H
369 case 0x6D: // LD L,L
370 case 0x7F: // LD A,A
371 goto loop;
372
373// CB Instructions
374
375 case 0xCB:
376 time += (instr_times + 256) [data];
377 pc++;
378 // now data is the opcode
379 switch ( data ) {
380
381 case 0x46: // BIT b,(HL)
382 case 0x4E:
383 case 0x56:
384 case 0x5E:
385 case 0x66:
386 case 0x6E:
387 case 0x76:
388 case 0x7E: {
389 int addr = RP.hl;
390 READ_FAST( this, addr, op );
391 goto bit_comm;
392 }
393
394 case 0x40: case 0x41: case 0x42: case 0x43: // BIT b,r
395 case 0x44: case 0x45: case 0x47: case 0x48:
396 case 0x49: case 0x4A: case 0x4B: case 0x4C:
397 case 0x4D: case 0x4F: case 0x50: case 0x51:
398 case 0x52: case 0x53: case 0x54: case 0x55:
399 case 0x57: case 0x58: case 0x59: case 0x5A:
400 case 0x5B: case 0x5C: case 0x5D: case 0x5F:
401 case 0x60: case 0x61: case 0x62: case 0x63:
402 case 0x64: case 0x65: case 0x67: case 0x68:
403 case 0x69: case 0x6A: case 0x6B: case 0x6C:
404 case 0x6D: case 0x6F: case 0x70: case 0x71:
405 case 0x72: case 0x73: case 0x74: case 0x75:
406 case 0x77: case 0x78: case 0x79: case 0x7A:
407 case 0x7B: case 0x7C: case 0x7D: case 0x7F:
408 op = R8( data & 7 );
409 bit_comm:
410 ph = op >> (data >> 3 & 7) & 1;
411 cz = (cz & 0x100) + ph;
412 ph ^= 0x110; // N=0 H=1
413 goto loop;
414
415 case 0x86: // RES b,(HL)
416 case 0x8E:
417 case 0x96:
418 case 0x9E:
419 case 0xA6:
420 case 0xAE:
421 case 0xB6:
422 case 0xBE: {
423 int temp = READ_MEM( this, RP.hl );
424 temp &= ~(1 << (data >> 3 & 7));
425 WRITE_MEM( this, RP.hl, temp );
426 goto loop;
427 }
428
429 case 0xC6: // SET b,(HL)
430 case 0xCE:
431 case 0xD6:
432 case 0xDE:
433 case 0xE6:
434 case 0xEE:
435 case 0xF6:
436 case 0xFE: {
437 int temp = READ_MEM( this, RP.hl );
438 temp |= 1 << (data >> 3 & 7);
439 WRITE_MEM( this, RP.hl, temp );
440 goto loop;
441 }
442
443 case 0xC0: case 0xC1: case 0xC2: case 0xC3: // SET b,r
444 case 0xC4: case 0xC5: case 0xC7: case 0xC8:
445 case 0xC9: case 0xCA: case 0xCB: case 0xCC:
446 case 0xCD: case 0xCF: case 0xD0: case 0xD1:
447 case 0xD2: case 0xD3: case 0xD4: case 0xD5:
448 case 0xD7: case 0xD8: case 0xD9: case 0xDA:
449 case 0xDB: case 0xDC: case 0xDD: case 0xDF:
450 case 0xE0: case 0xE1: case 0xE2: case 0xE3:
451 case 0xE4: case 0xE5: case 0xE7: case 0xE8:
452 case 0xE9: case 0xEA: case 0xEB: case 0xEC:
453 case 0xED: case 0xEF: case 0xF0: case 0xF1:
454 case 0xF2: case 0xF3: case 0xF4: case 0xF5:
455 case 0xF7: case 0xF8: case 0xF9: case 0xFA:
456 case 0xFB: case 0xFC: case 0xFD: case 0xFF:
457 R8( data & 7 ) |= 1 << (data >> 3 & 7);
458 goto loop;
459
460 case 0x80: case 0x81: case 0x82: case 0x83: // RES b,r
461 case 0x84: case 0x85: case 0x87: case 0x88:
462 case 0x89: case 0x8A: case 0x8B: case 0x8C:
463 case 0x8D: case 0x8F: case 0x90: case 0x91:
464 case 0x92: case 0x93: case 0x94: case 0x95:
465 case 0x97: case 0x98: case 0x99: case 0x9A:
466 case 0x9B: case 0x9C: case 0x9D: case 0x9F:
467 case 0xA0: case 0xA1: case 0xA2: case 0xA3:
468 case 0xA4: case 0xA5: case 0xA7: case 0xA8:
469 case 0xA9: case 0xAA: case 0xAB: case 0xAC:
470 case 0xAD: case 0xAF: case 0xB0: case 0xB1:
471 case 0xB2: case 0xB3: case 0xB4: case 0xB5:
472 case 0xB7: case 0xB8: case 0xB9: case 0xBA:
473 case 0xBB: case 0xBC: case 0xBD: case 0xBF:
474 R8( data & 7 ) &= ~(1 << (data >> 3 & 7));
475 goto loop;
476
477 case 0x36: // SWAP (HL)
478 op = READ_MEM( this, RP.hl );
479 goto swap_comm;
480
481 case 0x30: // SWAP B
482 case 0x31: // SWAP C
483 case 0x32: // SWAP D
484 case 0x33: // SWAP E
485 case 0x34: // SWAP H
486 case 0x35: // SWAP L
487 case 0x37: // SWAP A
488 op = R8( data & 7 );
489 swap_comm:
490 op = (op >> 4) + (op << 4);
491 cz = BYTE( op );
492 ph = cz + 0x100;
493 if ( data == 0x36 )
494 goto write_hl_op_ff;
495 R8( data & 7 ) = op;
496 goto loop;
497
498// Shift/Rotate
499
500 case 0x26: // SLA (HL)
501 cz = 0;
502 case 0x16: // RL (HL)
503 cz = (cz >> 8 & 1) + (READ_MEM( this, RP.hl ) << 1);
504 goto rl_hl_common;
505
506 case 0x06: // RLC (HL)
507 cz = READ_MEM( this, RP.hl );
508 cz = (cz << 1) + (cz >> 7 & 1);
509 rl_hl_common:
510 // Z=* C=*
511 ph = cz | 0x100; // N=0 H=0
512 WRITE_MEM( this, RP.hl, cz );
513 goto loop;
514
515 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x27: // SLA r
516 cz = 0;
517 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x17: // RL r
518 cz = (cz >> 8 & 1) + (R8( data & 7 ) << 1);
519 goto rl_common;
520
521 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x07: // RLC r
522 cz = R8( data & 7 );
523 cz = (cz << 1) + (cz >> 7 & 1);
524 rl_common:
525 // Z=* C=*
526 ph = cz | 0x100; // N=0 H=0
527 R8( data & 7 ) = cz;
528 goto loop;
529
530 case 0x0E: // RRC (HL)
531 cz = READ_MEM( this, RP.hl );
532 cz += cz << 8 & 0x100;
533 goto rr_hl_common;
534
535 case 0x2E: // SRA (HL)
536 cz = READ_MEM( this, RP.hl );
537 cz += cz << 1 & 0x100;
538 goto rr_hl_common;
539
540 case 0x3E: // SRL (HL)
541 cz = 0;
542 case 0x1E: // RR (HL)
543 cz = (cz & 0x100) + READ_MEM( this, RP.hl );
544 rr_hl_common:
545 cz = (cz << 8) + (cz >> 1); // Z=* C=*
546 ph = cz | 0x100; // N=0 H=0
547 WRITE_MEM( this, RP.hl, cz );
548 goto loop;
549
550 case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0F: // RRC r
551 cz = R8( data & 7 );
552 cz += cz << 8 & 0x100;
553 goto rr_common;
554
555 case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2F: // SRA r
556 cz = R8( data & 7 );
557 cz += cz << 1 & 0x100;
558 goto rr_common;
559
560 case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3F: // SRL r
561 cz = 0;
562 case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1F: // RR r
563 cz = (cz & 0x100) + R8( data & 7 );
564 rr_common:
565 cz = (cz << 8) + (cz >> 1); // Z=* C=*
566 ph = cz | 0x100; // N=0 H=0
567 R8( data & 7 ) = cz;
568 goto loop;
569
570 } // CB op
571 assert( false ); // unhandled CB op
572
573 case 0x07: // RLCA
574 cz = RG.a >> 7;
575 goto rlc_common;
576 case 0x17: // RLA
577 cz = cz >> 8 & 1;
578 rlc_common:
579 cz += RG.a << 1;
580 ph = cz | 0x100;
581 RG.a = BYTE( cz );
582 cz |= 1;
583 goto loop;
584
585 case 0x0F: // RRCA
586 ph = RG.a << 8;
587 goto rrc_common;
588 case 0x1F: // RRA
589 ph = cz;
590 rrc_common:
591 cz = (RG.a << 8) + 1; // Z=0 C=*
592 RG.a = ((ph & 0x100) + RG.a) >> 1;
593 ph = 0x100; // N=0 H=0
594 goto loop;
595
596// Load
597
598 case 0x70: // LD (HL),B
599 case 0x71: // LD (HL),C
600 case 0x72: // LD (HL),D
601 case 0x73: // LD (HL),E
602 case 0x74: // LD (HL),H
603 case 0x75: // LD (HL),L
604 case 0x77: // LD (HL),A
605 op = R8( op & 7 );
606 write_hl_op_ff:
607 WRITE_MEM( this, RP.hl, op );
608 goto loop;
609
610 case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x47: // LD r,r
611 case 0x48: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4F:
612 case 0x50: case 0x51: case 0x53: case 0x54: case 0x55: case 0x57:
613 case 0x58: case 0x59: case 0x5A: case 0x5C: case 0x5D: case 0x5F:
614 case 0x60: case 0x61: case 0x62: case 0x63: case 0x65: case 0x67:
615 case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6F:
616 case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D:
617 R8( op >> 3 & 7 ) = R8( op & 7 );
618 goto loop;
619
620 case 0x08: // LD IND16,SP
621 data = GET_ADDR();
622 pc += 2;
623 WRITE_MEM( this, data, sp );
624 data++;
625 WRITE_MEM( this, data, (sp >> 8) );
626 goto loop;
627
628 case 0xF9: // LD SP,HL
629 sp = RP.hl;
630 goto loop;
631
632 case 0x31: // LD SP,IMM
633 sp = GET_ADDR();
634 pc += 2;
635 goto loop;
636
637 case 0x01: // LD BC,IMM
638 case 0x11: // LD DE,IMM
639 R16( (unsigned) op >> 4 ) = GET_ADDR();
640 pc += 2;
641 goto loop;
642
643 case 0xE2: // LD (0xFF00+C),A
644 WRITE_IO( this, RG.c, RG.a );
645 goto loop;
646
647 case 0xE0: // LD (0xFF00+imm),A
648 pc++;
649 WRITE_IO( this, data, RG.a );
650 goto loop;
651
652 {
653 int temp;
654 case 0x32: // LD (HL-),A
655 temp = RP.hl;
656 RP.hl = temp - 1;
657 goto write_data_rg_a;
658
659 case 0x02: // LD (BC),A
660 temp = RP.bc;
661 goto write_data_rg_a;
662
663 case 0x12: // LD (DE),A
664 temp = RP.de;
665 goto write_data_rg_a;
666
667 case 0x22: // LD (HL+),A
668 temp = RP.hl;
669 RP.hl = temp + 1;
670 goto write_data_rg_a;
671
672 case 0xEA: // LD IND16,A (common)
673 temp = GET_ADDR();
674 pc += 2;
675 write_data_rg_a:
676 WRITE_MEM( this, temp, RG.a );
677 goto loop;
678 }
679
680 case 0x06: // LD B,IMM
681 RG.b = data;
682 pc++;
683 goto loop;
684
685 case 0x0E: // LD C,IMM
686 RG.c = data;
687 pc++;
688 goto loop;
689
690 case 0x16: // LD D,IMM
691 RG.d = data;
692 pc++;
693 goto loop;
694
695 case 0x1E: // LD E,IMM
696 RG.e = data;
697 pc++;
698 goto loop;
699
700 case 0x26: // LD H,IMM
701 RG.h = data;
702 pc++;
703 goto loop;
704
705 case 0x2E: // LD L,IMM
706 RG.l = data;
707 pc++;
708 goto loop;
709
710 case 0x36: // LD (HL),IMM
711 WRITE_MEM( this, RP.hl, data );
712 pc++;
713 goto loop;
714
715 case 0x3E: // LD A,IMM
716 RG.a = data;
717 pc++;
718 goto loop;
719
720// Increment/decrement
721
722 case 0x03: // INC BC
723 case 0x13: // INC DE
724 case 0x23: // INC HL
725 R16( (unsigned) op >> 4 )++;
726 goto loop;
727
728 case 0x33: // INC SP
729 sp = WORD( sp + 1 );
730 goto loop;
731
732 case 0x0B: // DEC BC
733 case 0x1B: // DEC DE
734 case 0x2B: // DEC HL
735 R16( (unsigned) op >> 4 )--;
736 goto loop;
737
738 case 0x3B: // DEC SP
739 sp = WORD( sp - 1 );
740 goto loop;
741
742 case 0x34: // INC (HL)
743 op = RP.hl;
744 data = READ_MEM( this, op );
745 data++;
746 WRITE_MEM( this, op, data );
747 goto inc_comm;
748
749 case 0x04: // INC B
750 case 0x0C: // INC C (common)
751 case 0x14: // INC D
752 case 0x1C: // INC E
753 case 0x24: // INC H
754 case 0x2C: // INC L
755 case 0x3C: // INC A
756 op = op >> 3 & 7;
757 data = R8( op ) + 1;
758 R8( op ) = data;
759 inc_comm:
760 ph = data - 0x101; // N=0 H=*
761 cz = (cz & 0x100) + BYTE( data ); // C=- Z=*
762 goto loop;
763
764 case 0x35: // DEC (HL)
765 op = RP.hl;
766 data = READ_MEM( this, op );
767 data--;
768 WRITE_MEM( this, op, data );
769 goto dec_comm;
770
771 case 0x05: // DEC B
772 case 0x0D: // DEC C
773 case 0x15: // DEC D
774 case 0x1D: // DEC E
775 case 0x25: // DEC H
776 case 0x2D: // DEC L
777 case 0x3D: // DEC A
778 op = op >> 3 & 7;
779 data = R8( op ) - 1;
780 R8( op ) = data;
781 dec_comm:
782 ph = data + 1; // N=1 H=*
783 cz = (cz & 0x100) + BYTE( data ); // C=- Z=*
784 goto loop;
785
786// Add 16-bit
787
788 case 0xF8: // LD HL,SP+n
789 case 0xE8:{// ADD SP,n
790 pc++;
791 int t = WORD( sp + SBYTE( data ) );
792 cz = ((BYTE( sp ) + data) & 0x100) + 1; // Z=0 C=*
793 ph = (sp ^ data ^ t) | 0x100; // N=0 H=*
794 if ( op == 0xF8 )
795 {
796 RP.hl = t;
797 goto loop;
798 }
799 sp = t;
800 goto loop;
801 }
802
803 case 0x39: // ADD HL,SP
804 data = sp;
805 goto add_hl_comm;
806
807 case 0x09: // ADD HL,BC
808 case 0x19: // ADD HL,DE
809 case 0x29: // ADD HL,HL
810 data = R16( (unsigned) op >> 4 );
811 add_hl_comm:
812 ph = RP.hl ^ data;
813 data += RP.hl;
814 RP.hl = WORD( data );
815 ph ^= data;
816 cz = BYTE( cz ) + (data >> 8 & 0x100); // C=* Z=-
817 ph = ((ph >> 8) ^ cz) | 0x100; // N=0 H=*
818 goto loop;
819
820 case 0x86: // ADD (HL)
821 data = READ_MEM( this, RP.hl );
822 goto add_comm;
823
824 case 0x80: // ADD B
825 case 0x81: // ADD C
826 case 0x82: // ADD D
827 case 0x83: // ADD E
828 case 0x84: // ADD H
829 case 0x85: // ADD L
830 case 0x87: // ADD A
831 data = R8( op & 7 );
832 goto add_comm;
833
834 case 0xC6: // ADD IMM
835 pc++;
836 add_comm:
837 ph = (RG.a ^ data) | 0x100; // N=1 H=*
838 cz = RG.a + data; // C=* Z=*
839 RG.a = cz;
840 goto loop;
841
842// Add/Subtract
843
844 case 0x8E: // ADC (HL)
845 data = READ_MEM( this, RP.hl );
846 goto adc_comm;
847
848 case 0x88: // ADC B
849 case 0x89: // ADC C
850 case 0x8A: // ADC D
851 case 0x8B: // ADC E
852 case 0x8C: // ADC H
853 case 0x8D: // ADC L
854 case 0x8F: // ADC A
855 data = R8( op & 7 );
856 goto adc_comm;
857
858 case 0xCE: // ADC IMM
859 pc++;
860 adc_comm:
861 ph = (RG.a ^ data) | 0x100; // N=1 H=*
862 cz = RG.a + data + (cz >> 8 & 1); // C=* Z=*
863 RG.a = cz;
864 goto loop;
865
866 case 0x96: // SUB (HL)
867 data = READ_MEM( this, RP.hl );
868 goto sub_comm;
869
870 case 0x90: // SUB B
871 case 0x91: // SUB C
872 case 0x92: // SUB D
873 case 0x93: // SUB E
874 case 0x94: // SUB H
875 case 0x95: // SUB L
876 case 0x97: // SUB A
877 data = R8( op & 7 );
878 goto sub_comm;
879
880 case 0xD6: // SUB IMM
881 pc++;
882 sub_comm:
883 ph = RG.a ^ data; // N=1 H=*
884 cz = RG.a - data; // C=* Z=*
885 RG.a = cz;
886 goto loop;
887
888 case 0x9E: // SBC (HL)
889 data = READ_MEM( this, RP.hl );
890 goto sbc_comm;
891
892 case 0x98: // SBC B
893 case 0x99: // SBC C
894 case 0x9A: // SBC D
895 case 0x9B: // SBC E
896 case 0x9C: // SBC H
897 case 0x9D: // SBC L
898 case 0x9F: // SBC A
899 data = R8( op & 7 );
900 goto sbc_comm;
901
902 case 0xDE: // SBC IMM
903 pc++;
904 sbc_comm:
905 ph = RG.a ^ data; // N=1 H=*
906 cz = RG.a - data - (cz >> 8 & 1); // C=* Z=*
907 RG.a = cz;
908 goto loop;
909
910// Logical
911
912 case 0xA0: // AND B
913 case 0xA1: // AND C
914 case 0xA2: // AND D
915 case 0xA3: // AND E
916 case 0xA4: // AND H
917 case 0xA5: // AND L
918 data = R8( op & 7 );
919 goto and_comm;
920
921 case 0xA6: // AND (HL)
922 data = READ_MEM( this, RP.hl );
923 goto and_comm;
924 case 0xE6: // AND IMM
925 pc++;
926 and_comm:
927 cz = RG.a & data; // C=0 Z=*
928 ph = ~cz; // N=0 H=1
929 RG.a = cz;
930 goto loop;
931
932 case 0xA7: // AND A
933 cz = RG.a; // C=0 Z=*
934 ph = ~RG.a; // N=0 H=1
935 goto loop;
936
937 case 0xB0: // OR B
938 case 0xB1: // OR C
939 case 0xB2: // OR D
940 case 0xB3: // OR E
941 case 0xB4: // OR H
942 case 0xB5: // OR L
943 data = R8( op & 7 );
944 goto or_comm;
945
946 case 0xB6: // OR (HL)
947 data = READ_MEM( this, RP.hl );
948 goto or_comm;
949 case 0xF6: // OR IMM
950 pc++;
951 or_comm:
952 cz = RG.a | data; // C=0 Z=*
953 ph = cz | 0x100; // N=0 H=0
954 RG.a = cz;
955 goto loop;
956
957 case 0xB7: // OR A
958 cz = RG.a; // C=0 Z=*
959 ph = RG.a + 0x100; // N=0 H=0
960 goto loop;
961
962 case 0xA8: // XOR B
963 case 0xA9: // XOR C
964 case 0xAA: // XOR D
965 case 0xAB: // XOR E
966 case 0xAC: // XOR H
967 case 0xAD: // XOR L
968 data = R8( op & 7 );
969 goto xor_comm;
970
971 case 0xAE: // XOR (HL)
972 data = READ_MEM( this, RP.hl );
973 pc--;
974 case 0xEE: // XOR IMM
975 pc++;
976 xor_comm:
977 cz = RG.a ^ data; // C=0 Z=*
978 ph = cz + 0x100; // N=0 H=0
979 RG.a = cz;
980 goto loop;
981
982 case 0xAF: // XOR A
983 RG.a = 0;
984 cz = 0; // C=0 Z=*
985 ph = 0x100; // N=0 H=0
986 goto loop;
987
988// Stack
989
990 case 0xF1: // POP AF
991 case 0xC1: // POP BC
992 case 0xD1: // POP DE
993 case 0xE1: // POP HL (common)
994 data = READ_MEM( this, sp );
995 R16( op >> 4 & 3 ) = data + 0x100 * READ_MEM( this, (sp + 1) );
996 sp = WORD( sp + 2 );
997 if ( op != 0xF1 )
998 goto loop;
999
1000 SET_FLAGS( RG.a );
1001 RG.a = RG.flags;
1002 goto loop;
1003
1004 case 0xC5: // PUSH BC
1005 data = RP.bc;
1006 goto push;
1007
1008 case 0xD5: // PUSH DE
1009 data = RP.de;
1010 goto push;
1011
1012 case 0xE5: // PUSH HL
1013 data = RP.hl;
1014 goto push;
1015
1016 case 0xF5: // PUSH AF
1017 GET_FLAGS( data );
1018 data += RG.a << 8;
1019 goto push;
1020
1021// Flow control
1022
1023 case 0xFF: case 0xC7: case 0xCF: case 0xD7: // RST
1024 case 0xDF: case 0xE7: case 0xEF: case 0xF7:
1025 data = pc;
1026 pc = (op & 0x38) + cpu->rst_base;
1027 goto push;
1028
1029 case 0xCC: // CALL Z
1030 pc += 2;
1031 if ( CC_Z() )
1032 goto call;
1033 goto loop;
1034
1035 case 0xD4: // CALL NC
1036 pc += 2;
1037 if ( CC_NC() )
1038 goto call;
1039 goto loop;
1040
1041 case 0xDC: // CALL C
1042 pc += 2;
1043 if ( CC_C() )
1044 goto call;
1045 goto loop;
1046
1047 case 0xC0: // RET NZ
1048 if ( CC_NZ() )
1049 goto ret;
1050 goto loop;
1051
1052 case 0xD0: // RET NC
1053 if ( CC_NC() )
1054 goto ret;
1055 goto loop;
1056
1057 case 0xD8: // RET C
1058 if ( CC_C() )
1059 goto ret;
1060 goto loop;
1061
1062 case 0x18: // JR
1063 BRANCH_( true, 0 )
1064
1065 case 0x30: // JR NC
1066 BRANCH( CC_NC() )
1067
1068 case 0x38: // JR C
1069 BRANCH( CC_C() )
1070
1071 case 0xE9: // LD PC,HL
1072 pc = RP.hl;
1073 goto loop;
1074
1075 case 0xC3: // JP (next-most-common)
1076 pc = GET_ADDR();
1077 goto loop;
1078
1079 case 0xC2: // JP NZ
1080 pc += 2;
1081 if ( CC_NZ() )
1082 goto jp_taken;
1083 time -= 4;
1084 goto loop;
1085
1086 case 0xCA: // JP Z (most common)
1087 pc += 2;
1088 if ( CC_Z() )
1089 goto jp_taken;
1090 time -= 4;
1091 goto loop;
1092
1093 jp_taken:
1094 pc -= 2;
1095 pc = GET_ADDR();
1096 goto loop;
1097
1098 case 0xD2: // JP NC
1099 pc += 2;
1100 if ( CC_NC() )
1101 goto jp_taken;
1102 time -= 4;
1103 goto loop;
1104
1105 case 0xDA: // JP C
1106 pc += 2;
1107 if ( CC_C() )
1108 goto jp_taken;
1109 time -= 4;
1110 goto loop;
1111
1112// Flags
1113
1114 case 0x2F: // CPL
1115 RG.a = ~RG.a;
1116 ph = BYTE( ~cz ); // N=1 H=1
1117 goto loop;
1118
1119 case 0x3F: // CCF
1120 ph = cz | 0x100; // N=0 H=0
1121 cz ^= 0x100; // C=* Z=-
1122 goto loop;
1123
1124 case 0x37: // SCF
1125 ph = cz | 0x100; // N=0 H=0
1126 cz |= 0x100; // C=1 Z=-
1127 goto loop;
1128
1129 case 0xF3: // DI
1130 goto loop;
1131
1132 case 0xFB: // EI
1133 goto loop;
1134
1135 case 0x27:{// DAA
1136 unsigned a = RG.a;
1137 int h = ph ^ cz;
1138 if ( ph & 0x100 )
1139 {
1140 if ( (h & 0x10) || (a & 0x0F) > 9 )
1141 a += 6;
1142
1143 if ( (cz & 0x100) || a > 0x9F )
1144 a += 0x60;
1145 }
1146 else
1147 {
1148 if ( h & 0x10 )
1149 a = (a - 6) & 0xFF;
1150
1151 if ( cz & 0x100 )
1152 a -= 0x60;
1153 }
1154 cz = (cz & 0x100) | a; // C=- Z=*
1155 RG.a = a;
1156 ph = (ph & 0x100) + BYTE( a ); // N=- H=0
1157 goto loop;
1158 }
1159
1160// Special
1161
1162 case 0x76: // HALT
1163 case 0x10: // STOP
1164 case 0xD3: case 0xDB: case 0xDD: // Illegal
1165 case 0xE3: case 0xE4: case 0xEB: case 0xEC: case 0xED: // (all freeze cpu)
1166 case 0xF4: case 0xFC: case 0xFD:
1167 goto stop;
1168 }
1169
1170 // If this fails then an opcode isn't handled above
1171 assert( false );
1172
1173stop:
1174 pc--;
1175
1176 // copy state back
1177 cpu->cpu_state_.time = time;
1178 cpu->r.pc = pc;
1179 cpu->r.sp = sp;
1180 {
1181 int t;
1182 GET_FLAGS( t );
1183 RG.flags = t;
1184 }
1185 cpu->cpu_state = &cpu->cpu_state_;
1186 cpu->r.rp = RP;
1187}
diff --git a/apps/codecs/libgme/gb_oscs.c b/apps/codecs/libgme/gb_oscs.c
new file mode 100644
index 0000000000..6d607d7f5a
--- /dev/null
+++ b/apps/codecs/libgme/gb_oscs.c
@@ -0,0 +1,787 @@
1// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/
2
3#include "gb_apu.h"
4
5/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18int const cgb_02 = 0; // enables bug in early CGB units that causes problems in some games
19int const cgb_05 = 0; // enables CGB-05 zombie behavior
20
21int const trigger_mask = 0x80;
22int const length_enabled = 0x40;
23
24void Osc_reset( struct Gb_Osc* this )
25{
26 this->output = NULL;
27 this->last_amp = 0;
28 this->delay = 0;
29 this->phase = 0;
30 this->enabled = false;
31}
32
33inline void Osc_update_amp( struct Gb_Osc* this, blip_time_t time, int new_amp )
34{
35 Blip_set_modified( this->output );
36 int delta = new_amp - this->last_amp;
37 if ( delta )
38 {
39 this->last_amp = new_amp;
40 Synth_offset( this->synth, time, delta, this->output );
41 }
42}
43
44// Units
45
46void Osc_clock_length( struct Gb_Osc* this )
47{
48 if ( (this->regs [4] & length_enabled) && this->length_ctr )
49 {
50 if ( --this->length_ctr <= 0 )
51 this->enabled = false;
52 }
53}
54
55void Noise_clock_envelope( struct Gb_Noise* this )
56{
57 if ( this->env_enabled && --this->env_delay <= 0 && Noise_reload_env_timer( this ) )
58 {
59 int v = this->volume + (this->osc.regs [2] & 0x08 ? +1 : -1);
60 if ( 0 <= v && v <= 15 )
61 this->volume = v;
62 else
63 this->env_enabled = false;
64 }
65}
66
67void Square_clock_envelope( struct Gb_Square* this )
68{
69 if ( this->env_enabled && --this->env_delay <= 0 && Square_reload_env_timer( this ) )
70 {
71 int v = this->volume + (this->osc.regs [2] & 0x08 ? +1 : -1);
72 if ( 0 <= v && v <= 15 )
73 this->volume = v;
74 else
75 this->env_enabled = false;
76 }
77}
78
79inline void reload_sweep_timer( struct Gb_Square* this )
80{
81 this->sweep_delay = (this->osc.regs [0] & period_mask) >> 4;
82 if ( !this->sweep_delay )
83 this->sweep_delay = 8;
84}
85
86void calc_sweep( struct Gb_Square* this, bool update )
87{
88 struct Gb_Osc* osc = &this->osc;
89 int const shift = osc->regs [0] & shift_mask;
90 int const delta = this->sweep_freq >> shift;
91 this->sweep_neg = (osc->regs [0] & 0x08) != 0;
92 int const freq = this->sweep_freq + (this->sweep_neg ? -delta : delta);
93
94 if ( freq > 0x7FF )
95 {
96 osc->enabled = false;
97 }
98 else if ( shift && update )
99 {
100 this->sweep_freq = freq;
101
102 osc->regs [3] = freq & 0xFF;
103 osc->regs [4] = (osc->regs [4] & ~0x07) | (freq >> 8 & 0x07);
104 }
105}
106
107void clock_sweep( struct Gb_Square* this )
108{
109 if ( --this->sweep_delay <= 0 )
110 {
111 reload_sweep_timer( this );
112 if ( this->sweep_enabled && (this->osc.regs [0] & period_mask) )
113 {
114 calc_sweep( this, true );
115 calc_sweep( this, false );
116 }
117 }
118}
119
120int wave_access( struct Gb_Wave* this, int addr )
121{
122 if ( this->osc.enabled )
123 {
124 addr = this->osc.phase & (wave_bank_size - 1);
125 if ( this->osc.mode == mode_dmg )
126 {
127 addr++;
128 if ( this->osc.delay > clk_mul )
129 return -1; // can only access within narrow time window while playing
130 }
131 addr >>= 1;
132 }
133 return addr & 0x0F;
134}
135
136// write_register
137
138int write_trig( struct Gb_Osc* this, int frame_phase, int max_len, int old_data )
139{
140 int data = this->regs [4];
141
142 if ( (frame_phase & 1) && !(old_data & length_enabled) && this->length_ctr )
143 {
144 if ( (data & length_enabled) || cgb_02 )
145 this->length_ctr--;
146 }
147
148 if ( data & trigger_mask )
149 {
150 this->enabled = true;
151 if ( !this->length_ctr )
152 {
153 this->length_ctr = max_len;
154 if ( (frame_phase & 1) && (data & length_enabled) )
155 this->length_ctr--;
156 }
157 }
158
159 if ( !this->length_ctr )
160 this->enabled = false;
161
162 return data & trigger_mask;
163}
164
165inline void Noise_zombie_volume( struct Gb_Noise* this, int old, int data )
166{
167 int v = this->volume;
168 if ( this->osc.mode == mode_agb || cgb_05 )
169 {
170 // CGB-05 behavior, very close to AGB behavior as well
171 if ( (old ^ data) & 8 )
172 {
173 if ( !(old & 8) )
174 {
175 v++;
176 if ( old & 7 )
177 v++;
178 }
179
180 v = 16 - v;
181 }
182 else if ( (old & 0x0F) == 8 )
183 {
184 v++;
185 }
186 }
187 else
188 {
189 // CGB-04&02 behavior, very close to MGB behavior as well
190 if ( !(old & 7) && this->env_enabled )
191 v++;
192 else if ( !(old & 8) )
193 v += 2;
194
195 if ( (old ^ data) & 8 )
196 v = 16 - v;
197 }
198 this->volume = v & 0x0F;
199}
200
201inline void Square_zombie_volume( struct Gb_Square* this, int old, int data )
202{
203 int v = this->volume;
204 if ( this->osc.mode == mode_agb || cgb_05 )
205 {
206 // CGB-05 behavior, very close to AGB behavior as well
207 if ( (old ^ data) & 8 )
208 {
209 if ( !(old & 8) )
210 {
211 v++;
212 if ( old & 7 )
213 v++;
214 }
215
216 v = 16 - v;
217 }
218 else if ( (old & 0x0F) == 8 )
219 {
220 v++;
221 }
222 }
223 else
224 {
225 // CGB-04&02 behavior, very close to MGB behavior as well
226 if ( !(old & 7) && this->env_enabled )
227 v++;
228 else if ( !(old & 8) )
229 v += 2;
230
231 if ( (old ^ data) & 8 )
232 v = 16 - v;
233 }
234 this->volume = v & 0x0F;
235}
236
237bool Square_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data )
238{
239 int const max_len = 64;
240
241 switch ( reg )
242 {
243 case 1:
244 this->osc.length_ctr = max_len - (data & (max_len - 1));
245 break;
246
247 case 2:
248 if ( !Square_dac_enabled( this ) )
249 this->osc.enabled = false;
250
251 Square_zombie_volume( this, old_data, data );
252
253 if ( (data & 7) && this->env_delay == 8 )
254 {
255 this->env_delay = 1;
256 Square_clock_envelope( this ); // TODO: really happens at next length clock
257 }
258 break;
259
260 case 4:
261 if ( write_trig( &this->osc, frame_phase, max_len, old_data ) )
262 {
263 this->volume = this->osc.regs [2] >> 4;
264 Square_reload_env_timer( this );
265 this->env_enabled = true;
266 if ( frame_phase == 7 )
267 this->env_delay++;
268 if ( !Square_dac_enabled( this ) )
269 this->osc.enabled = false;
270 this->osc.delay = (this->osc.delay & (4 * clk_mul - 1)) + Square_period( this );
271 return true;
272 }
273 }
274
275 return false;
276}
277
278inline void Noise_write_register( struct Gb_Noise* this, int frame_phase, int reg, int old_data, int data )
279{
280 int const max_len = 64;
281
282 switch ( reg )
283 {
284 case 1:
285 this->osc.length_ctr = max_len - (data & (max_len - 1));
286 break;
287
288 case 2:
289 if ( !Noise_dac_enabled( this ) )
290 this->osc.enabled = false;
291
292 Noise_zombie_volume( this, old_data, data );
293
294 if ( (data & 7) && this->env_delay == 8 )
295 {
296 this->env_delay = 1;
297 Noise_clock_envelope( this ); // TODO: really happens at next length clock
298 }
299 break;
300
301 case 4:
302 if ( write_trig( &this->osc, frame_phase, max_len, old_data ) )
303 {
304 this->volume = this->osc.regs [2] >> 4;
305 Noise_reload_env_timer( this );
306 this->env_enabled = true;
307 if ( frame_phase == 7 )
308 this->env_delay++;
309 if ( !Noise_dac_enabled( this ) )
310 this->osc.enabled = false;
311
312 this->osc.phase = 0x7FFF;
313 this->osc.delay += 8 * clk_mul;
314 }
315 }
316}
317
318inline void Sweep_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data )
319{
320 if ( reg == 0 && this->sweep_enabled && this->sweep_neg && !(data & 0x08) )
321 this->osc.enabled = false; // sweep negate disabled after used
322
323 if ( Square_write_register( this, frame_phase, reg, old_data, data ) )
324 {
325 this->sweep_freq = Osc_frequency( &this->osc );
326 this->sweep_neg = false;
327 reload_sweep_timer( this );
328 this->sweep_enabled = (this->osc.regs [0] & (period_mask | shift_mask)) != 0;
329 if ( this->osc.regs [0] & shift_mask )
330 calc_sweep( this, false );
331 }
332}
333
334void corrupt_wave( struct Gb_Wave* this )
335{
336 int pos = ((this->osc.phase + 1) & (wave_bank_size - 1)) >> 1;
337 if ( pos < 4 )
338 this->wave_ram [0] = this->wave_ram [pos];
339 else {
340 int i;
341 for ( i = 4; --i >= 0; )
342 this->wave_ram [i] = this->wave_ram [(pos & ~3) + i];
343 }
344}
345
346inline void Wave_write_register( struct Gb_Wave* this, int frame_phase, int reg, int old_data, int data )
347{
348 int const max_len = 256;
349
350 switch ( reg )
351 {
352 case 0:
353 if ( !Wave_dac_enabled( this ) )
354 this->osc.enabled = false;
355 break;
356
357 case 1:
358 this->osc.length_ctr = max_len - data;
359 break;
360
361 case 4:
362 {
363 bool was_enabled = this->osc.enabled;
364 if ( write_trig( &this->osc, frame_phase, max_len, old_data ) )
365 {
366 if ( !Wave_dac_enabled( this ) )
367 this->osc.enabled = false;
368 else if ( this->osc.mode == mode_dmg && was_enabled &&
369 (unsigned) (this->osc.delay - 2 * clk_mul) < 2 * clk_mul )
370 corrupt_wave( this );
371
372 this->osc.phase = 0;
373 this->osc.delay = Wave_period( this ) + 6 * clk_mul;
374 }
375 }
376 }
377}
378
379void write_osc( struct Gb_Apu* this, int reg, int old_data, int data )
380{
381 int index = (reg * 3 + 3) >> 4; // avoids divide
382 assert( index == reg / 5 );
383 reg -= index * 5;
384 switch ( index )
385 {
386 case 0: Sweep_write_register ( &this->square1, this->frame_phase, reg, old_data, data ); break;
387 case 1: Square_write_register( &this->square2, this->frame_phase, reg, old_data, data ); break;
388 case 2: Wave_write_register ( &this->wave, this->frame_phase, reg, old_data, data ); break;
389 case 3: Noise_write_register ( &this->noise, this->frame_phase, reg, old_data, data ); break;
390 }
391}
392
393// Synthesis
394
395void Square_run( struct Gb_Square* this, blip_time_t time, blip_time_t end_time )
396{
397 // Calc duty and phase
398 static byte const duty_offsets [4] ICONST_ATTR = { 1, 1, 3, 7 };
399 static byte const duties [4] ICONST_ATTR = { 1, 2, 4, 6 };
400
401 struct Gb_Osc* osc = &this->osc;
402 int const duty_code = osc->regs [1] >> 6;
403 int duty_offset = duty_offsets [duty_code];
404 int duty = duties [duty_code];
405 if ( osc->mode == mode_agb )
406 {
407 // AGB uses inverted duty
408 duty_offset -= duty;
409 duty = 8 - duty;
410 }
411 int ph = (osc->phase + duty_offset) & 7;
412
413 // Determine what will be generated
414 int vol = 0;
415 struct Blip_Buffer* const out = osc->output;
416 if ( out )
417 {
418 int amp = osc->dac_off_amp;
419 if ( Square_dac_enabled( this ) )
420 {
421 if ( osc->enabled )
422 vol = this->volume;
423
424 amp = -dac_bias;
425 if ( osc->mode == mode_agb )
426 amp = -(vol >> 1);
427
428 // Play inaudible frequencies as constant amplitude
429 if ( Osc_frequency( osc ) >= 0x7FA && osc->delay < 32 * clk_mul )
430 {
431 amp += (vol * duty) >> 3;
432 vol = 0;
433 }
434
435 if ( ph < duty )
436 {
437 amp += vol;
438 vol = -vol;
439 }
440 }
441 Osc_update_amp( osc, time, amp );
442 }
443
444 // Generate wave
445 time += osc->delay;
446 if ( time < end_time )
447 {
448 int const per = Square_period( this );
449 if ( !vol )
450 {
451 #ifdef GB_APU_FAST
452 time = end_time;
453 #else
454 // Maintain phase when not playing
455 int count = (end_time - time + per - 1) / per;
456 ph += count; // will be masked below
457 time += (blip_time_t) count * per;
458 #endif
459 }
460 else
461 {
462 // Output amplitude transitions
463 int delta = vol;
464 do
465 {
466 ph = (ph + 1) & 7;
467 if ( ph == 0 || ph == duty )
468 {
469 Synth_offset_inline( osc->synth, time, delta, out );
470 delta = -delta;
471 }
472 time += per;
473 }
474 while ( time < end_time );
475
476 if ( delta != vol )
477 osc->last_amp -= delta;
478 }
479 osc->phase = (ph - duty_offset) & 7;
480 }
481 osc->delay = time - end_time;
482}
483
484#ifndef GB_APU_FAST
485// Quickly runs LFSR for a large number of clocks. For use when noise is generating
486// no sound.
487static unsigned run_lfsr( unsigned s, unsigned mask, int count )
488{
489 bool const optimized = true; // set to false to use only unoptimized loop in middle
490
491 // optimization used in several places:
492 // ((s & (1 << b)) << n) ^ ((s & (1 << b)) << (n + 1)) = (s & (1 << b)) * (3 << n)
493
494 if ( mask == 0x4000 && optimized )
495 {
496 if ( count >= 32767 )
497 count %= 32767;
498
499 // Convert from Fibonacci to Galois configuration,
500 // shifted left 1 bit
501 s ^= (s & 1) * 0x8000;
502
503 // Each iteration is equivalent to clocking LFSR 255 times
504 while ( (count -= 255) > 0 )
505 s ^= ((s & 0xE) << 12) ^ ((s & 0xE) << 11) ^ (s >> 3);
506 count += 255;
507
508 // Each iteration is equivalent to clocking LFSR 15 times
509 // (interesting similarity to single clocking below)
510 while ( (count -= 15) > 0 )
511 s ^= ((s & 2) * (3 << 13)) ^ (s >> 1);
512 count += 15;
513
514 // Remaining singles
515 while ( --count >= 0 )
516 s = ((s & 2) * (3 << 13)) ^ (s >> 1);
517
518 // Convert back to Fibonacci configuration
519 s &= 0x7FFF;
520 }
521 else if ( count < 8 || !optimized )
522 {
523 // won't fully replace upper 8 bits, so have to do the unoptimized way
524 while ( --count >= 0 )
525 s = (s >> 1 | mask) ^ (mask & -((s - 1) & 2));
526 }
527 else
528 {
529 if ( count > 127 )
530 {
531 count %= 127;
532 if ( !count )
533 count = 127; // must run at least once
534 }
535
536 // Need to keep one extra bit of history
537 s = s << 1 & 0xFF;
538
539 // Convert from Fibonacci to Galois configuration,
540 // shifted left 2 bits
541 s ^= (s & 2) * 0x80;
542
543 // Each iteration is equivalent to clocking LFSR 7 times
544 // (interesting similarity to single clocking below)
545 while ( (count -= 7) > 0 )
546 s ^= ((s & 4) * (3 << 5)) ^ (s >> 1);
547 count += 7;
548
549 // Remaining singles
550 while ( --count >= 0 )
551 s = ((s & 4) * (3 << 5)) ^ (s >> 1);
552
553 // Convert back to Fibonacci configuration and
554 // repeat last 8 bits above significant 7
555 s = (s << 7 & 0x7F80) | (s >> 1 & 0x7F);
556 }
557
558 return s;
559}
560#endif
561
562void Noise_run( struct Gb_Noise* this, blip_time_t time, blip_time_t end_time )
563{
564 // Determine what will be generated
565 int vol = 0;
566 struct Gb_Osc* osc = &this->osc;
567 struct Blip_Buffer* const out = osc->output;
568 if ( out )
569 {
570 int amp = osc->dac_off_amp;
571 if ( Noise_dac_enabled( this ) )
572 {
573 if ( osc->enabled )
574 vol = this->volume;
575
576 amp = -dac_bias;
577 if ( osc->mode == mode_agb )
578 amp = -(vol >> 1);
579
580 if ( !(osc->phase & 1) )
581 {
582 amp += vol;
583 vol = -vol;
584 }
585 }
586
587 // AGB negates final output
588 if ( osc->mode == mode_agb )
589 {
590 vol = -vol;
591 amp = -amp;
592 }
593
594 Osc_update_amp( osc, time, amp );
595 }
596
597 // Run timer and calculate time of next LFSR clock
598 static byte const period1s [8] ICONST_ATTR = { 1, 2, 4, 6, 8, 10, 12, 14 };
599 int const period1 = period1s [osc->regs [3] & 7] * clk_mul;
600
601 #ifdef GB_APU_FAST
602 time += delay;
603 #else
604 {
605 int extra = (end_time - time) - osc->delay;
606 int const per2 = period2( this, 8 );
607 time += osc->delay + ((this->divider ^ (per2 >> 1)) & (per2 - 1)) * period1;
608
609 int count = (extra < 0 ? 0 : (extra + period1 - 1) / period1);
610 this->divider = (this->divider - count) & period2_mask;
611 osc->delay = count * period1 - extra;
612 }
613 #endif
614
615 // Generate wave
616 if ( time < end_time )
617 {
618 unsigned const mask = lfsr_mask( this );
619 unsigned bits = osc->phase;
620
621 int per = period2( this, period1 * 8 );
622 #ifdef GB_APU_FAST
623 // Noise can be THE biggest time hog; adjust as necessary
624 int const min_period = 24;
625 if ( per < min_period )
626 per = min_period;
627 #endif
628 if ( period2_index( this ) >= 0xE )
629 {
630 time = end_time;
631 }
632 else if ( !vol )
633 {
634 #ifdef GB_APU_FAST
635 time = end_time;
636 #else
637 // Maintain phase when not playing
638 int count = (end_time - time + per - 1) / per;
639 time += (blip_time_t) count * per;
640 bits = run_lfsr( bits, ~mask, count );
641 #endif
642 }
643 else
644 {
645 struct Blip_Synth* synth = osc->synth; // cache
646
647 // Output amplitude transitions
648 int delta = -vol;
649 do
650 {
651 unsigned changed = bits + 1;
652 bits = bits >> 1 & mask;
653 if ( changed & 2 )
654 {
655 bits |= ~mask;
656 delta = -delta;
657 Synth_offset_inline( synth, time, delta, out );
658 }
659 time += per;
660 }
661 while ( time < end_time );
662
663 if ( delta == vol )
664 osc->last_amp += delta;
665 }
666 osc->phase = bits;
667 }
668
669 #ifdef GB_APU_FAST
670 osc->delay = time - end_time;
671 #endif
672}
673
674void Wave_run( struct Gb_Wave* this, blip_time_t time, blip_time_t end_time )
675{
676 // Calc volume
677#ifdef GB_APU_NO_AGB
678 static byte const shifts [4] = { 4+4, 0+4, 1+4, 2+4 };
679 int const volume_idx = this->regs [2] >> 5 & 3;
680 int const volume_shift = shifts [volume_idx];
681 int const volume_mul = 1;
682#else
683 static byte const volumes [8] ICONST_ATTR = { 0, 4, 2, 1, 3, 3, 3, 3 };
684 int const volume_shift = 2 + 4;
685 int const volume_idx = this->osc.regs [2] >> 5 & (this->agb_mask | 3); // 2 bits on DMG/CGB, 3 on AGB
686 int const volume_mul = volumes [volume_idx];
687#endif
688
689 // Determine what will be generated
690 int playing = false;
691 struct Gb_Osc* osc = &this->osc;
692 struct Blip_Buffer* out = osc->output;
693 if ( out )
694 {
695 int amp = osc->dac_off_amp;
696 if ( Wave_dac_enabled( this ) )
697 {
698 // Play inaudible frequencies as constant amplitude
699 amp = 8 << 4; // really depends on average of all samples in wave
700
701 // if delay is larger, constant amplitude won't start yet
702 if ( Osc_frequency( osc ) <= 0x7FB || osc->delay > 15 * clk_mul )
703 {
704 if ( volume_mul && volume_shift != 4+4 )
705 playing = (int) osc->enabled;
706
707 amp = (this->sample_buf << (osc->phase << 2 & 4) & 0xF0) * playing;
708 }
709
710 amp = ((amp * volume_mul) >> volume_shift) - dac_bias;
711 }
712 Osc_update_amp( osc, time, amp );
713 }
714
715 // Generate wave
716 time += osc->delay;
717 if ( time < end_time )
718 {
719 byte const* wave = this->wave_ram;
720
721 // wave size and bank
722 #ifdef GB_APU_NO_AGB
723 int const wave_mask = 0x1F;
724 int const swap_banks = 0;
725 #else
726 int const size20_mask = 0x20;
727 int const flags = osc->regs [0] & this->agb_mask;
728 int const wave_mask = (flags & size20_mask) | 0x1F;
729 int swap_banks = 0;
730 if ( flags & bank40_mask )
731 {
732 swap_banks = flags & size20_mask;
733 wave += wave_bank_size/2 - (swap_banks >> 1);
734 }
735 #endif
736
737 int ph = osc->phase ^ swap_banks;
738 ph = (ph + 1) & wave_mask; // pre-advance
739
740 int const per = Wave_period( this );
741 if ( !playing )
742 {
743 #ifdef GB_APU_FAST
744 time = end_time;
745 #else
746 // Maintain phase when not playing
747 int count = (end_time - time + per - 1) / per;
748 ph += count; // will be masked below
749 time += (blip_time_t) count * per;
750 #endif
751 }
752 else
753 {
754 struct Blip_Synth* synth = osc->synth; // cache
755
756 // Output amplitude transitions
757 int lamp = osc->last_amp + dac_bias;
758 do
759 {
760 // Extract nibble
761 int nibble = wave [ph >> 1] << (ph << 2 & 4) & 0xF0;
762 ph = (ph + 1) & wave_mask;
763
764 // Scale by volume
765 int amp = (nibble * volume_mul) >> volume_shift;
766
767 int delta = amp - lamp;
768 if ( delta )
769 {
770 lamp = amp;
771 Synth_offset_inline( synth, time, delta, out );
772 }
773 time += per;
774 }
775 while ( time < end_time );
776 osc->last_amp = lamp - dac_bias;
777 }
778 ph = (ph - 1) & wave_mask; // undo pre-advance and mask position
779
780 // Keep track of last byte read
781 if ( osc->enabled )
782 this->sample_buf = wave [ph >> 1];
783
784 osc->phase = ph ^ swap_banks; // undo swapped banks
785 }
786 osc->delay = time - end_time;
787}
diff --git a/apps/codecs/libgme/gb_oscs.h b/apps/codecs/libgme/gb_oscs.h
new file mode 100644
index 0000000000..0cc9d3f567
--- /dev/null
+++ b/apps/codecs/libgme/gb_oscs.h
@@ -0,0 +1,198 @@
1// Private oscillators used by Gb_Apu
2
3// Gb_Snd_Emu 0.1.4
4#ifndef GB_OSCS_H
5#define GB_OSCS_H
6
7#include "blargg_common.h"
8#include "blip_buffer.h"
9
10#ifndef GB_APU_OVERCLOCK
11 #define GB_APU_OVERCLOCK 1
12#endif
13
14#if GB_APU_OVERCLOCK & (GB_APU_OVERCLOCK - 1)
15 #error "GB_APU_OVERCLOCK must be a power of 2"
16#endif
17
18enum { clk_mul = GB_APU_OVERCLOCK };
19enum { dac_bias = 7 };
20
21struct Gb_Osc {
22 struct Blip_Buffer* outputs [4];// NULL, right, left, center
23 struct Blip_Buffer* output; // where to output sound
24 uint8_t* regs; // osc's 5 registers
25 int mode; // mode_dmg, mode_cgb, mode_agb
26 int dac_off_amp;// amplitude when DAC is off
27 int last_amp; // current amplitude in Blip_Buffer
28
29 struct Blip_Synth* synth;
30
31 int delay; // clocks until frequency timer expires
32 int length_ctr; // length counter
33 unsigned phase; // waveform phase (or equivalent)
34 bool enabled; // internal enabled flag
35};
36
37// 11-bit frequency in NRx3 and NRx4
38static inline int Osc_frequency( struct Gb_Osc* this ) { return (this->regs [4] & 7) * 0x100 + this->regs [3]; }
39
40void Osc_update_amp( struct Gb_Osc* this, blip_time_t, int new_amp ) ICODE_ATTR;
41int Osc_write_trig( struct Gb_Osc* this, int frame_phase, int max_len, int old_data ) ICODE_ATTR;
42void Osc_clock_length( struct Gb_Osc* this ) ICODE_ATTR;
43void Osc_reset( struct Gb_Osc* this );
44
45// Square
46
47enum { period_mask = 0x70 };
48enum { shift_mask = 0x07 };
49
50struct Gb_Square {
51 struct Gb_Osc osc;
52
53 int env_delay;
54 int volume;
55 bool env_enabled;
56
57 // Sweep square
58 int sweep_freq;
59 int sweep_delay;
60 bool sweep_enabled;
61 bool sweep_neg;
62};
63
64bool Square_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR;
65void Square_run( struct Gb_Square* this, blip_time_t, blip_time_t ) ICODE_ATTR;
66void Square_clock_envelope( struct Gb_Square* this ) ICODE_ATTR;
67
68static inline void Square_reset( struct Gb_Square* this )
69{
70 this->env_delay = 0;
71 this->volume = 0;
72 Osc_reset( &this->osc );
73 this->osc.delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger)
74}
75// Frequency timer period
76static inline int Square_period( struct Gb_Square* this ) { return (2048 - Osc_frequency( &this->osc )) * (4 * clk_mul); }
77static inline int Square_dac_enabled( struct Gb_Square* this) { return this->osc.regs [2] & 0xF8; }
78static inline int Square_reload_env_timer( struct Gb_Square* this )
79{
80 int raw = this->osc.regs [2] & 7;
81 this->env_delay = (raw ? raw : 8);
82 return raw;
83}
84
85// Sweep square
86
87void clock_sweep( struct Gb_Square* this ) ICODE_ATTR;
88void Sweep_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR;
89
90static inline void Sweep_reset( struct Gb_Square* this )
91{
92 this->sweep_freq = 0;
93 this->sweep_delay = 0;
94 this->sweep_enabled = false;
95 this->sweep_neg = false;
96
97 this->env_delay = 0;
98 this->volume = 0;
99 Osc_reset( &this->osc );
100 this->osc.delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger)
101}
102
103void calc_sweep( struct Gb_Square* this, bool update ) ICODE_ATTR;
104void reload_sweep_timer( struct Gb_Square* this ) ICODE_ATTR;
105
106// Noise
107
108enum { period2_mask = 0x1FFFF };
109
110struct Gb_Noise {
111 struct Gb_Osc osc;
112
113 int env_delay;
114 int volume;
115 bool env_enabled;
116
117 int divider; // noise has more complex frequency divider setup
118};
119
120void Noise_run( struct Gb_Noise* this, blip_time_t, blip_time_t ) ICODE_ATTR;
121void Noise_write_register( struct Gb_Noise* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR;
122
123static inline void Noise_reset( struct Gb_Noise* this )
124{
125 this->divider = 0;
126
127 this->env_delay = 0;
128 this->volume = 0;
129 Osc_reset( &this->osc );
130 this->osc.delay = 4 * clk_mul; // TODO: remove?
131}
132
133void Noise_clock_envelope( struct Gb_Noise* this ) ICODE_ATTR;
134
135// Non-zero if DAC is enabled
136static inline int Noise_dac_enabled( struct Gb_Noise* this) { return this->osc.regs [2] & 0xF8; }
137static inline int Noise_reload_env_timer( struct Gb_Noise* this )
138{
139 int raw = this->osc.regs [2] & 7;
140 this->env_delay = (raw ? raw : 8);
141 return raw;
142}
143
144static inline int period2_index( struct Gb_Noise* this ) { return this->osc.regs [3] >> 4; }
145static inline int period2( struct Gb_Noise* this, int base ) { return base << period2_index( this ); }
146static inline unsigned lfsr_mask( struct Gb_Noise* this ) { return (this->osc.regs [3] & 0x08) ? ~0x4040 : ~0x4000; }
147
148// Wave
149
150enum { bank40_mask = 0x40 };
151enum { wave_bank_size = 32 };
152
153struct Gb_Wave {
154 struct Gb_Osc osc;
155
156 int sample_buf; // last wave RAM byte read (hardware has this as well)
157
158 int agb_mask; // 0xFF if AGB features enabled, 0 otherwise
159 uint8_t* wave_ram; // 32 bytes (64 nybbles), stored in APU
160};
161
162void Wave_write_register( struct Gb_Wave* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR;
163void Wave_run( struct Gb_Wave* this, blip_time_t, blip_time_t ) ICODE_ATTR;
164
165static inline void Wave_reset( struct Gb_Wave* this )
166{
167 this->sample_buf = 0;
168 Osc_reset( &this->osc );
169}
170
171// Frequency timer period
172static inline int Wave_period( struct Gb_Wave* this ) { return (2048 - Osc_frequency( &this->osc )) * (2 * clk_mul); }
173
174// Non-zero if DAC is enabled
175static inline int Wave_dac_enabled( struct Gb_Wave* this ) { return this->osc.regs [0] & 0x80; }
176
177void corrupt_wave( struct Gb_Wave* this );
178
179static inline uint8_t* wave_bank( struct Gb_Wave* this ) { return &this->wave_ram [(~this->osc.regs [0] & bank40_mask) >> 2 & this->agb_mask]; }
180
181// Wave index that would be accessed, or -1 if no access would occur
182int wave_access( struct Gb_Wave* this, int addr ) ICODE_ATTR;
183
184// Reads/writes wave RAM
185static inline int Wave_read( struct Gb_Wave* this, int addr )
186{
187 int index = wave_access( this, addr );
188 return (index < 0 ? 0xFF : wave_bank( this ) [index]);
189}
190
191static inline void Wave_write( struct Gb_Wave* this, int addr, int data )
192{
193 int index = wave_access( this, addr );
194 if ( index >= 0 )
195 wave_bank( this ) [index] = data;;
196}
197
198#endif
diff --git a/apps/codecs/libgme/gbs_cpu.c b/apps/codecs/libgme/gbs_cpu.c
new file mode 100644
index 0000000000..5a27bf6abe
--- /dev/null
+++ b/apps/codecs/libgme/gbs_cpu.c
@@ -0,0 +1,120 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "gbs_emu.h"
4#include "blargg_endian.h"
5
6/* Copyright (C) 2003-2009 Shay Green. This module is free software; you
7can redistribute it and/or modify it under the terms of the GNU Lesser
8General Public License as published by the Free Software Foundation; either
9version 2.1 of the License, or (at your option) any later version. This
10module is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13details. You should have received a copy of the GNU Lesser General Public
14License along with this module; if not, write to the Free Software Foundation,
15Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
16
17#include "blargg_source.h"
18
19#ifndef LOG_MEM
20 #define LOG_MEM( addr, str, data ) data
21#endif
22
23int Read_mem( struct Gbs_Emu* this, addr_t addr )
24{
25 int result = *Cpu_get_code( &this->cpu, addr );
26 if ( (unsigned) (addr - io_addr) < io_size )
27 result = Apu_read_register( &this->apu, Time( this ), addr );
28
29 return LOG_MEM( addr, ">", result );
30}
31
32inline void Write_io_inline( struct Gbs_Emu* this, int offset, int data, int base )
33{
34 if ( (unsigned) (offset - (io_addr - base)) < io_size )
35 Apu_write_register( &this->apu, Time( this ), offset + base, data & 0xFF );
36 else if ( (unsigned) (offset - (0xFF06 - base)) < 2 )
37 Update_timer( this );
38 else if ( offset == io_base - base )
39 this->ram [base - ram_addr + offset] = 0; // keep joypad return value 0
40 else
41 this->ram [base - ram_addr + offset] = 0xFF;
42}
43
44void Write_mem( struct Gbs_Emu* this, addr_t addr, int data )
45{
46 (void) LOG_MEM( addr, "<", data );
47
48 int offset = addr - ram_addr;
49 if ( (unsigned) offset < 0x10000 - ram_addr )
50 {
51 this->ram [offset] = data;
52
53 offset -= 0xE000 - ram_addr;
54 if ( (unsigned) offset < 0x1F80 )
55 Write_io_inline( this, offset, data, 0xE000 );
56 }
57 else if ( (unsigned) (offset - (0x2000 - ram_addr)) < 0x2000 )
58 {
59 Set_bank( this, data & 0xFF );
60 }
61#ifndef NDEBUG
62 else if ( unsigned (addr - 0x8000) < 0x2000 || unsigned (addr - 0xE000) < 0x1F00 )
63 {
64 /* dprintf( "Unmapped write $%04X\n", (unsigned) addr ); */
65 }
66#endif
67}
68
69void Write_io_( struct Gbs_Emu* this, int offset, int data )
70{
71 Write_io_inline( this, offset, data, io_base );
72}
73
74inline void Write_io( struct Gbs_Emu* this, int offset, int data )
75{
76 (void) LOG_MEM( offset + io_base, "<", data );
77
78 this->ram [io_base - ram_addr + offset] = data;
79 if ( (unsigned) offset < 0x80 )
80 Write_io_( this, offset, data );
81}
82
83int Read_io( struct Gbs_Emu* this, int offset )
84{
85 int const io_base = 0xFF00;
86 int result = this->ram [io_base - ram_addr + offset];
87
88 if ( (unsigned) (offset - (io_addr - io_base)) < io_size )
89 {
90 result = Apu_read_register( &this->apu, Time( this ), offset + io_base );
91 (void) LOG_MEM( offset + io_base, ">", result );
92 }
93 else
94 {
95 check( result == read_mem( offset + io_base ) );
96 }
97 return result;
98}
99
100#define READ_FAST( emu, addr, out ) \
101{\
102 out = READ_CODE( addr );\
103 if ( (unsigned) (addr - io_addr) < io_size )\
104 out = LOG_MEM( addr, ">", Apu_read_register( &emu->apu, TIME() + emu->end_time, addr ) );\
105 else\
106 check( out == Read_mem( emu, addr ) );\
107}
108
109#define READ_MEM( emu, addr ) Read_mem( emu, addr )
110#define WRITE_MEM( emu, addr, data ) Write_mem( emu, addr, data )
111
112#define WRITE_IO( emu, addr, data ) Write_io( emu, addr, data )
113#define READ_IO( emu, addr, out ) out = Read_io( emu, addr )
114
115#define CPU_BEGIN \
116void Run_cpu( struct Gbs_Emu* this )\
117{ \
118 struct Gb_Cpu* cpu = &this->cpu;
119 #include "gb_cpu_run.h"
120}
diff --git a/apps/codecs/libgme/gbs_emu.c b/apps/codecs/libgme/gbs_emu.c
new file mode 100644
index 0000000000..693e84a39b
--- /dev/null
+++ b/apps/codecs/libgme/gbs_emu.c
@@ -0,0 +1,631 @@
1// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/
2
3#include "gbs_emu.h"
4
5#include "blargg_endian.h"
6#include "blargg_source.h"
7
8/* Copyright (C) 2003-2006 Shay Green. this module is free software; you
9can redistribute it and/or modify it under the terms of the GNU Lesser
10General Public License as published by the Free Software Foundation; either
11version 2.1 of the License, or (at your option) any later version. this
12module is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15details. You should have received a copy of the GNU Lesser General Public
16License along with this module; if not, write to the Free Software Foundation,
17Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19
20const char gme_wrong_file_type [] ICONST_ATTR = "Wrong file type for this emulator";
21
22int const idle_addr = 0xF00D;
23int const tempo_unit = 16;
24
25int const stereo = 2; // number of channels for stereo
26int const silence_max = 6; // seconds
27int const silence_threshold = 0x10;
28long const fade_block_size = 512;
29int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
30
31void clear_track_vars( struct Gbs_Emu* this )
32{
33 this->current_track_ = -1;
34 this->out_time = 0;
35 this->emu_time = 0;
36 this->emu_track_ended_ = true;
37 this->track_ended = true;
38 this->fade_start = LONG_MAX / 2 + 1;
39 this->fade_step = 1;
40 this->silence_time = 0;
41 this->silence_count = 0;
42 this->buf_remain = 0;
43}
44
45void Gbs_init( struct Gbs_Emu* this )
46{
47 this->sample_rate_ = 0;
48 this->mute_mask_ = 0;
49 this->tempo_ = 1.0;
50
51 // Unload
52 this->header.timer_mode = 0;
53 clear_track_vars( this );
54
55 this->ignore_silence = false;
56 this->silence_lookahead = 6;
57 this->max_initial_silence = 21;
58 Sound_set_gain( this, 1.2 );
59
60 Rom_init( &this->rom, 0x4000 );
61
62 Apu_init( &this->apu );
63 Cpu_init( &this->cpu );
64
65 this->tempo = tempo_unit;
66 this->sound_hardware = sound_gbs;
67
68 // Reduce apu sound clicks?
69 Apu_reduce_clicks( &this->apu, true );
70}
71
72static blargg_err_t check_gbs_header( void const* header )
73{
74 if ( memcmp( header, "GBS", 3 ) )
75 return gme_wrong_file_type;
76 return 0;
77}
78
79// Setup
80
81blargg_err_t Gbs_load( struct Gbs_Emu* this, void* data, long size )
82{
83 // Unload
84 this->header.timer_mode = 0;
85 this->voice_count_ = 0;
86 this->m3u.size = 0;
87 clear_track_vars( this );
88
89 assert( offsetof (struct header_t,copyright [32]) == header_size );
90 RETURN_ERR( Rom_load( &this->rom, data, size, header_size, &this->header, 0 ) );
91
92 RETURN_ERR( check_gbs_header( &this->header ) );
93
94 /* Ignore warnings? */
95 /*if ( header_.vers != 1 )
96 warning( "Unknown file version" );
97
98 if ( header_.timer_mode & 0x78 )
99 warning( "Invalid timer mode" ); */
100
101 /* unsigned load_addr = get_le16( this->header.load_addr ); */
102 /* if ( (header_.load_addr [1] | header_.init_addr [1] | header_.play_addr [1]) > 0x7F ||
103 load_addr < 0x400 )
104 warning( "Invalid load/init/play address" ); */
105
106 unsigned load_addr = get_le16( this->header.load_addr );
107 /* if ( (this->header.load_addr [1] | this->header.init_addr [1] | this->header.play_addr [1]) > 0x7F ||
108 load_addr < 0x400 )
109 warning( "Invalid load/init/play address" ); */
110
111 this->cpu.rst_base = load_addr;
112 Rom_set_addr( &this->rom, load_addr );
113
114 this->voice_count_ = osc_count;
115 Apu_volume( &this->apu, this->gain_ );
116
117 // Change clock rate & setup buffer
118 this->clock_rate_ = 4194304;
119 Buffer_clock_rate( &this->stereo_buf, 4194304 );
120 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
121
122 // Post load
123 Sound_set_tempo( this, this->tempo_ );
124
125 // Remute voices
126 Sound_mute_voices( this, this->mute_mask_ );
127
128 // Reset track count
129 this->track_count = this->header.track_count;
130 return 0;
131}
132
133// Emulation
134
135// see gb_cpu_io.h for read/write functions
136
137void Set_bank( struct Gbs_Emu* this, int n )
138{
139 addr_t addr = mask_addr( n * this->rom.bank_size, this->rom.mask );
140 if ( addr == 0 && this->rom.size > this->rom.bank_size )
141 addr = this->rom.bank_size; // MBC1&2 behavior, bank 0 acts like bank 1
142 Cpu_map_code( &this->cpu, this->rom.bank_size, this->rom.bank_size, Rom_at_addr( &this->rom, addr ) );
143}
144
145void Update_timer( struct Gbs_Emu* this )
146{
147 this->play_period = 70224 / tempo_unit; /// 59.73 Hz
148
149 if ( this->header.timer_mode & 0x04 )
150 {
151 // Using custom rate
152 static byte const rates [4] = { 6, 0, 2, 4 };
153 // TODO: emulate double speed CPU mode rather than halving timer rate
154 int double_speed = this->header.timer_mode >> 7;
155 int shift = rates [this->ram [hi_page + 7] & 3] - double_speed;
156 this->play_period = (256 - this->ram [hi_page + 6]) << shift;
157 }
158
159 this->play_period *= this->tempo;
160}
161
162// Jumps to routine, given pointer to address in file header. Pushes idle_addr
163// as return address, NOT old PC.
164void Jsr_then_stop( struct Gbs_Emu* this, byte const addr [] )
165{
166 check( this->cpu.r.sp == get_le16( this->header.stack_ptr ) );
167 this->cpu.r.pc = get_le16( addr );
168 Write_mem( this, --this->cpu.r.sp, idle_addr >> 8 );
169 Write_mem( this, --this->cpu.r.sp, idle_addr );
170}
171
172blargg_err_t Run_until( struct Gbs_Emu* this, int end )
173{
174 this->end_time = end;
175 Cpu_set_time( &this->cpu, Cpu_time( &this->cpu ) - end );
176 while ( true )
177 {
178 Run_cpu( this );
179 if ( Cpu_time( &this->cpu ) >= 0 )
180 break;
181
182 if ( this->cpu.r.pc == idle_addr )
183 {
184 if ( this->next_play > this->end_time )
185 {
186 Cpu_set_time( &this->cpu, 0 );
187 break;
188 }
189
190 if ( Cpu_time( &this->cpu ) < this->next_play - this->end_time )
191 Cpu_set_time( &this->cpu, this->next_play - this->end_time );
192 this->next_play += this->play_period;
193 Jsr_then_stop( this, this->header.play_addr );
194 }
195 else if ( this->cpu.r.pc > 0xFFFF )
196 {
197 /* warning( "PC wrapped around\n" ); */
198 this->cpu.r.pc &= 0xFFFF;
199 }
200 else
201 {
202 /* warning( "Emulation error (illegal/unsupported instruction)" ); */
203 this->cpu.r.pc = (this->cpu.r.pc + 1) & 0xFFFF;
204 Cpu_set_time( &this->cpu, Cpu_time( &this->cpu ) + 6 );
205 }
206 }
207
208 return 0;
209}
210
211blargg_err_t End_frame( struct Gbs_Emu* this, int end )
212{
213 RETURN_ERR( Run_until( this, end ) );
214
215 this->next_play -= end;
216 if ( this->next_play < 0 ) // happens when play routine takes too long
217 {
218 #if !defined(GBS_IGNORE_STARVED_PLAY)
219 check( false );
220 #endif
221 this->next_play = 0;
222 }
223
224 Apu_end_frame( &this->apu, end );
225
226 return 0;
227}
228
229blargg_err_t Run_clocks( struct Gbs_Emu* this, blip_time_t duration )
230{
231 return End_frame( this, duration );
232}
233
234blargg_err_t play_( struct Gbs_Emu* this, long count, sample_t* out )
235{
236 long remain = count;
237 while ( remain )
238 {
239 remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain );
240 if ( remain )
241 {
242 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) )
243 {
244 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
245
246 // Remute voices
247 Sound_mute_voices( this, this->mute_mask_ );
248 }
249 int msec = Buffer_length( &this->stereo_buf );
250 blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate_ / 1000;
251 RETURN_ERR( Run_clocks( this, clocks_emulated ) );
252 assert( clocks_emulated );
253 Buffer_end_frame( &this->stereo_buf, clocks_emulated );
254 }
255 }
256 return 0;
257}
258
259blargg_err_t Gbs_set_sample_rate( struct Gbs_Emu* this, long rate )
260{
261 require( !this->sample_rate_ ); // sample rate can't be changed once set
262 Buffer_init( &this->stereo_buf );
263 RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) );
264
265 // Set bass frequency
266 Buffer_bass_freq( &this->stereo_buf, 300 );
267
268 this->sample_rate_ = rate;
269 return 0;
270}
271
272
273// Sound
274
275void Sound_mute_voice( struct Gbs_Emu* this, int index, bool mute )
276{
277 require( (unsigned) index < (unsigned) this->voice_count_ );
278 int bit = 1 << index;
279 int mask = this->mute_mask_ | bit;
280 if ( !mute )
281 mask ^= bit;
282 Sound_mute_voices( this, mask );
283}
284
285void Sound_mute_voices( struct Gbs_Emu* this, int mask )
286{
287 require( this->sample_rate_ ); // sample rate must be set first
288 this->mute_mask_ = mask;
289
290 int i;
291 for ( i = this->voice_count_; i--; )
292 {
293 if ( mask & (1 << i) )
294 {
295 Apu_set_output( &this->apu, i, 0, 0, 0 );
296 }
297 else
298 {
299 struct channel_t ch = Buffer_channel( &this->stereo_buf );
300 assert( (ch.center && ch.left && ch.right) ||
301 (!ch.center && !ch.left && !ch.right) ); // all or nothing
302 Apu_set_output( &this->apu, i, ch.center, ch.left, ch.right );
303 }
304 }
305}
306
307void Sound_set_tempo( struct Gbs_Emu* this, double t )
308{
309 require( this->sample_rate_ ); // sample rate must be set first
310 double const min = 0.02;
311 double const max = 4.00;
312 if ( t < min ) t = min;
313 if ( t > max ) t = max;
314 this->tempo_ = t;
315
316 this->tempo = (int) (tempo_unit / t + 0.5 );
317 Apu_set_tempo( &this->apu, t );
318 Update_timer( this );
319}
320
321void fill_buf( struct Gbs_Emu* this );
322blargg_err_t Gbs_start_track( struct Gbs_Emu* this, int track )
323{
324 clear_track_vars( this );
325
326 // Remap track if playlist available
327 if ( this->m3u.size > 0 ) {
328 struct entry_t* e = &this->m3u.entries[track];
329 track = e->track;
330 }
331
332 this->current_track_ = track;
333
334 Buffer_clear( &this->stereo_buf );
335
336 // Reset APU to state expected by most rips
337 static byte const sound_data [] ICONST_ATTR = {
338 0x80, 0xBF, 0x00, 0x00, 0xB8, // square 1 DAC disabled
339 0x00, 0x3F, 0x00, 0x00, 0xB8, // square 2 DAC disabled
340 0x7F, 0xFF, 0x9F, 0x00, 0xB8, // wave DAC disabled
341 0x00, 0xFF, 0x00, 0x00, 0xB8, // noise DAC disabled
342 0x77, 0xFF, 0x80, // max volume, all chans in center, power on
343 };
344
345 enum sound_t mode = this->sound_hardware;
346 if ( mode == sound_gbs )
347 mode = (this->header.timer_mode & 0x80) ? sound_cgb : sound_dmg;
348
349 Apu_reset( &this->apu, (enum gb_mode_t) mode, false );
350 Apu_write_register( &this->apu, 0, 0xFF26, 0x80 ); // power on
351 int i;
352 for ( i = 0; i < (int) sizeof sound_data; i++ )
353 Apu_write_register( &this->apu, 0, i + io_addr, sound_data [i] );
354 Apu_end_frame( &this->apu, 1 ); // necessary to get click out of the way */
355
356 memset( this->ram, 0, 0x4000 );
357 memset( this->ram + 0x4000, 0xFF, 0x1F80 );
358 memset( this->ram + 0x5F80, 0, sizeof this->ram - 0x5F80 );
359 this->ram [hi_page] = 0; // joypad reads back as 0
360 this->ram [idle_addr - ram_addr] = 0xED; // illegal instruction
361 this->ram [hi_page + 6] = this->header.timer_modulo;
362 this->ram [hi_page + 7] = this->header.timer_mode;
363
364 Cpu_reset( &this->cpu, this->rom.unmapped );
365 Cpu_map_code( &this->cpu, ram_addr, 0x10000 - ram_addr, this->ram );
366 Cpu_map_code( &this->cpu, 0, this->rom.bank_size, Rom_at_addr( &this->rom, 0 ) );
367 Set_bank( this, this->rom.size > this->rom.bank_size );
368
369 Update_timer( this );
370 this->next_play = this->play_period;
371 this->cpu.r.rp.fa = track;
372 this->cpu.r.sp = get_le16( this->header.stack_ptr );
373 this->cpu_time = 0;
374 Jsr_then_stop( this, this->header.init_addr );
375
376 this->emu_track_ended_ = false;
377 this->track_ended = false;
378
379 if ( !this->ignore_silence )
380 {
381 // play until non-silence or end of track
382 long end;
383 for ( end = this->max_initial_silence * stereo * this->sample_rate_; this->emu_time < end; )
384 {
385 fill_buf( this );
386 if ( this->buf_remain | (int) this->emu_track_ended_ )
387 break;
388 }
389
390 this->emu_time = this->buf_remain;
391 this->out_time = 0;
392 this->silence_time = 0;
393 this->silence_count = 0;
394 }
395 /* return track_ended() ? warning() : 0; */
396 return 0;
397}
398
399
400// Track
401
402blargg_long msec_to_samples( blargg_long msec, long sample_rate )
403{
404 blargg_long sec = msec / 1000;
405 msec -= sec * 1000;
406 return (sec * sample_rate + msec * sample_rate / 1000) * stereo;
407}
408
409long Track_tell( struct Gbs_Emu* this )
410{
411 blargg_long rate = this->sample_rate_ * stereo;
412 blargg_long sec = this->out_time / rate;
413 return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate;
414}
415
416blargg_err_t Track_seek( struct Gbs_Emu* this, long msec )
417{
418 blargg_long time = msec_to_samples( msec, this->sample_rate_ );
419 if ( time < this->out_time )
420 RETURN_ERR( Gbs_start_track( this, this->current_track_ ) );
421 return Track_skip( this, time - this->out_time );
422}
423
424blargg_err_t skip_( struct Gbs_Emu* this, long count )
425{
426 // for long skip, mute sound
427 const long threshold = 30000;
428 if ( count > threshold )
429 {
430 int saved_mute = this->mute_mask_;
431 Sound_mute_voices( this, ~0 );
432
433 while ( count > threshold / 2 && !this->emu_track_ended_ )
434 {
435 RETURN_ERR( play_( this, buf_size, this->buf ) );
436 count -= buf_size;
437 }
438
439 Sound_mute_voices( this, saved_mute );
440 }
441
442 while ( count && !this->emu_track_ended_ )
443 {
444 long n = buf_size;
445 if ( n > count )
446 n = count;
447 count -= n;
448 RETURN_ERR( play_( this, n, this->buf ) );
449 }
450 return 0;
451}
452
453blargg_err_t Track_skip( struct Gbs_Emu* this, long count )
454{
455 require( this->current_track_ >= 0 ); // start_track() must have been called already
456 this->out_time += count;
457
458 // remove from silence and buf first
459 {
460 long n = min( count, this->silence_count );
461 this->silence_count -= n;
462 count -= n;
463
464 n = min( count, this->buf_remain );
465 this->buf_remain -= n;
466 count -= n;
467 }
468
469 if ( count && !this->emu_track_ended_ )
470 {
471 this->emu_time += count;
472 // End track if error
473 if ( skip_( this, count ) )
474 this->emu_track_ended_ = true;
475 }
476
477 if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended
478 this->track_ended |= this->emu_track_ended_;
479
480 return 0;
481}
482
483// Fading
484
485void Track_set_fade( struct Gbs_Emu* this, long start_msec, long length_msec )
486{
487 this->fade_step = this->sample_rate_ * length_msec / (fade_block_size * fade_shift * 1000 / stereo);
488 this->fade_start = msec_to_samples( start_msec, this->sample_rate_ );
489}
490
491// unit / pow( 2.0, (double) x / step )
492static int int_log( blargg_long x, int step, int unit )
493{
494 int shift = x / step;
495 int fraction = (x - shift * step) * unit / step;
496 return ((unit - fraction) + (fraction >> 1)) >> shift;
497}
498
499void handle_fade( struct Gbs_Emu* this, long out_count, sample_t* out )
500{
501 int i;
502 for ( i = 0; i < out_count; i += fade_block_size )
503 {
504 int const shift = 14;
505 int const unit = 1 << shift;
506 int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size,
507 this->fade_step, unit );
508 if ( gain < (unit >> fade_shift) )
509 this->track_ended = this->emu_track_ended_ = true;
510
511 sample_t* io = &out [i];
512 int count;
513 for ( count = min( fade_block_size, out_count - i ); count; --count )
514 {
515 *io = (sample_t) ((*io * gain) >> shift);
516 ++io;
517 }
518 }
519}
520
521// Silence detection
522
523void emu_play( struct Gbs_Emu* this, long count, sample_t* out )
524{
525 check( current_track_ >= 0 );
526 this->emu_time += count;
527 if ( this->current_track_ >= 0 && !this->emu_track_ended_ ) {
528 // End track if error
529 if ( play_( this, count, out ) ) this->emu_track_ended_ = true;
530 }
531 else
532 memset( out, 0, count * sizeof *out );
533}
534
535// number of consecutive silent samples at end
536static long count_silence( sample_t* begin, long size )
537{
538 sample_t first = *begin;
539 *begin = silence_threshold; // sentinel
540 sample_t* p = begin + size;
541 while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { }
542 *begin = first;
543 return size - (p - begin);
544}
545
546// fill internal buffer and check it for silence
547void fill_buf( struct Gbs_Emu* this )
548{
549 assert( !this->buf_remain );
550 if ( !this->emu_track_ended_ )
551 {
552 emu_play( this, buf_size, this->buf );
553 long silence = count_silence( this->buf, buf_size );
554 if ( silence < buf_size )
555 {
556 this->silence_time = this->emu_time - silence;
557 this->buf_remain = buf_size;
558 return;
559 }
560 }
561 this->silence_count += buf_size;
562}
563
564blargg_err_t Gbs_play( struct Gbs_Emu* this, long out_count, sample_t* out )
565{
566 if ( this->track_ended )
567 {
568 memset( out, 0, out_count * sizeof *out );
569 }
570 else
571 {
572 require( this->current_track_ >= 0 );
573 require( out_count % stereo == 0 );
574
575 assert( this->emu_time >= this->out_time );
576
577 long pos = 0;
578 if ( this->silence_count )
579 {
580 // during a run of silence, run emulator at >=2x speed so it gets ahead
581 long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time;
582 while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) )
583 fill_buf( this );
584
585 // fill with silence
586 pos = min( this->silence_count, out_count );
587 memset( out, 0, pos * sizeof *out );
588 this->silence_count -= pos;
589
590 if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate_ )
591 {
592 this->track_ended = this->emu_track_ended_ = true;
593 this->silence_count = 0;
594 this->buf_remain = 0;
595 }
596 }
597
598 if ( this->buf_remain )
599 {
600 // empty silence buf
601 long n = min( this->buf_remain, out_count - pos );
602 memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out );
603 this->buf_remain -= n;
604 pos += n;
605 }
606
607 // generate remaining samples normally
608 long remain = out_count - pos;
609 if ( remain )
610 {
611 emu_play( this, remain, out + pos );
612 this->track_ended |= this->emu_track_ended_;
613
614 if ( !this->ignore_silence || this->out_time > this->fade_start )
615 {
616 // check end for a new run of silence
617 long silence = count_silence( out + pos, remain );
618 if ( silence < remain )
619 this->silence_time = this->emu_time - silence;
620
621 if ( this->emu_time - this->silence_time >= buf_size )
622 fill_buf( this ); // cause silence detection on next play()
623 }
624 }
625
626 if ( this->out_time > this->fade_start )
627 handle_fade( this, out_count, out );
628 }
629 this->out_time += out_count;
630 return 0;
631}
diff --git a/apps/codecs/libgme/gbs_emu.h b/apps/codecs/libgme/gbs_emu.h
new file mode 100644
index 0000000000..c107264f9f
--- /dev/null
+++ b/apps/codecs/libgme/gbs_emu.h
@@ -0,0 +1,204 @@
1// Nintendo Game Boy GBS music file emulator
2
3// Game_Music_Emu 0.5.2
4#ifndef GBS_EMU_H
5#define GBS_EMU_H
6
7#include "rom_data.h"
8#include "multi_buffer.h"
9#include "gb_apu.h"
10#include "gb_cpu.h"
11#include "m3u_playlist.h"
12
13/* typedef uint8_t byte; */
14typedef short sample_t;
15
16enum { joypad_addr = 0xFF00 };
17enum { ram_addr = 0xA000 };
18enum { hi_page = 0xFF00 - ram_addr };
19enum { io_base = 0xFF00 };
20enum { buf_size = 2048 };
21
22// Selects which sound hardware to use. AGB hardware is cleaner than the
23// others. Doesn't take effect until next start_track().
24enum sound_t {
25 sound_dmg = mode_dmg, // Game Boy monochrome
26 sound_cgb = mode_cgb, // Game Boy Color
27 sound_agb = mode_agb, // Game Boy Advance
28 sound_gbs // Use DMG/CGB based on GBS (default)
29};
30
31// GBS file header
32enum { header_size = 112 };
33struct header_t
34{
35 char tag [3];
36 byte vers;
37 byte track_count;
38 byte first_track;
39 byte load_addr [2];
40 byte init_addr [2];
41 byte play_addr [2];
42 byte stack_ptr [2];
43 byte timer_modulo;
44 byte timer_mode;
45 char game [32];
46 char author [32];
47 char copyright [32];
48};
49
50struct Gbs_Emu {
51 enum sound_t sound_hardware;
52
53 int tempo;
54
55 // timer
56 blip_time_t cpu_time;
57 blip_time_t end_time;
58 blip_time_t play_period;
59 blip_time_t next_play;
60
61 // Sound
62 long clock_rate_;
63 long sample_rate_;
64 unsigned buf_changed_count;
65 int voice_count_;
66 double gain_;
67 double tempo_;
68
69 // track-specific
70 byte track_count;
71 volatile bool track_ended;
72 int current_track_;
73 blargg_long out_time; // number of samples played since start of track
74 blargg_long emu_time; // number of samples emulator has generated since start of track
75 bool emu_track_ended_; // emulator has reached end of track
76
77 // fading
78 blargg_long fade_start;
79 int fade_step;
80
81 // silence detection
82 // Disable automatic end-of-track detection and skipping of silence at beginning
83 bool ignore_silence;
84
85 int max_initial_silence;
86 int mute_mask_;
87 int silence_lookahead; // speed to run emulator when looking ahead for silence
88 long silence_time; // number of samples where most recent silence began
89 long silence_count; // number of samples of silence to play before using buf
90 long buf_remain; // number of samples left in silence buffer
91
92 // Larger items at the end
93 // Header for currently loaded file
94 struct header_t header;
95
96 // M3u Playlist
97 struct M3u_Playlist m3u;
98
99 struct Gb_Apu apu;
100 struct Gb_Cpu cpu;
101 struct Stereo_Buffer stereo_buf;
102
103 sample_t buf [buf_size];
104
105 // rom & ram
106 struct Rom_Data rom;
107 byte ram [0x4000 + 0x2000 + cpu_padding];
108};
109
110
111// Basic functionality
112// Initializes Gbs_Emu structure
113void Gbs_init( struct Gbs_Emu* this );
114
115// Stops (clear) Gbs_Emu structure
116void Gbs_stop( struct Gbs_Emu* this );
117
118// Loads a file from memory
119blargg_err_t Gbs_load( struct Gbs_Emu* this, void* data, long size );
120
121// Set output sample rate. Must be called only once before loading file.
122blargg_err_t Gbs_set_sample_rate( struct Gbs_Emu* this, long sample_rate );
123
124// Start a track, where 0 is the first track. Also clears warning string.
125blargg_err_t Gbs_start_track( struct Gbs_Emu* this, int );
126
127// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation
128// errors set warning string, and major errors also end track.
129blargg_err_t Gbs_play( struct Gbs_Emu* this, long count, sample_t* buf ) ICODE_ATTR;
130
131// Track status/control
132// Number of milliseconds (1000 msec = 1 second) played since beginning of track
133long Track_tell( struct Gbs_Emu* this );
134
135// Seek to new time in track. Seeking backwards or far forward can take a while.
136blargg_err_t Track_seek( struct Gbs_Emu* this, long msec );
137
138// Skip n samples
139blargg_err_t Track_skip( struct Gbs_Emu* this, long n );
140
141// Set start time and length of track fade out. Once fade ends track_ended() returns
142// true. Fade time can be changed while track is playing.
143void Track_set_fade( struct Gbs_Emu* this, long start_msec, long length_msec );
144
145// Get track length in milliseconds
146static inline long Track_get_length( struct Gbs_Emu* this, int n )
147{
148 long length = 120 * 1000; /* 2 minutes */
149 if ( (this->m3u.size > 0) && (n < this->m3u.size) ) {
150 struct entry_t* entry = &this->m3u.entries [n];
151 length = entry->length;
152 }
153
154 return length;
155}
156
157
158// Sound customization
159// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed.
160// Track length as returned by track_info() assumes a tempo of 1.0.
161void Sound_set_tempo( struct Gbs_Emu* this, double );
162
163// Mute/unmute voice i, where voice 0 is first voice
164void Sound_mute_voice( struct Gbs_Emu* this, int index, bool mute );
165
166// Set muting state of all voices at once using a bit mask, where -1 mutes them all,
167// 0 unmutes them all, 0x01 mutes just the first voice, etc.
168void Sound_mute_voices( struct Gbs_Emu* this, int mask );
169
170// Change overall output amplitude, where 1.0 results in minimal clamping.
171// Must be called before set_sample_rate().
172static inline void Sound_set_gain( struct Gbs_Emu* this, double g )
173{
174 assert( !this->sample_rate_ ); // you must set gain before setting sample rate
175 this->gain_ = g;
176}
177
178
179// Emulation (You shouldn't touch these)
180
181blargg_err_t Run_clocks( struct Gbs_Emu* this, blip_time_t duration ) ICODE_ATTR;
182void Set_bank( struct Gbs_Emu* this, int ) ICODE_ATTR;
183void Update_timer( struct Gbs_Emu* this ) ICODE_ATTR;
184
185// Runs CPU until time becomes >= 0
186void Run_cpu( struct Gbs_Emu* this ) ICODE_ATTR;
187
188// Reads/writes memory and I/O
189int Read_mem( struct Gbs_Emu* this, addr_t addr ) ICODE_ATTR;
190void Write_mem( struct Gbs_Emu* this, addr_t addr, int data ) ICODE_ATTR;
191
192// Current time
193static inline blip_time_t Time( struct Gbs_Emu* this )
194{
195 return Cpu_time( &this->cpu ) + this->end_time;
196}
197
198void Jsr_then_stop( struct Gbs_Emu* this, byte const [] ) ICODE_ATTR;
199void Write_io_inline( struct Gbs_Emu* this, int offset, int data, int base ) ICODE_ATTR;
200void Write_io_( struct Gbs_Emu* this, int offset, int data ) ICODE_ATTR;
201int Read_io( struct Gbs_Emu* this, int offset ) ICODE_ATTR;
202void Write_io( struct Gbs_Emu* this, int offset, int data ) ICODE_ATTR;
203
204#endif
diff --git a/apps/codecs/libgme/gme.h b/apps/codecs/libgme/gme.h
new file mode 100644
index 0000000000..d6803704ce
--- /dev/null
+++ b/apps/codecs/libgme/gme.h
@@ -0,0 +1,18 @@
1/* Game music emulator library C interface (also usable from C++) */
2
3/* Game_Music_Emu 0.5.2 */
4#ifndef GME_H
5#define GME_H
6
7#ifdef __cplusplus
8 extern "C" {
9#endif
10
11/* Error string returned by library functions, or NULL if no error (success) */
12typedef const char* gme_err_t;
13
14#ifdef __cplusplus
15 }
16#endif
17
18#endif
diff --git a/apps/codecs/libgme/gme_types.h b/apps/codecs/libgme/gme_types.h
new file mode 100644
index 0000000000..06226f4aa1
--- /dev/null
+++ b/apps/codecs/libgme/gme_types.h
@@ -0,0 +1,21 @@
1#ifndef GME_TYPES_H
2#define GME_TYPES_H
3
4/*
5 * This is a default gme_types.h for use when *not* using
6 * CMake. If CMake is in use gme_types.h.in will be
7 * processed instead.
8 */
9#define USE_GME_AY
10#define USE_GME_GBS
11#define USE_GME_GYM
12#define USE_GME_HES
13#define USE_GME_KSS
14#define USE_GME_NSF
15#define USE_GME_NSFE
16#define USE_GME_SAP
17#define USE_GME_SPC
18/* VGM and VGZ are a package deal */
19#define USE_GME_VGM
20
21#endif /* GME_TYPES_H */
diff --git a/apps/codecs/libgme/hes_apu.c b/apps/codecs/libgme/hes_apu.c
new file mode 100644
index 0000000000..a3af054548
--- /dev/null
+++ b/apps/codecs/libgme/hes_apu.c
@@ -0,0 +1,315 @@
1// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/
2
3#include "hes_apu.h"
4#include <string.h>
5
6/* Copyright (C) 2006 Shay Green. This module is free software; you
7can redistribute it and/or modify it under the terms of the GNU Lesser
8General Public License as published by the Free Software Foundation; either
9version 2.1 of the License, or (at your option) any later version. This
10module is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13details. You should have received a copy of the GNU Lesser General Public
14License along with this module; if not, write to the Free Software Foundation,
15Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
16
17#include "blargg_source.h"
18
19enum { center_waves = 1 }; // reduces asymmetry and clamping when starting notes
20
21static void Apu_balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc ) ICODE_ATTR;
22static void Apu_balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc )
23{
24 static short const log_table [32] ICONST_ATTR = { // ~1.5 db per step
25 #define ENTRY( factor ) (short) (factor * amp_range / 31.0 + 0.5)
26 ENTRY( 0.000000 ),ENTRY( 0.005524 ),ENTRY( 0.006570 ),ENTRY( 0.007813 ),
27 ENTRY( 0.009291 ),ENTRY( 0.011049 ),ENTRY( 0.013139 ),ENTRY( 0.015625 ),
28 ENTRY( 0.018581 ),ENTRY( 0.022097 ),ENTRY( 0.026278 ),ENTRY( 0.031250 ),
29 ENTRY( 0.037163 ),ENTRY( 0.044194 ),ENTRY( 0.052556 ),ENTRY( 0.062500 ),
30 ENTRY( 0.074325 ),ENTRY( 0.088388 ),ENTRY( 0.105112 ),ENTRY( 0.125000 ),
31 ENTRY( 0.148651 ),ENTRY( 0.176777 ),ENTRY( 0.210224 ),ENTRY( 0.250000 ),
32 ENTRY( 0.297302 ),ENTRY( 0.353553 ),ENTRY( 0.420448 ),ENTRY( 0.500000 ),
33 ENTRY( 0.594604 ),ENTRY( 0.707107 ),ENTRY( 0.840896 ),ENTRY( 1.000000 ),
34 #undef ENTRY
35 };
36
37 int vol = (osc->control & 0x1F) - 0x1E * 2;
38
39 int left = vol + (osc->balance >> 3 & 0x1E) + (this->balance >> 3 & 0x1E);
40 if ( left < 0 ) left = 0;
41
42 int right = vol + (osc->balance << 1 & 0x1E) + (this->balance << 1 & 0x1E);
43 if ( right < 0 ) right = 0;
44
45 left = log_table [left ];
46 right = log_table [right];
47
48 // optimizing for the common case of being centered also allows easy
49 // panning using Effects_Buffer
50 osc->outputs [0] = osc->chans [0]; // center
51 osc->outputs [1] = 0;
52 if ( left != right )
53 {
54 osc->outputs [0] = osc->chans [1]; // left
55 osc->outputs [1] = osc->chans [2]; // right
56 }
57
58 if ( center_waves )
59 {
60 osc->last_amp [0] += (left - osc->volume [0]) * 16;
61 osc->last_amp [1] += (right - osc->volume [1]) * 16;
62 }
63
64 osc->volume [0] = left;
65 osc->volume [1] = right;
66}
67
68void Apu_init( struct Hes_Apu* this )
69{
70 struct Hes_Osc* osc = &this->oscs [osc_count];
71 do
72 {
73 osc--;
74 osc->outputs [0] = 0;
75 osc->outputs [1] = 0;
76 osc->chans [0] = 0;
77 osc->chans [1] = 0;
78 osc->chans [2] = 0;
79 }
80 while ( osc != this->oscs );
81
82 Apu_reset( this );
83}
84
85void Apu_reset( struct Hes_Apu* this )
86{
87 this->latch = 0;
88 this->balance = 0xFF;
89
90 struct Hes_Osc* osc = &this->oscs [osc_count];
91 do
92 {
93 osc--;
94 memset( osc, 0, offsetof (struct Hes_Osc,outputs) );
95 osc->noise_lfsr = 1;
96 osc->control = 0x40;
97 osc->balance = 0xFF;
98 }
99 while ( osc != this->oscs );
100}
101
102void Apu_osc_output( struct Hes_Apu* this, int index, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right )
103{
104 require( (unsigned) index < osc_count );
105 this->oscs [index].chans [0] = center;
106 this->oscs [index].chans [1] = left;
107 this->oscs [index].chans [2] = right;
108
109 struct Hes_Osc* osc = &this->oscs [osc_count];
110 do
111 {
112 osc--;
113 Apu_balance_changed( this, osc );
114 }
115 while ( osc != this->oscs );
116}
117
118void Osc_run_until( struct Hes_Osc* this, struct Blip_Synth* synth_, blip_time_t end_time )
119{
120 struct Blip_Buffer* const osc_outputs_0 = this->outputs [0]; // cache often-used values
121 if ( osc_outputs_0 && this->control & 0x80 )
122 {
123 int dac = this->dac;
124
125 int const volume_0 = this->volume [0];
126 {
127 int delta = dac * volume_0 - this->last_amp [0];
128 if ( delta )
129 Synth_offset( synth_, this->last_time, delta, osc_outputs_0 );
130 Blip_set_modified( osc_outputs_0 );
131 }
132
133 struct Blip_Buffer* const osc_outputs_1 = this->outputs [1];
134 int const volume_1 = this->volume [1];
135 if ( osc_outputs_1 )
136 {
137 int delta = dac * volume_1 - this->last_amp [1];
138 if ( delta )
139 Synth_offset( synth_, this->last_time, delta, osc_outputs_1 );
140 Blip_set_modified( osc_outputs_1 );
141 }
142
143 blip_time_t time = this->last_time + this->delay;
144 if ( time < end_time )
145 {
146 if ( this->noise & 0x80 )
147 {
148 if ( volume_0 | volume_1 )
149 {
150 // noise
151 int const period = (32 - (this->noise & 0x1F)) * 64; // TODO: correct?
152 unsigned noise_lfsr = this->noise_lfsr;
153 do
154 {
155 int new_dac = 0x1F & -(noise_lfsr >> 1 & 1);
156 // Implemented using "Galios configuration"
157 // TODO: find correct LFSR algorithm
158 noise_lfsr = (noise_lfsr >> 1) ^ (0xE008 & -(noise_lfsr & 1));
159 //noise_lfsr = (noise_lfsr >> 1) ^ (0x6000 & -(noise_lfsr & 1));
160 int delta = new_dac - dac;
161 if ( delta )
162 {
163 dac = new_dac;
164 Synth_offset( synth_, time, delta * volume_0, osc_outputs_0 );
165 if ( osc_outputs_1 )
166 Synth_offset( synth_, time, delta * volume_1, osc_outputs_1 );
167 }
168 time += period;
169 }
170 while ( time < end_time );
171
172 this->noise_lfsr = noise_lfsr;
173 assert( noise_lfsr );
174 }
175 }
176 else if ( !(this->control & 0x40) )
177 {
178 // wave
179 int phase = (this->phase + 1) & 0x1F; // pre-advance for optimal inner loop
180 int period = this->period * 2;
181 if ( period >= 14 && (volume_0 | volume_1) )
182 {
183 do
184 {
185 int new_dac = this->wave [phase];
186 phase = (phase + 1) & 0x1F;
187 int delta = new_dac - dac;
188 if ( delta )
189 {
190 dac = new_dac;
191 Synth_offset( synth_, time, delta * volume_0, osc_outputs_0 );
192 if ( osc_outputs_1 )
193 Synth_offset( synth_, time, delta * volume_1, osc_outputs_1 );
194 }
195 time += period;
196 }
197 while ( time < end_time );
198 }
199 else
200 {
201 if ( !period )
202 {
203 // TODO: Gekisha Boy assumes that period = 0 silences wave
204 //period = 0x1000 * 2;
205 period = 1;
206 //if ( !(volume_0 | volume_1) )
207 // dprintf( "Used period 0\n" );
208 }
209
210 // maintain phase when silent
211 blargg_long count = (end_time - time + period - 1) / period;
212 phase += count; // phase will be masked below
213 time += count * period;
214 }
215 this->phase = (phase - 1) & 0x1F; // undo pre-advance
216 }
217 }
218 time -= end_time;
219 if ( time < 0 )
220 time = 0;
221 this->delay = time;
222
223 this->dac = dac;
224 this->last_amp [0] = dac * volume_0;
225 this->last_amp [1] = dac * volume_1;
226 }
227 this->last_time = end_time;
228}
229
230void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data )
231{
232 if ( addr == 0x800 )
233 {
234 this->latch = data & 7;
235 }
236 else if ( addr == 0x801 )
237 {
238 if ( this->balance != data )
239 {
240 this->balance = data;
241
242 struct Hes_Osc* osc = &this->oscs [osc_count];
243 do
244 {
245 osc--;
246 Osc_run_until( osc, &this->synth, time );
247 Apu_balance_changed( this, this->oscs );
248 }
249 while ( osc != this->oscs );
250 }
251 }
252 else if ( this->latch < osc_count )
253 {
254 struct Hes_Osc* osc = &this->oscs [this->latch];
255 Osc_run_until( osc, &this->synth, time );
256 switch ( addr )
257 {
258 case 0x802:
259 osc->period = (osc->period & 0xF00) | data;
260 break;
261
262 case 0x803:
263 osc->period = (osc->period & 0x0FF) | ((data & 0x0F) << 8);
264 break;
265
266 case 0x804:
267 if ( osc->control & 0x40 & ~data )
268 osc->phase = 0;
269 osc->control = data;
270 Apu_balance_changed( this, osc );
271 break;
272
273 case 0x805:
274 osc->balance = data;
275 Apu_balance_changed( this, osc );
276 break;
277
278 case 0x806:
279 data &= 0x1F;
280 if ( !(osc->control & 0x40) )
281 {
282 osc->wave [osc->phase] = data;
283 osc->phase = (osc->phase + 1) & 0x1F;
284 }
285 else if ( osc->control & 0x80 )
286 {
287 osc->dac = data;
288 }
289 break;
290
291 case 0x807:
292 if ( osc >= &this->oscs [4] )
293 osc->noise = data;
294 break;
295 case 0x809:
296 if ( !(data & 0x80) && (data & 0x03) != 0 ) {
297 dprintf( "HES LFO not supported\n" );
298 }
299 }
300 }
301}
302
303void Apu_end_frame( struct Hes_Apu* this, blip_time_t end_time )
304{
305 struct Hes_Osc* osc = &this->oscs [osc_count];
306 do
307 {
308 osc--;
309 if ( end_time > osc->last_time )
310 Osc_run_until( osc, &this->synth, end_time );
311 assert( osc->last_time >= end_time );
312 osc->last_time -= end_time;
313 }
314 while ( osc != this->oscs );
315}
diff --git a/apps/codecs/libgme/hes_apu.h b/apps/codecs/libgme/hes_apu.h
new file mode 100644
index 0000000000..8a49a5afc7
--- /dev/null
+++ b/apps/codecs/libgme/hes_apu.h
@@ -0,0 +1,55 @@
1// Turbo Grafx 16 (PC Engine) PSG sound chip emulator
2
3// Game_Music_Emu 0.5.2
4#ifndef HES_APU_H
5#define HES_APU_H
6
7#include "blargg_common.h"
8#include "blip_buffer.h"
9
10enum { amp_range = 0x8000 };
11enum { osc_count = 6 };
12enum { start_addr = 0x0800 };
13enum { end_addr = 0x0809 };
14
15struct Hes_Osc
16{
17 unsigned char wave [32];
18 short volume [2];
19 int last_amp [2];
20 int delay;
21 int period;
22 unsigned char noise;
23 unsigned char phase;
24 unsigned char balance;
25 unsigned char dac;
26 blip_time_t last_time;
27
28 struct Blip_Buffer* outputs [2];
29 struct Blip_Buffer* chans [3];
30 unsigned noise_lfsr;
31 unsigned char control;
32};
33
34void Osc_run_until( struct Hes_Osc* this, struct Blip_Synth* synth, blip_time_t ) ICODE_ATTR;
35
36struct Hes_Apu {
37 struct Hes_Osc oscs [osc_count];
38
39 int latch;
40 int balance;
41 struct Blip_Synth synth;
42};
43
44// Init HES apu sound chip
45void Apu_init( struct Hes_Apu* this );
46
47// Reset HES apu couns chip
48void Apu_reset( struct Hes_Apu* this );
49
50void Apu_osc_output( struct Hes_Apu* this, int index, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right ) ICODE_ATTR;
51void Apu_write_data( struct Hes_Apu* this, blip_time_t, int addr, int data ) ICODE_ATTR;
52void Apu_end_frame( struct Hes_Apu* this, blip_time_t ) ICODE_ATTR;
53
54static inline void Apu_volume( struct Hes_Apu* this, double v ) { Synth_volume( &this->synth, 1.8 / osc_count / amp_range * v ); }
55#endif
diff --git a/apps/codecs/libgme/hes_apu_adpcm.c b/apps/codecs/libgme/hes_apu_adpcm.c
new file mode 100644
index 0000000000..b2f78ff71f
--- /dev/null
+++ b/apps/codecs/libgme/hes_apu_adpcm.c
@@ -0,0 +1,297 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "hes_apu_adpcm.h"
4
5/* Copyright (C) 2006-2008 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16
17void Adpcm_init( struct Hes_Apu_Adpcm* this )
18{
19 this->output = NULL;
20 memset( &this->state, 0, sizeof( this->state ) );
21 Adpcm_reset( this );
22}
23
24void Adpcm_reset( struct Hes_Apu_Adpcm* this )
25{
26 this->last_time = 0;
27 this->next_timer = 0;
28 this->last_amp = 0;
29
30 memset( &this->state.pcmbuf, 0, sizeof(this->state.pcmbuf) );
31 memset( &this->state.port, 0, sizeof(this->state.port) );
32
33 this->state.ad_sample = 0;
34 this->state.ad_ref_index = 0;
35
36 this->state.addr = 0;
37 this->state.freq = 0;
38 this->state.writeptr = 0;
39 this->state.readptr = 0;
40 this->state.playflag = 0;
41 this->state.repeatflag = 0;
42 this->state.length = 0;
43 this->state.volume = 0xFF;
44 this->state.fadetimer = 0;
45 this->state.fadecount = 0;
46}
47
48static short stepsize[49] = {
49 16, 17, 19, 21, 23, 25, 28,
50 31, 34, 37, 41, 45, 50, 55,
51 60, 66, 73, 80, 88, 97, 107,
52 118, 130, 143, 157, 173, 190, 209,
53 230, 253, 279, 307, 337, 371, 408,
54 449, 494, 544, 598, 658, 724, 796,
55 876, 963,1060,1166,1282,1411,1552
56};
57
58static int Adpcm_decode( struct Hes_Apu_Adpcm* this,int code ) ICODE_ATTR;
59static int Adpcm_decode( struct Hes_Apu_Adpcm* this,int code )
60{
61 struct State* state = &this->state;
62 int step = stepsize[state->ad_ref_index];
63 int delta;
64 int c = code & 7;
65#if 1
66 delta = 0;
67 if ( c & 4 ) delta += step;
68 step >>= 1;
69 if ( c & 2 ) delta += step;
70 step >>= 1;
71 if ( c & 1 ) delta += step;
72 step >>= 1;
73 delta += step;
74#else
75 delta = ( ( c + c + 1 ) * step ) / 8; // maybe faster, but introduces rounding
76#endif
77 if ( c != code )
78 {
79 state->ad_sample -= delta;
80 if ( state->ad_sample < -2048 )
81 state->ad_sample = -2048;
82 }
83 else
84 {
85 state->ad_sample += delta;
86 if ( state->ad_sample > 2047 )
87 state->ad_sample = 2047;
88 }
89
90 static int const steps [8] ICONST_ATTR = {
91 -1, -1, -1, -1, 2, 4, 6, 8
92 };
93 state->ad_ref_index += steps [c];
94 if ( state->ad_ref_index < 0 )
95 state->ad_ref_index = 0;
96 else if ( state->ad_ref_index > 48 )
97 state->ad_ref_index = 48;
98
99 return state->ad_sample;
100}
101
102static void Adpcm_run_until( struct Hes_Apu_Adpcm* this, blip_time_t end_time ) ICODE_ATTR;
103static void Adpcm_run_until( struct Hes_Apu_Adpcm* this, blip_time_t end_time )
104{
105 struct State* state = &this->state;
106 int volume = state->volume;
107 int fadetimer = state->fadetimer;
108 int fadecount = state->fadecount;
109 int last_time = this->last_time;
110 double next_timer = this->next_timer;
111 int last_amp = this->last_amp;
112
113 struct Blip_Buffer* output = this->output; // cache often-used values
114
115 while ( state->playflag && last_time < end_time )
116 {
117 while ( last_time >= next_timer )
118 {
119 if ( fadetimer )
120 {
121 if ( fadecount > 0 )
122 {
123 fadecount--;
124 volume = 0xFF * fadecount / fadetimer;
125 }
126 else if ( fadecount < 0 )
127 {
128 fadecount++;
129 volume = 0xFF - ( 0xFF * fadecount / fadetimer );
130 }
131 }
132 next_timer += 7159.091;
133 }
134 int amp;
135 if ( state->ad_low_nibble )
136 {
137 amp = Adpcm_decode( this, state->pcmbuf[ state->playptr ] & 0x0F );
138 state->ad_low_nibble = false;
139 state->playptr++;
140 state->playedsamplecount++;
141 if ( state->playedsamplecount == state->playlength )
142 {
143 state->playflag = 0;
144 }
145 }
146 else
147 {
148 amp = Adpcm_decode( this, state->pcmbuf[ state->playptr ] >> 4 );
149 state->ad_low_nibble = true;
150 }
151 amp = amp * volume / 0xFF;
152 int delta = amp - last_amp;
153 if ( output && delta )
154 {
155 last_amp = amp;
156 Synth_offset_inline( &this->synth, last_time, delta, output );
157 }
158 last_time += state->freq;
159 }
160
161 if ( !state->playflag )
162 {
163 while ( next_timer <= end_time ) next_timer += 7159.091;
164 last_time = end_time;
165 }
166
167 this->last_time = last_time;
168 this->next_timer = next_timer;
169 this->last_amp = last_amp;
170 state->volume = volume;
171 state->fadetimer = fadetimer;
172 state->fadecount = fadecount;
173}
174
175void Adpcm_write_data( struct Hes_Apu_Adpcm* this, blip_time_t time, int addr, int data )
176{
177 if ( time > this->last_time ) Adpcm_run_until( this, time );
178 struct State* state = &this->state;
179
180 data &= 0xFF;
181 state->port[ addr & 15 ] = data;
182 switch ( addr & 15 )
183 {
184 case 8:
185 state->addr &= 0xFF00;
186 state->addr |= data;
187 break;
188 case 9:
189 state->addr &= 0xFF;
190 state->addr |= data << 8;
191 break;
192 case 10:
193 state->pcmbuf[ state->writeptr++ ] = data;
194 state->playlength ++;
195 break;
196 case 11:
197 dprintf("ADPCM DMA 0x%02X", data);
198 break;
199 case 13:
200 if ( data & 0x80 )
201 {
202 state->addr = 0;
203 state->freq = 0;
204 state->writeptr = 0;
205 state->readptr = 0;
206 state->playflag = 0;
207 state->repeatflag = 0;
208 state->length = 0;
209 state->volume = 0xFF;
210 }
211 if ( ( data & 3 ) == 3 )
212 {
213 state->writeptr = state->addr;
214 }
215 if ( data & 8 )
216 {
217 state->readptr = state->addr ? state->addr - 1 : state->addr;
218 }
219 if ( data & 0x10 )
220 {
221 state->length = state->addr;
222 }
223 state->repeatflag = data & 0x20;
224 state->playflag = data & 0x40;
225 if ( state->playflag )
226 {
227 state->playptr = state->readptr;
228 state->playlength = state->length + 1;
229 state->playedsamplecount = 0;
230 state->ad_sample = 0;
231 state->ad_low_nibble = false;
232 }
233 break;
234 case 14:
235 state->freq = 7159091 / ( 32000 / ( 16 - ( data & 15 ) ) );
236 break;
237 case 15:
238 switch ( data & 15 )
239 {
240 case 0:
241 case 8:
242 case 12:
243 state->fadetimer = -100;
244 state->fadecount = state->fadetimer;
245 break;
246 case 10:
247 state->fadetimer = 5000;
248 state->fadecount = state->fadetimer;
249 break;
250 case 14:
251 state->fadetimer = 1500;
252 state->fadecount = state->fadetimer;
253 break;
254 }
255 break;
256 }
257}
258
259int Adpcm_read_data( struct Hes_Apu_Adpcm* this, blip_time_t time, int addr )
260{
261 if ( time > this->last_time ) Adpcm_run_until( this, time );
262
263 struct State* state = &this->state;
264 switch ( addr & 15 )
265 {
266 case 10:
267 return state->pcmbuf [state->readptr++];
268 case 11:
269 return state->port [11] & ~1;
270 case 12:
271 if (!state->playflag)
272 {
273 state->port [12] |= 1;
274 state->port [12] &= ~8;
275 }
276 else
277 {
278 state->port [12] &= ~1;
279 state->port [12] |= 8;
280 }
281 return state->port [12];
282 case 13:
283 return state->port [13];
284 }
285
286 return 0xFF;
287}
288
289void Adpcm_end_frame( struct Hes_Apu_Adpcm* this, blip_time_t end_time )
290{
291 Adpcm_run_until( this, end_time );
292 this->last_time -= end_time;
293 this->next_timer -= (double)end_time;
294 check( last_time >= 0 );
295 if ( this->output )
296 Blip_set_modified( this->output );
297}
diff --git a/apps/codecs/libgme/hes_apu_adpcm.h b/apps/codecs/libgme/hes_apu_adpcm.h
new file mode 100644
index 0000000000..5478f2b360
--- /dev/null
+++ b/apps/codecs/libgme/hes_apu_adpcm.h
@@ -0,0 +1,89 @@
1// Turbo Grafx 16 (PC Engine) ADPCM sound chip emulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef HES_APU_ADPCM_H
5#define HES_APU_ADPCM_H
6
7#include "blargg_source.h"
8#include "blargg_common.h"
9#include "blip_buffer.h"
10
11enum { adpcm_amp_range = 2048 };
12enum { adpcm_osc_count = 1 }; // 0 <= chan < osc_count
13
14// Registers are at io_addr to io_addr+io_size-1
15enum { io_addr = 0x1800 };
16enum { io_size = 0x400 };
17
18struct State
19{
20 byte pcmbuf [0x10000];
21 byte port [0x10];
22 int ad_sample;
23 int ad_ref_index;
24 bool ad_low_nibble;
25 int freq;
26 unsigned short addr;
27 unsigned short writeptr;
28 unsigned short readptr;
29 unsigned short playptr;
30 byte playflag;
31 byte repeatflag;
32 int length;
33 int playlength;
34 int playedsamplecount;
35 int volume;
36 int fadetimer;
37 int fadecount;
38};
39
40struct Hes_Apu_Adpcm {
41 struct State state;
42 struct Blip_Synth synth;
43
44 struct Blip_Buffer* output;
45 blip_time_t last_time;
46 double next_timer;
47 int last_amp;
48};
49
50// Init HES adpcm sound chip
51void Adpcm_init( struct Hes_Apu_Adpcm* this );
52
53// Rest HES adpcm sound chip
54void Adpcm_reset( struct Hes_Apu_Adpcm* this );
55
56// Sets buffer(s) to generate sound into, or 0 to mute. If only center is not 0,
57// output is mono.
58static inline void Adpcm_set_output( struct Hes_Apu_Adpcm* this, int chan, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right )
59{
60 // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL)
61 require( !center || (center && !left && !right) || (center && left && right) );
62 require( (unsigned) chan < adpcm_osc_count ); // fails if you pass invalid osc index
63
64#if defined(ROCKBOX)
65 (void) chan;
66#endif
67
68 if ( !center || !left || !right )
69 {
70 left = center;
71 right = center;
72 }
73
74 this->output = center;
75}
76
77// Emulates to time t, then writes data to addr
78void Adpcm_write_data( struct Hes_Apu_Adpcm* this, blip_time_t t, int addr, int data ) ICODE_ATTR;
79
80// Emulates to time t, then reads from addr
81int Adpcm_read_data( struct Hes_Apu_Adpcm* this, blip_time_t t, int addr ) ICODE_ATTR;
82
83// Emulates to time t, then subtracts t from the current time.
84// OK if previous write call had time slightly after t.
85void Adpcm_end_frame( struct Hes_Apu_Adpcm* this,blip_time_t t ) ICODE_ATTR;
86
87// Sets overall volume, where 1.0 is normal
88static inline void Adpcm_volume( struct Hes_Apu_Adpcm* this, double v ) { Synth_volume( &this->synth, 0.6 / adpcm_osc_count / adpcm_amp_range * v ); }
89#endif
diff --git a/apps/codecs/libgme/hes_cpu.c b/apps/codecs/libgme/hes_cpu.c
new file mode 100644
index 0000000000..08dfb5e993
--- /dev/null
+++ b/apps/codecs/libgme/hes_cpu.c
@@ -0,0 +1,1321 @@
1// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/
2
3#include "hes_cpu.h"
4
5#include "blargg_endian.h"
6
7//#include "hes_cpu_log.h"
8
9/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
10can redistribute it and/or modify it under the terms of the GNU Lesser
11General Public License as published by the Free Software Foundation; either
12version 2.1 of the License, or (at your option) any later version. This
13module is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16details. You should have received a copy of the GNU Lesser General Public
17License along with this module; if not, write to the Free Software Foundation,
18Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
19
20// TODO: support T flag, including clearing it at appropriate times?
21
22// all zero-page should really use whatever is at page 1, but that would
23// reduce efficiency quite a bit
24int const ram_addr = 0x2000;
25
26#define FLUSH_TIME() (void) (s.time = s_time)
27#define CACHE_TIME() (void) (s_time = s.time)
28
29#include "hes_cpu_io.h"
30
31#include "blargg_source.h"
32
33#ifdef BLARGG_NONPORTABLE
34 #define PAGE_OFFSET( addr ) (addr)
35#else
36 #define PAGE_OFFSET( addr ) ((addr) & (page_size - 1))
37#endif
38
39// status flags
40int const st_n = 0x80;
41int const st_v = 0x40;
42int const st_t = 0x20;
43int const st_b = 0x10;
44int const st_d = 0x08;
45int const st_i = 0x04;
46int const st_z = 0x02;
47int const st_c = 0x01;
48
49void Cpu_init( struct Hes_Cpu* this )
50{
51 this->state = &this->state_;
52}
53
54void Cpu_reset( struct Hes_Cpu* this )
55{
56 check( this->state == &state_ );
57 this->state = &this->state_;
58
59 this->state_.time = 0;
60 this->state_.base = 0;
61 this->irq_time = future_hes_time;
62 this->end_time = future_hes_time;
63
64 this->r.status = st_i;
65 this->r.sp = 0;
66 this->r.pc = 0;
67 this->r.a = 0;
68 this->r.x = 0;
69 this->r.y = 0;
70
71 blargg_verify_byte_order();
72}
73
74void Cpu_set_mmr( struct Hes_Emu* this, int reg, int bank )
75{
76 assert( (unsigned) reg <= page_count ); // allow page past end to be set
77 assert( (unsigned) bank < 0x100 );
78 this->cpu.mmr [reg] = bank;
79 uint8_t const* code = CPU_SET_MMR( this, reg, bank );
80 this->cpu.state->code_map [reg] = code - PAGE_OFFSET( reg << page_shift );
81}
82
83#define TIME (s_time + s.base)
84
85#define READ( addr ) CPU_READ( this, (addr), TIME )
86#define WRITE( addr, data ) {CPU_WRITE( this, (addr), (data), TIME );}
87#define READ_LOW( addr ) (cpu->ram [(int) (addr)])
88#define WRITE_LOW( addr, data ) (void) (READ_LOW( addr ) = (data))
89#define READ_PROG( addr ) (s.code_map [(addr) >> page_shift] [PAGE_OFFSET( addr )])
90
91#define SET_SP( v ) (sp = ((v) + 1) | 0x100)
92#define GET_SP() ((sp - 1) & 0xFF)
93#define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v ))
94
95// even on x86, using short and unsigned char was slower
96typedef int fint16;
97typedef unsigned fuint16;
98typedef unsigned fuint8;
99typedef blargg_long fint32;
100
101bool Cpu_run( struct Hes_Emu* this, hes_time_t end_time )
102{
103 bool illegal_encountered = false;
104
105 // Set cpu end time
106 struct Hes_Cpu* cpu = &this->cpu;
107 cpu->state->time += Cpu_update_end_time( cpu, cpu->r.status, (cpu->end_time = end_time), cpu->irq_time );
108
109 struct state_t s = cpu->state_;
110 cpu->state = &s;
111
112 // even on x86, using s.time in place of s_time was slower
113 fint16 s_time = s.time;
114
115 struct registers_t* r = &cpu->r;
116
117 // registers
118 fuint16 pc = r->pc;
119 fuint8 a = r->a;
120 fuint8 x = r->x;
121 fuint8 y = r->y;
122 fuint16 sp;
123 SET_SP( r->sp );
124
125 #define IS_NEG (nz & 0x8080)
126
127 #define CALC_STATUS( out ) do {\
128 out = status & (st_v | st_d | st_i);\
129 out |= ((nz >> 8) | nz) & st_n;\
130 out |= c >> 8 & st_c;\
131 if ( !(nz & 0xFF) ) out |= st_z;\
132 } while ( 0 )
133
134 #define SET_STATUS( in ) do {\
135 status = in & (st_v | st_d | st_i);\
136 nz = in << 8;\
137 c = nz;\
138 nz |= ~in & st_z;\
139 } while ( 0 )
140
141 fuint8 status;
142 fuint16 c; // carry set if (c & 0x100) != 0
143 fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
144 {
145 fuint8 temp = r->status;
146 SET_STATUS( temp );
147 }
148
149 goto loop;
150branch_not_taken:
151 s_time -= 2;
152loop:
153
154 #ifndef NDEBUG
155 {
156 hes_time_t correct = end_time_;
157 if ( !(status & st_i) && correct > irq_time_ )
158 correct = irq_time_;
159 check( s.base == correct );
160 /*
161 static long count;
162 if ( count == 1844 ) Debugger();
163 if ( s.base != correct ) dprintf( "%ld\n", count );
164 count++;
165 */
166 }
167 #endif
168
169 check( (unsigned) GET_SP() < 0x100 );
170 check( (unsigned) a < 0x100 );
171 check( (unsigned) x < 0x100 );
172
173 uint8_t const* instr = s.code_map [pc >> page_shift];
174 fuint8 opcode;
175
176 // TODO: eliminate this special case
177 #ifdef BLARGG_NONPORTABLE
178 opcode = instr [pc];
179 pc++;
180 instr += pc;
181 #else
182 instr += PAGE_OFFSET( pc );
183 opcode = *instr++;
184 pc++;
185 #endif
186
187 // TODO: each reference lists slightly different timing values, ugh
188 static uint8_t const clock_table [256] ICONST_ATTR =
189 {// 0 1 2 3 4 5 6 7 8 9 A B C D E F
190 1,7,3, 4,6,4,6,7,3,2,2,2,7,5,7,6,// 0
191 4,7,7, 4,6,4,6,7,2,5,2,2,7,5,7,6,// 1
192 7,7,3, 4,4,4,6,7,4,2,2,2,5,5,7,6,// 2
193 4,7,7, 2,4,4,6,7,2,5,2,2,5,5,7,6,// 3
194 7,7,3, 4,8,4,6,7,3,2,2,2,4,5,7,6,// 4
195 4,7,7, 5,2,4,6,7,2,5,3,2,2,5,7,6,// 5
196 7,7,2, 2,4,4,6,7,4,2,2,2,7,5,7,6,// 6
197 4,7,7,17,4,4,6,7,2,5,4,2,7,5,7,6,// 7
198 4,7,2, 7,4,4,4,7,2,2,2,2,5,5,5,6,// 8
199 4,7,7, 8,4,4,4,7,2,5,2,2,5,5,5,6,// 9
200 2,7,2, 7,4,4,4,7,2,2,2,2,5,5,5,6,// A
201 4,7,7, 8,4,4,4,7,2,5,2,2,5,5,5,6,// B
202 2,7,2,17,4,4,6,7,2,2,2,2,5,5,7,6,// C
203 4,7,7,17,2,4,6,7,2,5,3,2,2,5,7,6,// D
204 2,7,2,17,4,4,6,7,2,2,2,2,5,5,7,6,// E
205 4,7,7,17,2,4,6,7,2,5,4,2,2,5,7,6 // F
206 }; // 0x00 was 8
207
208 fuint16 data;
209 data = clock_table [opcode];
210 if ( (s_time += data) >= 0 )
211 goto possibly_out_of_time;
212almost_out_of_time:
213
214 data = *instr;
215
216 #ifdef HES_CPU_LOG_H
217 log_cpu( "new", pc - 1, opcode, instr [0], instr [1], instr [2],
218 instr [3], instr [4], instr [5] );
219 //log_opcode( opcode );
220 #endif
221
222 switch ( opcode )
223 {
224possibly_out_of_time:
225 if ( s_time < (int) data )
226 goto almost_out_of_time;
227 s_time -= data;
228 goto out_of_time;
229
230// Macros
231
232#define GET_MSB() (instr [1])
233#define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB());
234#define GET_ADDR() GET_LE16( instr )
235
236// TODO: is the penalty really always added? the original 6502 was much better
237//#define PAGE_CROSS_PENALTY( lsb ) (void) (s_time += (lsb) >> 8)
238#define PAGE_CROSS_PENALTY( lsb )
239
240// Branch
241
242// TODO: more efficient way to handle negative branch that wraps PC around
243#define BRANCH( cond )\
244{\
245 fint16 offset = (int8_t) data;\
246 pc++;\
247 if ( !(cond) ) goto branch_not_taken;\
248 pc = (uint16_t) (pc + offset);\
249 goto loop;\
250}
251
252 case 0xF0: // BEQ
253 BRANCH( !((uint8_t) nz) );
254
255 case 0xD0: // BNE
256 BRANCH( (uint8_t) nz );
257
258 case 0x10: // BPL
259 BRANCH( !IS_NEG );
260
261 case 0x90: // BCC
262 BRANCH( !(c & 0x100) )
263
264 case 0x30: // BMI
265 BRANCH( IS_NEG )
266
267 case 0x50: // BVC
268 BRANCH( !(status & st_v) )
269
270 case 0x70: // BVS
271 BRANCH( status & st_v )
272
273 case 0xB0: // BCS
274 BRANCH( c & 0x100 )
275
276 case 0x80: // BRA
277 branch_taken:
278 BRANCH( true );
279
280 case 0xFF:
281 if ( pc == idle_addr + 1 )
282 goto idle_done;
283 case 0x0F: // BBRn
284 case 0x1F:
285 case 0x2F:
286 case 0x3F:
287 case 0x4F:
288 case 0x5F:
289 case 0x6F:
290 case 0x7F:
291 case 0x8F: // BBSn
292 case 0x9F:
293 case 0xAF:
294 case 0xBF:
295 case 0xCF:
296 case 0xDF:
297 case 0xEF: {
298 fuint16 t = 0x101 * READ_LOW( data );
299 t ^= 0xFF;
300 pc++;
301 data = GET_MSB();
302 BRANCH( t & (1 << (opcode >> 4)) )
303 }
304
305 case 0x4C: // JMP abs
306 pc = GET_ADDR();
307 goto loop;
308
309 case 0x7C: // JMP (ind+X)
310 data += x;
311 case 0x6C:{// JMP (ind)
312 data += 0x100 * GET_MSB();
313 pc = GET_LE16( &READ_PROG( data ) );
314 goto loop;
315 }
316
317// Subroutine
318
319 case 0x44: // BSR
320 WRITE_LOW( 0x100 | (sp - 1), pc >> 8 );
321 sp = (sp - 2) | 0x100;
322 WRITE_LOW( sp, pc );
323 goto branch_taken;
324
325 case 0x20: { // JSR
326 fuint16 temp = pc + 1;
327 pc = GET_ADDR();
328 WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
329 sp = (sp - 2) | 0x100;
330 WRITE_LOW( sp, temp );
331 goto loop;
332 }
333
334 case 0x60: // RTS
335 pc = 0x100 * READ_LOW( 0x100 | (sp - 0xFF) );
336 pc += 1 + READ_LOW( sp );
337 sp = (sp - 0xFE) | 0x100;
338 goto loop;
339
340 case 0x00: // BRK
341 goto handle_brk;
342
343// Common
344
345 case 0xBD:{// LDA abs,X
346 PAGE_CROSS_PENALTY( data + x );
347 fuint16 addr = GET_ADDR() + x;
348 pc += 2;
349 CPU_READ_FAST( this, addr, TIME, nz );
350 a = nz;
351 goto loop;
352 }
353
354 case 0x9D:{// STA abs,X
355 fuint16 addr = GET_ADDR() + x;
356 pc += 2;
357 CPU_WRITE_FAST( this, addr, a, TIME );
358 goto loop;
359 }
360
361 case 0x95: // STA zp,x
362 data = (uint8_t) (data + x);
363 case 0x85: // STA zp
364 pc++;
365 WRITE_LOW( data, a );
366 goto loop;
367
368 case 0xAE:{// LDX abs
369 fuint16 addr = GET_ADDR();
370 pc += 2;
371 CPU_READ_FAST( this, addr, TIME, nz );
372 x = nz;
373 goto loop;
374 }
375
376 case 0xA5: // LDA zp
377 a = nz = READ_LOW( data );
378 pc++;
379 goto loop;
380
381// Load/store
382
383 {
384 fuint16 addr;
385 case 0x91: // STA (ind),Y
386 addr = 0x100 * READ_LOW( (uint8_t) (data + 1) );
387 addr += READ_LOW( data ) + y;
388 pc++;
389 goto sta_ptr;
390
391 case 0x81: // STA (ind,X)
392 data = (uint8_t) (data + x);
393 case 0x92: // STA (ind)
394 addr = 0x100 * READ_LOW( (uint8_t) (data + 1) );
395 addr += READ_LOW( data );
396 pc++;
397 goto sta_ptr;
398
399 case 0x99: // STA abs,Y
400 data += y;
401 case 0x8D: // STA abs
402 addr = data + 0x100 * GET_MSB();
403 pc += 2;
404 sta_ptr:
405 CPU_WRITE_FAST( this, addr, a, TIME );
406 goto loop;
407 }
408
409 {
410 fuint16 addr;
411 case 0xA1: // LDA (ind,X)
412 data = (uint8_t) (data + x);
413 case 0xB2: // LDA (ind)
414 addr = 0x100 * READ_LOW( (uint8_t) (data + 1) );
415 addr += READ_LOW( data );
416 pc++;
417 goto a_nz_read_addr;
418
419 case 0xB1:// LDA (ind),Y
420 addr = READ_LOW( data ) + y;
421 PAGE_CROSS_PENALTY( addr );
422 addr += 0x100 * READ_LOW( (uint8_t) (data + 1) );
423 pc++;
424 goto a_nz_read_addr;
425
426 case 0xB9: // LDA abs,Y
427 data += y;
428 PAGE_CROSS_PENALTY( data );
429 case 0xAD: // LDA abs
430 addr = data + 0x100 * GET_MSB();
431 pc += 2;
432 a_nz_read_addr:
433 CPU_READ_FAST( this, addr, TIME, nz );
434 a = nz;
435 goto loop;
436 }
437
438 case 0xBE:{// LDX abs,y
439 PAGE_CROSS_PENALTY( data + y );
440 fuint16 addr = GET_ADDR() + y;
441 pc += 2;
442 FLUSH_TIME();
443 x = nz = READ( addr );
444 CACHE_TIME();
445 goto loop;
446 }
447
448 case 0xB5: // LDA zp,x
449 a = nz = READ_LOW( (uint8_t) (data + x) );
450 pc++;
451 goto loop;
452
453 case 0xA9: // LDA #imm
454 pc++;
455 a = data;
456 nz = data;
457 goto loop;
458
459// Bit operations
460
461 case 0x3C: // BIT abs,x
462 data += x;
463 case 0x2C:{// BIT abs
464 fuint16 addr;
465 ADD_PAGE( addr );
466 FLUSH_TIME();
467 nz = READ( addr );
468 CACHE_TIME();
469 goto bit_common;
470 }
471 case 0x34: // BIT zp,x
472 data = (uint8_t) (data + x);
473 case 0x24: // BIT zp
474 data = READ_LOW( data );
475 case 0x89: // BIT imm
476 nz = data;
477 bit_common:
478 pc++;
479 status &= ~st_v;
480 status |= nz & st_v;
481 if ( nz & a )
482 goto loop; // Z should be clear, and nz must be non-zero if nz & a is
483 nz <<= 8; // set Z flag without affecting N flag
484 goto loop;
485
486 {
487 fuint16 addr;
488
489 case 0xB3: // TST abs,x
490 addr = GET_MSB() + x;
491 goto tst_abs;
492
493 case 0x93: // TST abs
494 addr = GET_MSB();
495 tst_abs:
496 addr += 0x100 * instr [2];
497 pc++;
498 FLUSH_TIME();
499 nz = READ( addr );
500 CACHE_TIME();
501 goto tst_common;
502 }
503
504 case 0xA3: // TST zp,x
505 nz = READ_LOW( (uint8_t) (GET_MSB() + x) );
506 goto tst_common;
507
508 case 0x83: // TST zp
509 nz = READ_LOW( GET_MSB() );
510 tst_common:
511 pc += 2;
512 status &= ~st_v;
513 status |= nz & st_v;
514 if ( nz & data )
515 goto loop; // Z should be clear, and nz must be non-zero if nz & data is
516 nz <<= 8; // set Z flag without affecting N flag
517 goto loop;
518
519 {
520 fuint16 addr;
521 case 0x0C: // TSB abs
522 case 0x1C: // TRB abs
523 addr = GET_ADDR();
524 pc++;
525 goto txb_addr;
526
527 // TODO: everyone lists different behaviors for the status flags, ugh
528 case 0x04: // TSB zp
529 case 0x14: // TRB zp
530 addr = data + ram_addr;
531 txb_addr:
532 FLUSH_TIME();
533 nz = a | READ( addr );
534 if ( opcode & 0x10 )
535 nz ^= a; // bits from a will already be set, so this clears them
536 status &= ~st_v;
537 status |= nz & st_v;
538 pc++;
539 WRITE( addr, nz );
540 CACHE_TIME();
541 goto loop;
542 }
543
544 case 0x07: // RMBn
545 case 0x17:
546 case 0x27:
547 case 0x37:
548 case 0x47:
549 case 0x57:
550 case 0x67:
551 case 0x77:
552 pc++;
553 READ_LOW( data ) &= ~(1 << (opcode >> 4));
554 goto loop;
555
556 case 0x87: // SMBn
557 case 0x97:
558 case 0xA7:
559 case 0xB7:
560 case 0xC7:
561 case 0xD7:
562 case 0xE7:
563 case 0xF7:
564 pc++;
565 READ_LOW( data ) |= 1 << ((opcode >> 4) - 8);
566 goto loop;
567
568// Load/store
569
570 case 0x9E: // STZ abs,x
571 data += x;
572 case 0x9C: // STZ abs
573 ADD_PAGE( data );
574 pc++;
575 FLUSH_TIME();
576 WRITE( data, 0 );
577 CACHE_TIME();
578 goto loop;
579
580 case 0x74: // STZ zp,x
581 data = (uint8_t) (data + x);
582 case 0x64: // STZ zp
583 pc++;
584 WRITE_LOW( data, 0 );
585 goto loop;
586
587 case 0x94: // STY zp,x
588 data = (uint8_t) (data + x);
589 case 0x84: // STY zp
590 pc++;
591 WRITE_LOW( data, y );
592 goto loop;
593
594 case 0x96: // STX zp,y
595 data = (uint8_t) (data + y);
596 case 0x86: // STX zp
597 pc++;
598 WRITE_LOW( data, x );
599 goto loop;
600
601 case 0xB6: // LDX zp,y
602 data = (uint8_t) (data + y);
603 case 0xA6: // LDX zp
604 data = READ_LOW( data );
605 case 0xA2: // LDX #imm
606 pc++;
607 x = data;
608 nz = data;
609 goto loop;
610
611 case 0xB4: // LDY zp,x
612 data = (uint8_t) (data + x);
613 case 0xA4: // LDY zp
614 data = READ_LOW( data );
615 case 0xA0: // LDY #imm
616 pc++;
617 y = data;
618 nz = data;
619 goto loop;
620
621 case 0xBC: // LDY abs,X
622 data += x;
623 PAGE_CROSS_PENALTY( data );
624 case 0xAC:{// LDY abs
625 fuint16 addr = data + 0x100 * GET_MSB();
626 pc += 2;
627 FLUSH_TIME();
628 y = nz = READ( addr );
629 CACHE_TIME();
630 goto loop;
631 }
632
633 {
634 fuint8 temp;
635 case 0x8C: // STY abs
636 temp = y;
637 goto store_abs;
638
639 case 0x8E: // STX abs
640 temp = x;
641 store_abs:
642 {
643 fuint16 addr = GET_ADDR();
644 pc += 2;
645 FLUSH_TIME();
646 WRITE( addr, temp );
647 CACHE_TIME();
648 goto loop;
649 }
650 }
651
652// Compare
653
654 case 0xEC:{// CPX abs
655 fuint16 addr = GET_ADDR();
656 pc++;
657 FLUSH_TIME();
658 data = READ( addr );
659 CACHE_TIME();
660 goto cpx_data;
661 }
662
663 case 0xE4: // CPX zp
664 data = READ_LOW( data );
665 case 0xE0: // CPX #imm
666 cpx_data:
667 nz = x - data;
668 pc++;
669 c = ~nz;
670 nz &= 0xFF;
671 goto loop;
672
673 case 0xCC:{// CPY abs
674 fuint16 addr = GET_ADDR();
675 pc++;
676 FLUSH_TIME();
677 data = READ( addr );
678 CACHE_TIME();
679 goto cpy_data;
680 }
681
682 case 0xC4: // CPY zp
683 data = READ_LOW( data );
684 case 0xC0: // CPY #imm
685 cpy_data:
686 nz = y - data;
687 pc++;
688 c = ~nz;
689 nz &= 0xFF;
690 goto loop;
691
692// Logical
693
694#define ARITH_ADDR_MODES( op )\
695 case op - 0x04: /* (ind,x) */\
696 data = (uint8_t) (data + x);\
697 case op + 0x0D: /* (ind) */\
698 data = 0x100 * READ_LOW( (uint8_t) (data + 1) ) + READ_LOW( data );\
699 goto ptr##op;\
700 case op + 0x0C:{/* (ind),y */\
701 fuint16 temp = READ_LOW( data ) + y;\
702 PAGE_CROSS_PENALTY( temp );\
703 data = temp + 0x100 * READ_LOW( (uint8_t) (data + 1) );\
704 goto ptr##op;\
705 }\
706 case op + 0x10: /* zp,X */\
707 data = (uint8_t) (data + x);\
708 case op + 0x00: /* zp */\
709 data = READ_LOW( data );\
710 goto imm##op;\
711 case op + 0x14: /* abs,Y */\
712 data += y;\
713 goto ind##op;\
714 case op + 0x18: /* abs,X */\
715 data += x;\
716 ind##op:\
717 PAGE_CROSS_PENALTY( data );\
718 case op + 0x08: /* abs */\
719 ADD_PAGE( data );\
720 ptr##op:\
721 FLUSH_TIME();\
722 data = READ( data );\
723 CACHE_TIME();\
724 case op + 0x04: /* imm */\
725 imm##op:
726
727 ARITH_ADDR_MODES( 0xC5 ) // CMP
728 nz = a - data;
729 pc++;
730 c = ~nz;
731 nz &= 0xFF;
732 goto loop;
733
734 ARITH_ADDR_MODES( 0x25 ) // AND
735 nz = (a &= data);
736 pc++;
737 goto loop;
738
739 ARITH_ADDR_MODES( 0x45 ) // EOR
740 nz = (a ^= data);
741 pc++;
742 goto loop;
743
744 ARITH_ADDR_MODES( 0x05 ) // ORA
745 nz = (a |= data);
746 pc++;
747 goto loop;
748
749// Add/subtract
750
751 ARITH_ADDR_MODES( 0xE5 ) // SBC
752 data ^= 0xFF;
753 goto adc_imm;
754
755 ARITH_ADDR_MODES( 0x65 ) // ADC
756 adc_imm: {
757 if ( status & st_d ) {
758 dprintf( "Decimal mode not supported\n" );
759 }
760 fint16 carry = c >> 8 & 1;
761 fint16 ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend
762 status &= ~st_v;
763 status |= ov >> 2 & 0x40;
764 c = nz = a + data + carry;
765 pc++;
766 a = (uint8_t) nz;
767 goto loop;
768 }
769
770// Shift/rotate
771
772 case 0x4A: // LSR A
773 c = 0;
774 case 0x6A: // ROR A
775 nz = c >> 1 & 0x80;
776 c = a << 8;
777 nz |= a >> 1;
778 a = nz;
779 goto loop;
780
781 case 0x0A: // ASL A
782 nz = a << 1;
783 c = nz;
784 a = (uint8_t) nz;
785 goto loop;
786
787 case 0x2A: { // ROL A
788 nz = a << 1;
789 fint16 temp = c >> 8 & 1;
790 c = nz;
791 nz |= temp;
792 a = (uint8_t) nz;
793 goto loop;
794 }
795
796 case 0x5E: // LSR abs,X
797 data += x;
798 case 0x4E: // LSR abs
799 c = 0;
800 case 0x6E: // ROR abs
801 ror_abs: {
802 ADD_PAGE( data );
803 FLUSH_TIME();
804 int temp = READ( data );
805 nz = (c >> 1 & 0x80) | (temp >> 1);
806 c = temp << 8;
807 goto rotate_common;
808 }
809
810 case 0x3E: // ROL abs,X
811 data += x;
812 goto rol_abs;
813
814 case 0x1E: // ASL abs,X
815 data += x;
816 case 0x0E: // ASL abs
817 c = 0;
818 case 0x2E: // ROL abs
819 rol_abs:
820 ADD_PAGE( data );
821 nz = c >> 8 & 1;
822 FLUSH_TIME();
823 nz |= (c = READ( data ) << 1);
824 rotate_common:
825 pc++;
826 WRITE( data, (uint8_t) nz );
827 CACHE_TIME();
828 goto loop;
829
830 case 0x7E: // ROR abs,X
831 data += x;
832 goto ror_abs;
833
834 case 0x76: // ROR zp,x
835 data = (uint8_t) (data + x);
836 goto ror_zp;
837
838 case 0x56: // LSR zp,x
839 data = (uint8_t) (data + x);
840 case 0x46: // LSR zp
841 c = 0;
842 case 0x66: // ROR zp
843 ror_zp: {
844 int temp = READ_LOW( data );
845 nz = (c >> 1 & 0x80) | (temp >> 1);
846 c = temp << 8;
847 goto write_nz_zp;
848 }
849
850 case 0x36: // ROL zp,x
851 data = (uint8_t) (data + x);
852 goto rol_zp;
853
854 case 0x16: // ASL zp,x
855 data = (uint8_t) (data + x);
856 case 0x06: // ASL zp
857 c = 0;
858 case 0x26: // ROL zp
859 rol_zp:
860 nz = c >> 8 & 1;
861 nz |= (c = READ_LOW( data ) << 1);
862 goto write_nz_zp;
863
864// Increment/decrement
865
866#define INC_DEC_AXY( reg, n ) reg = (uint8_t) (nz = reg + n); goto loop;
867
868 case 0x1A: // INA
869 INC_DEC_AXY( a, +1 )
870
871 case 0xE8: // INX
872 INC_DEC_AXY( x, +1 )
873
874 case 0xC8: // INY
875 INC_DEC_AXY( y, +1 )
876
877 case 0x3A: // DEA
878 INC_DEC_AXY( a, -1 )
879
880 case 0xCA: // DEX
881 INC_DEC_AXY( x, -1 )
882
883 case 0x88: // DEY
884 INC_DEC_AXY( y, -1 )
885
886 case 0xF6: // INC zp,x
887 data = (uint8_t) (data + x);
888 case 0xE6: // INC zp
889 nz = 1;
890 goto add_nz_zp;
891
892 case 0xD6: // DEC zp,x
893 data = (uint8_t) (data + x);
894 case 0xC6: // DEC zp
895 nz = (unsigned) -1;
896 add_nz_zp:
897 nz += READ_LOW( data );
898 write_nz_zp:
899 pc++;
900 WRITE_LOW( data, nz );
901 goto loop;
902
903 case 0xFE: // INC abs,x
904 data = x + GET_ADDR();
905 goto inc_ptr;
906
907 case 0xEE: // INC abs
908 data = GET_ADDR();
909 inc_ptr:
910 nz = 1;
911 goto inc_common;
912
913 case 0xDE: // DEC abs,x
914 data = x + GET_ADDR();
915 goto dec_ptr;
916
917 case 0xCE: // DEC abs
918 data = GET_ADDR();
919 dec_ptr:
920 nz = (unsigned) -1;
921 inc_common:
922 FLUSH_TIME();
923 nz += READ( data );
924 pc += 2;
925 WRITE( data, (uint8_t) nz );
926 CACHE_TIME();
927 goto loop;
928
929// Transfer
930
931 case 0xA8: // TAY
932 y = a;
933 nz = a;
934 goto loop;
935
936 case 0x98: // TYA
937 a = y;
938 nz = y;
939 goto loop;
940
941 case 0xAA: // TAX
942 x = a;
943 nz = a;
944 goto loop;
945
946 case 0x8A: // TXA
947 a = x;
948 nz = x;
949 goto loop;
950
951 case 0x9A: // TXS
952 SET_SP( x ); // verified (no flag change)
953 goto loop;
954
955 case 0xBA: // TSX
956 x = nz = GET_SP();
957 goto loop;
958
959 #define SWAP_REGS( r1, r2 ) {\
960 fuint8 t = r1;\
961 r1 = r2;\
962 r2 = t;\
963 goto loop;\
964 }
965
966 case 0x02: // SXY
967 SWAP_REGS( x, y );
968
969 case 0x22: // SAX
970 SWAP_REGS( a, x );
971
972 case 0x42: // SAY
973 SWAP_REGS( a, y );
974
975 case 0x62: // CLA
976 a = 0;
977 goto loop;
978
979 case 0x82: // CLX
980 x = 0;
981 goto loop;
982
983 case 0xC2: // CLY
984 y = 0;
985 goto loop;
986
987// Stack
988
989 case 0x48: // PHA
990 PUSH( a );
991 goto loop;
992
993 case 0xDA: // PHX
994 PUSH( x );
995 goto loop;
996
997 case 0x5A: // PHY
998 PUSH( y );
999 goto loop;
1000
1001 case 0x40:{// RTI
1002 fuint8 temp = READ_LOW( sp );
1003 pc = READ_LOW( 0x100 | (sp - 0xFF) );
1004 pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100;
1005 sp = (sp - 0xFD) | 0x100;
1006 data = status;
1007 SET_STATUS( temp );
1008 r->status = status; // update externally-visible I flag
1009 if ( (data ^ status) & st_i )
1010 {
1011 hes_time_t new_time = cpu->end_time;
1012 if ( !(status & st_i) && new_time > cpu->irq_time )
1013 new_time = cpu->irq_time;
1014 blargg_long delta = s.base - new_time;
1015 s.base = new_time;
1016 s_time += delta;
1017 }
1018 goto loop;
1019 }
1020
1021 #define POP() READ_LOW( sp ); sp = (sp - 0xFF) | 0x100
1022
1023 case 0x68: // PLA
1024 a = nz = POP();
1025 goto loop;
1026
1027 case 0xFA: // PLX
1028 x = nz = POP();
1029 goto loop;
1030
1031 case 0x7A: // PLY
1032 y = nz = POP();
1033 goto loop;
1034
1035 case 0x28:{// PLP
1036 fuint8 temp = POP();
1037 fuint8 changed = status ^ temp;
1038 SET_STATUS( temp );
1039 if ( !(changed & st_i) )
1040 goto loop; // I flag didn't change
1041 if ( status & st_i )
1042 goto handle_sei;
1043 goto handle_cli;
1044 }
1045 #undef POP
1046
1047 case 0x08: { // PHP
1048 fuint8 temp;
1049 CALC_STATUS( temp );
1050 PUSH( temp | st_b );
1051 goto loop;
1052 }
1053
1054// Flags
1055
1056 case 0x38: // SEC
1057 c = (unsigned) ~0;
1058 goto loop;
1059
1060 case 0x18: // CLC
1061 c = 0;
1062 goto loop;
1063
1064 case 0xB8: // CLV
1065 status &= ~st_v;
1066 goto loop;
1067
1068 case 0xD8: // CLD
1069 status &= ~st_d;
1070 goto loop;
1071
1072 case 0xF8: // SED
1073 status |= st_d;
1074 goto loop;
1075
1076 case 0x58: // CLI
1077 if ( !(status & st_i) )
1078 goto loop;
1079 status &= ~st_i;
1080 handle_cli: {
1081 r->status = status; // update externally-visible I flag
1082 blargg_long delta = s.base - cpu->irq_time;
1083 if ( delta <= 0 )
1084 {
1085 if ( TIME < cpu->irq_time )
1086 goto loop;
1087 goto delayed_cli;
1088 }
1089 s.base = cpu->irq_time;
1090 s_time += delta;
1091 if ( s_time < 0 )
1092 goto loop;
1093
1094 if ( delta >= s_time + 1 )
1095 {
1096 // delayed irq until after next instruction
1097 s.base += s_time + 1;
1098 s_time = -1;
1099 cpu->irq_time = s.base; // TODO: remove, as only to satisfy debug check in loop
1100 goto loop;
1101 }
1102 delayed_cli:
1103 dprintf( "Delayed CLI not supported\n" ); // TODO: implement
1104 goto loop;
1105 }
1106
1107 case 0x78: // SEI
1108 if ( status & st_i )
1109 goto loop;
1110 status |= st_i;
1111 handle_sei: {
1112 r->status = status; // update externally-visible I flag
1113 blargg_long delta = s.base - cpu->end_time;
1114 s.base = cpu->end_time;
1115 s_time += delta;
1116 if ( s_time < 0 )
1117 goto loop;
1118 dprintf( "Delayed SEI not supported\n" ); // TODO: implement
1119 goto loop;
1120 }
1121
1122// Special
1123
1124 case 0x53:{// TAM
1125 fuint8 const bits = data; // avoid using data across function call
1126 pc++;
1127 int i;
1128 for ( i = 0; i < 8; i++ )
1129 if ( bits & (1 << i) )
1130 /* this->cpu.set_mmr( i, a ); */
1131 Cpu_set_mmr( this, i, a );
1132 goto loop;
1133 }
1134
1135 case 0x43:{// TMA
1136 pc++;
1137 byte const* in = cpu->mmr;
1138 do
1139 {
1140 if ( data & 1 )
1141 a = *in;
1142 in++;
1143 }
1144 while ( (data >>= 1) != 0 );
1145 goto loop;
1146 }
1147
1148 case 0x03: // ST0
1149 case 0x13: // ST1
1150 case 0x23:{// ST2
1151 fuint16 addr = opcode >> 4;
1152 if ( addr )
1153 addr++;
1154 pc++;
1155 FLUSH_TIME();
1156 CPU_WRITE_VDP( this, addr, data, TIME );
1157 CACHE_TIME();
1158 goto loop;
1159 }
1160
1161 case 0xEA: // NOP
1162 goto loop;
1163
1164 case 0x54: // CSL
1165 dprintf( "CSL not supported\n" );
1166 illegal_encountered = true;
1167 goto loop;
1168
1169 case 0xD4: // CSH
1170 goto loop;
1171
1172 case 0xF4: { // SET
1173 //fuint16 operand = GET_MSB();
1174 dprintf( "SET not handled\n" );
1175 //switch ( data )
1176 //{
1177 //}
1178 illegal_encountered = true;
1179 goto loop;
1180 }
1181
1182// Block transfer
1183
1184 {
1185 fuint16 in_alt;
1186 fint16 in_inc;
1187 fuint16 out_alt;
1188 fint16 out_inc;
1189
1190 case 0xE3: // TIA
1191 in_alt = 0;
1192 goto bxfer_alt;
1193
1194 case 0xF3: // TAI
1195 in_alt = 1;
1196 bxfer_alt:
1197 in_inc = in_alt ^ 1;
1198 out_alt = in_inc;
1199 out_inc = in_alt;
1200 goto bxfer;
1201
1202 case 0xD3: // TIN
1203 in_inc = 1;
1204 out_inc = 0;
1205 goto bxfer_no_alt;
1206
1207 case 0xC3: // TDD
1208 in_inc = -1;
1209 out_inc = -1;
1210 goto bxfer_no_alt;
1211
1212 case 0x73: // TII
1213 in_inc = 1;
1214 out_inc = 1;
1215 bxfer_no_alt:
1216 in_alt = 0;
1217 out_alt = 0;
1218 bxfer: {
1219 fuint16 in = GET_LE16( instr + 0 );
1220 fuint16 out = GET_LE16( instr + 2 );
1221 int count = GET_LE16( instr + 4 );
1222 if ( !count )
1223 count = 0x10000;
1224 pc += 6;
1225 WRITE_LOW( 0x100 | (sp - 1), y );
1226 WRITE_LOW( 0x100 | (sp - 2), a );
1227 WRITE_LOW( 0x100 | (sp - 3), x );
1228 FLUSH_TIME();
1229 do
1230 {
1231 // TODO: reads from $0800-$1400 in I/O page return 0 and don't access I/O
1232 fuint8 t = READ( in );
1233 in += in_inc;
1234 in &= 0xFFFF;
1235 s.time += 6;
1236 if ( in_alt )
1237 in_inc = -in_inc;
1238 WRITE( out, t );
1239 out += out_inc;
1240 out &= 0xFFFF;
1241 if ( out_alt )
1242 out_inc = -out_inc;
1243 }
1244 while ( --count );
1245 CACHE_TIME();
1246 goto loop;
1247 }
1248 }
1249
1250// Illegal
1251
1252 default:
1253 assert( (unsigned) opcode <= 0xFF );
1254 dprintf( "Illegal opcode $%02X at $%04X\n", (int) opcode, (int) pc - 1 );
1255 illegal_encountered = true;
1256 goto loop;
1257 }
1258 assert( false );
1259
1260 int result_;
1261handle_brk:
1262 pc++;
1263 result_ = 6;
1264
1265interrupt:
1266 {
1267 s_time += 7;
1268
1269 WRITE_LOW( 0x100 | (sp - 1), pc >> 8 );
1270 WRITE_LOW( 0x100 | (sp - 2), pc );
1271 pc = GET_LE16( &READ_PROG( 0xFFF0 ) + result_ );
1272
1273 sp = (sp - 3) | 0x100;
1274 fuint8 temp;
1275 CALC_STATUS( temp );
1276 if ( result_ == 6 )
1277 temp |= st_b;
1278 WRITE_LOW( sp, temp );
1279
1280 status &= ~st_d;
1281 status |= st_i;
1282 r->status = status; // update externally-visible I flag
1283
1284 blargg_long delta = s.base - cpu->end_time;
1285 s.base = cpu->end_time;
1286 s_time += delta;
1287 goto loop;
1288 }
1289
1290idle_done:
1291 s_time = 0;
1292out_of_time:
1293 pc--;
1294 FLUSH_TIME();
1295 CPU_DONE( this, TIME, result_ );
1296 CACHE_TIME();
1297 if ( result_ > 0 )
1298 goto interrupt;
1299 if ( s_time < 0 )
1300 goto loop;
1301
1302 s.time = s_time;
1303
1304 r->pc = pc;
1305 r->sp = GET_SP();
1306 r->a = a;
1307 r->x = x;
1308 r->y = y;
1309
1310 {
1311 fuint8 temp;
1312 CALC_STATUS( temp );
1313 r->status = temp;
1314 }
1315
1316 cpu->state_ = s;
1317 cpu->state = &cpu->state_;
1318
1319 return illegal_encountered;
1320}
1321
diff --git a/apps/codecs/libgme/hes_cpu.h b/apps/codecs/libgme/hes_cpu.h
new file mode 100644
index 0000000000..f3bcf7d4cf
--- /dev/null
+++ b/apps/codecs/libgme/hes_cpu.h
@@ -0,0 +1,95 @@
1// PC Engine CPU emulator for use with HES music files
2
3// Game_Music_Emu 0.5.2
4#ifndef HES_CPU_H
5#define HES_CPU_H
6
7#include "blargg_common.h"
8
9typedef blargg_long hes_time_t; // clock cycle count
10typedef unsigned hes_addr_t; // 16-bit address
11
12struct Hes_Emu;
13
14enum { future_hes_time = LONG_MAX / 2 + 1 };
15enum { page_size = 0x2000 };
16enum { page_shift = 13 };
17enum { page_count = 8 };
18
19// Attempt to execute instruction here results in CPU advancing time to
20// lesser of irq_time() and end_time() (or end_time() if IRQs are
21// disabled)
22enum { idle_addr = 0x1FFF };
23
24// Can read this many bytes past end of a page
25enum { cpu_padding = 8 };
26enum { irq_inhibit = 0x04 };
27
28
29// Cpu state
30struct state_t {
31 uint8_t const* code_map [page_count + 1];
32 hes_time_t base;
33 blargg_long time;
34};
35
36// Cpu registers
37struct registers_t {
38 uint16_t pc;
39 uint8_t a;
40 uint8_t x;
41 uint8_t y;
42 uint8_t status;
43 uint8_t sp;
44};
45
46struct Hes_Cpu {
47 struct registers_t r;
48
49 hes_time_t irq_time;
50 hes_time_t end_time;
51
52 struct state_t* state; // points to state_ or a local copy within run()
53 struct state_t state_;
54
55 // page mapping registers
56 uint8_t mmr [page_count + 1];
57 uint8_t ram [page_size];
58};
59
60// Init cpu state
61void Cpu_init( struct Hes_Cpu* this );
62
63// Reset hes cpu
64void Cpu_reset( struct Hes_Cpu* this );
65
66// Set end_time and run CPU from current time. Returns true if any illegal
67// instructions were encountered.
68bool Cpu_run( struct Hes_Emu* this, hes_time_t end_time ) ICODE_ATTR;
69
70void Cpu_set_mmr( struct Hes_Emu* this, int reg, int bank ) ICODE_ATTR;
71
72// Time of ning of next instruction to be executed
73static inline hes_time_t Cpu_time( struct Hes_Cpu* this )
74{
75 return this->state->time + this->state->base;
76}
77
78static inline uint8_t const* Cpu_get_code( struct Hes_Cpu* this, hes_addr_t addr )
79{
80 return this->state->code_map [addr >> page_shift] + addr
81 #if !defined (BLARGG_NONPORTABLE)
82 % (unsigned) page_size
83 #endif
84 ;
85}
86
87static inline int Cpu_update_end_time( struct Hes_Cpu* this, uint8_t reg_status, hes_time_t t, hes_time_t irq )
88{
89 if ( irq < t && !(reg_status & irq_inhibit) ) t = irq;
90 int delta = this->state->base - t;
91 this->state->base = t;
92 return delta;
93}
94
95#endif
diff --git a/apps/codecs/libgme/hes_cpu_io.h b/apps/codecs/libgme/hes_cpu_io.h
new file mode 100644
index 0000000000..6b49c69e22
--- /dev/null
+++ b/apps/codecs/libgme/hes_cpu_io.h
@@ -0,0 +1,72 @@
1
2#include "hes_emu.h"
3
4#include "blargg_source.h"
5
6int Cpu_read( struct Hes_Emu* this, hes_addr_t addr )
7{
8 check( addr <= 0xFFFF );
9 int result = *Cpu_get_code( &this->cpu, addr );
10 if ( this->cpu.mmr [addr >> page_shift] == 0xFF )
11 result = Emu_cpu_read( this, addr );
12 return result;
13}
14
15void Cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data )
16{
17 check( addr <= 0xFFFF );
18 byte* out = this->write_pages [addr >> page_shift];
19 addr &= page_size - 1;
20 if ( out )
21 out [addr] = data;
22 else if ( this->cpu.mmr [addr >> page_shift] == 0xFF )
23 Emu_cpu_write( this, addr, data );
24}
25
26#define CPU_READ_FAST( emu, addr, time, out ) \
27 CPU_READ_FAST_( emu, addr, time, out )
28
29#define CPU_READ_FAST_( emu, addr, time, out ) \
30{\
31 out = READ_PROG( addr );\
32 if ( emu->cpu.mmr [addr >> page_shift] == 0xFF )\
33 {\
34 FLUSH_TIME();\
35 out = Emu_cpu_read( emu, addr );\
36 CACHE_TIME();\
37 }\
38}
39
40#define CPU_WRITE_FAST( emu, addr, data, time ) \
41 CPU_WRITE_FAST_( emu, addr, data, time )
42
43#define CPU_WRITE_FAST_( emu, addr, data, time ) \
44{\
45 byte* out = emu->write_pages [addr >> page_shift];\
46 addr &= page_size - 1;\
47 if ( out )\
48 {\
49 out [addr] = data;\
50 }\
51 else if ( emu->cpu.mmr [addr >> page_shift] == 0xFF )\
52 {\
53 FLUSH_TIME();\
54 Emu_cpu_write( emu, addr, data );\
55 CACHE_TIME();\
56 }\
57}
58
59#define CPU_READ( emu, addr, time ) \
60 Cpu_read( emu, addr )
61
62#define CPU_WRITE( emu, addr, data, time ) \
63 Cpu_write( emu, addr, data )
64
65#define CPU_WRITE_VDP( emu, addr, data, time ) \
66 Cpu_write_vdp( emu, addr, data )
67
68#define CPU_SET_MMR( emu, page, bank ) \
69 Emu_cpu_set_mmr( emu, page, bank )
70
71#define CPU_DONE( emu, time, result_out ) \
72 result_out = Cpu_done( emu )
diff --git a/apps/codecs/libgme/hes_emu.c b/apps/codecs/libgme/hes_emu.c
new file mode 100644
index 0000000000..a44eded8d7
--- /dev/null
+++ b/apps/codecs/libgme/hes_emu.c
@@ -0,0 +1,877 @@
1// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/
2
3#include "hes_emu.h"
4
5#include "blargg_endian.h"
6#include "blargg_source.h"
7
8/* Copyright (C) 2006 Shay Green. This module is free software; you
9can redistribute it and/or modify it under the terms of the GNU Lesser
10General Public License as published by the Free Software Foundation; either
11version 2.1 of the License, or (at your option) any later version. This
12module is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15details. You should have received a copy of the GNU Lesser General Public
16License along with this module; if not, write to the Free Software Foundation,
17Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19int const timer_mask = 0x04;
20int const vdp_mask = 0x02;
21int const i_flag_mask = 0x04;
22int const unmapped = 0xFF;
23
24long const period_60hz = 262 * 455L; // scanlines * clocks per scanline
25
26int const stereo = 2; // number of channels for stereo
27int const silence_max = 6; // seconds
28int const silence_threshold = 0x10;
29long const fade_block_size = 512;
30int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
31
32const char gme_wrong_file_type [] ICONST_ATTR = "Wrong file type for this emulator";
33
34void clear_track_vars( struct Hes_Emu* this )
35{
36 this->current_track_ = -1;
37 this->out_time = 0;
38 this->emu_time = 0;
39 this->emu_track_ended_ = true;
40 this->track_ended = true;
41 this->fade_start = LONG_MAX / 2 + 1;
42 this->fade_step = 1;
43 this->silence_time = 0;
44 this->silence_count = 0;
45 this->buf_remain = 0;
46}
47
48void Hes_init( struct Hes_Emu* this )
49{
50 this->sample_rate_ = 0;
51 this->mute_mask_ = 0;
52 this->tempo_ = 1.0;
53
54 // defaults
55 this->max_initial_silence = 2;
56 this->ignore_silence = false;
57
58 // Unload
59 this->voice_count_ = 0;
60 clear_track_vars( this );
61
62 this->timer.raw_load = 0;
63 this->silence_lookahead = 6;
64 Sound_set_gain( this, 1.11 );
65
66 Rom_init( &this->rom, 0x2000 );
67
68 Apu_init( &this->apu );
69 Adpcm_init( &this->adpcm );
70 Cpu_init( &this->cpu );
71
72 /* Set default track count */
73 this->track_count = 255;
74}
75
76static blargg_err_t check_hes_header( void const* header )
77{
78 if ( memcmp( header, "HESM", 4 ) )
79 return gme_wrong_file_type;
80 return 0;
81}
82
83// Setup
84
85blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size )
86{
87 // Unload
88 this->voice_count_ = 0;
89 clear_track_vars( this );
90
91 assert( offsetof (struct header_t,unused [4]) == header_size );
92 RETURN_ERR( Rom_load( &this->rom, data, size, header_size, &this->header, unmapped ) );
93
94 RETURN_ERR( check_hes_header( this->header.tag ) );
95
96 /* if ( header_.vers != 0 )
97 warning( "Unknown file version" );
98
99 if ( memcmp( header_.data_tag, "DATA", 4 ) )
100 warning( "Data header missing" );
101
102 if ( memcmp( header_.unused, "\0\0\0\0", 4 ) )
103 warning( "Unknown header data" ); */
104
105 // File spec supports multiple blocks, but I haven't found any, and
106 // many files have bad sizes in the only block, so it's simpler to
107 // just try to load the damn data as best as possible.
108
109 long addr = get_le32( this->header.addr );
110 /* long rom_size = get_le32( this->header.size ); */
111 long const rom_max = 0x100000;
112 if ( addr & ~(rom_max - 1) )
113 {
114 /* warning( "Invalid address" ); */
115 addr &= rom_max - 1;
116 }
117 /* if ( (unsigned long) (addr + size) > (unsigned long) rom_max )
118 warning( "Invalid size" );
119
120 if ( rom_size != rom.file_size() )
121 {
122 if ( size <= rom.file_size() - 4 && !memcmp( rom.begin() + size, "DATA", 4 ) )
123 warning( "Multiple DATA not supported" );
124 else if ( size < rom.file_size() )
125 warning( "Extra file data" );
126 else
127 warning( "Missing file data" );
128 } */
129
130 Rom_set_addr( &this->rom, addr );
131
132 this->voice_count_ = osc_count + adpcm_osc_count;
133
134 Apu_volume( &this->apu, this->gain_ );
135 Adpcm_volume( &this->adpcm, this->gain_ );
136
137 // Setup buffer
138 this->clock_rate_ = 7159091;
139 Buffer_clock_rate( &this->stereo_buf, 7159091 );
140 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
141
142 Sound_set_tempo( this, this->tempo_ );
143 Sound_mute_voices( this, this->mute_mask_ );
144
145 // Reset track count
146 this->track_count = 255;
147 this->m3u.size = 0;
148 return 0;
149}
150
151
152// Emulation
153
154void recalc_timer_load( struct Hes_Emu* this ) ICODE_ATTR;
155void recalc_timer_load( struct Hes_Emu* this )
156{
157 this->timer.load = this->timer.raw_load * this->timer_base + 1;
158}
159
160// Hardware
161
162void irq_changed( struct Hes_Emu* this ) ICODE_ATTR;
163void run_until( struct Hes_Emu* this, hes_time_t present ) ICODE_ATTR;
164void Cpu_write_vdp( struct Hes_Emu* this, int addr, int data )
165{
166 switch ( addr )
167 {
168 case 0:
169 this->vdp.latch = data & 0x1F;
170 break;
171
172 case 2:
173 if ( this->vdp.latch == 5 )
174 {
175 /* if ( data & 0x04 )
176 warning( "Scanline interrupt unsupported" ); */
177 run_until( this, Cpu_time( &this->cpu ) );
178 this->vdp.control = data;
179 irq_changed( this );
180 }
181 else
182 {
183 dprintf( "VDP not supported: $%02X <- $%02X\n", this->vdp.latch, data );
184 }
185 break;
186
187 case 3:
188 dprintf( "VDP MSB not supported: $%02X <- $%02X\n", this->vdp.latch, data );
189 break;
190 }
191}
192
193int Cpu_done( struct Hes_Emu* this )
194{
195 check( time() >= end_time() ||
196 (!(r.status & i_flag_mask) && time() >= irq_time()) );
197
198 if ( !(this->cpu.r.status & i_flag_mask) )
199 {
200 hes_time_t present = Cpu_time( &this->cpu );
201
202 if ( this->irq.timer <= present && !(this->irq.disables & timer_mask) )
203 {
204 this->timer.fired = true;
205 this->irq.timer = future_hes_time;
206 irq_changed( this ); // overkill, but not worth writing custom code
207 #if defined (GME_FRAME_HOOK_DEFINED)
208 {
209 unsigned const threshold = period_60hz / 30;
210 unsigned long elapsed = present - last_frame_hook;
211 if ( elapsed - period_60hz + threshold / 2 < threshold )
212 {
213 last_frame_hook = present;
214 GME_FRAME_HOOK( this );
215 }
216 }
217 #endif
218 return 0x0A;
219 }
220
221 if ( this->irq.vdp <= present && !(this->irq.disables & vdp_mask) )
222 {
223 // work around for bugs with music not acknowledging VDP
224 //run_until( present );
225 //irq.vdp = future_hes_time;
226 //irq_changed();
227 #if defined(GME_FRAME_HOOK_DEFINED)
228 last_frame_hook = present;
229 GME_FRAME_HOOK( this );
230 #endif
231 return 0x08;
232 }
233 }
234 return 0;
235}
236
237void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data )
238{
239 hes_time_t time = Cpu_time( &this->cpu );
240 if ( (unsigned) (addr - start_addr) <= end_addr - start_addr )
241 {
242 GME_APU_HOOK( this, addr - apu.start_addr, data );
243 // avoid going way past end when a long block xfer is writing to I/O space
244 hes_time_t t = min( time, this->cpu.end_time + 8 );
245 Apu_write_data( &this->apu, t, addr, data );
246 return;
247 }
248
249 if ( (unsigned) (addr - io_addr) < io_size )
250 {
251 hes_time_t t = min( time, this->cpu.end_time + 6 );
252 Adpcm_write_data( &this->adpcm, t, addr, data );
253 return;
254 }
255
256 switch ( addr )
257 {
258 case 0x0000:
259 case 0x0002:
260 case 0x0003:
261 Cpu_write_vdp( this, addr, data );
262 return;
263
264 case 0x0C00: {
265 run_until( this, time );
266 this->timer.raw_load = (data & 0x7F) + 1;
267 recalc_timer_load( this );
268 this->timer.count = this->timer.load;
269 break;
270 }
271
272 case 0x0C01:
273 data &= 1;
274 if ( this->timer.enabled == data )
275 return;
276 run_until( this, time );
277 this->timer.enabled = data;
278 if ( data )
279 this->timer.count = this->timer.load;
280 break;
281
282 case 0x1402:
283 run_until( this, time );
284 this->irq.disables = data;
285
286 // flag questionable values
287 if ( (data & 0xF8) && (data & 0xF8) != 0xF8 ) {
288 dprintf( "Int mask: $%02X\n", data );
289 }
290 break;
291
292 case 0x1403:
293 run_until( this, time );
294 if ( this->timer.enabled )
295 this->timer.count = this->timer.load;
296 this->timer.fired = false;
297 break;
298
299#ifndef NDEBUG
300 case 0x1000: // I/O port
301 case 0x0402: // palette
302 case 0x0403:
303 case 0x0404:
304 case 0x0405:
305 return;
306
307 default:
308 dprintf( "unmapped write $%04X <- $%02X\n", addr, data );
309 return;
310#endif
311 }
312
313 irq_changed( this );
314}
315
316int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t addr )
317{
318 hes_time_t time = Cpu_time( &this->cpu );
319 addr &= page_size - 1;
320 switch ( addr )
321 {
322 case 0x0000:
323 if ( this->irq.vdp > time )
324 return 0;
325 this->irq.vdp = future_hes_time;
326 run_until( this, time );
327 irq_changed( this );
328 return 0x20;
329
330 case 0x0002:
331 case 0x0003:
332 dprintf( "VDP read not supported: %d\n", addr );
333 return 0;
334
335 case 0x0C01:
336 //return timer.enabled; // TODO: remove?
337 case 0x0C00:
338 run_until( this, time );
339 dprintf( "Timer count read\n" );
340 return (unsigned) (this->timer.count - 1) / this->timer_base;
341
342 case 0x1402:
343 return this->irq.disables;
344
345 case 0x1403:
346 {
347 int status = 0;
348 if ( this->irq.timer <= time ) status |= timer_mask;
349 if ( this->irq.vdp <= time ) status |= vdp_mask;
350 return status;
351 }
352
353 case 0x180A:
354 case 0x180B:
355 case 0x180C:
356 case 0x180D:
357 return Adpcm_read_data( &this->adpcm, time, addr );
358
359 #ifndef NDEBUG
360 case 0x1000: // I/O port
361 // case 0x180C: // CD-ROM
362 // case 0x180D:
363 break;
364
365 default:
366 dprintf( "unmapped read $%04X\n", addr );
367 #endif
368 }
369
370 return unmapped;
371}
372
373// see hes_cpu_io.h for core read/write functions
374
375// Emulation
376
377void run_until( struct Hes_Emu* this, hes_time_t present )
378{
379 while ( this->vdp.next_vbl < present )
380 this->vdp.next_vbl += this->play_period;
381
382 hes_time_t elapsed = present - this->timer.last_time;
383 if ( elapsed > 0 )
384 {
385 if ( this->timer.enabled )
386 {
387 this->timer.count -= elapsed;
388 if ( this->timer.count <= 0 )
389 this->timer.count += this->timer.load;
390 }
391 this->timer.last_time = present;
392 }
393}
394
395void irq_changed( struct Hes_Emu* this )
396{
397 hes_time_t present = Cpu_time( &this->cpu );
398
399 if ( this->irq.timer > present )
400 {
401 this->irq.timer = future_hes_time;
402 if ( this->timer.enabled && !this->timer.fired )
403 this->irq.timer = present + this->timer.count;
404 }
405
406 if ( this->irq.vdp > present )
407 {
408 this->irq.vdp = future_hes_time;
409 if ( this->vdp.control & 0x08 )
410 this->irq.vdp = this->vdp.next_vbl;
411 }
412
413 hes_time_t time = future_hes_time;
414 if ( !(this->irq.disables & timer_mask) ) time = this->irq.timer;
415 if ( !(this->irq.disables & vdp_mask) ) time = min( time, this->irq.vdp );
416
417 // Set cpu irq time
418 this->cpu.state->time += Cpu_update_end_time( &this->cpu, this->cpu.r.status,
419 this->cpu.end_time, (this->cpu.irq_time = time) );
420}
421
422static void adjust_time( blargg_long* time, hes_time_t delta ) ICODE_ATTR;
423static void adjust_time( blargg_long* time, hes_time_t delta )
424{
425 if ( *time < future_hes_time )
426 {
427 *time -= delta;
428 if ( *time < 0 )
429 *time = 0;
430 }
431}
432
433blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ) ICODE_ATTR;
434blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ )
435{
436 blip_time_t duration = *duration_; // cache
437
438 Cpu_run( this, duration );
439 /* warning( "Emulation error (illegal instruction)" ); */
440
441 check( time() >= duration );
442 //check( time() - duration < 20 ); // Txx instruction could cause going way over
443
444 run_until( this, duration );
445
446 // end time frame
447 this->timer.last_time -= duration;
448 this->vdp.next_vbl -= duration;
449 #if defined (GME_FRAME_HOOK_DEFINED)
450 last_frame_hook -= *duration;
451 #endif
452
453 // End cpu frame
454 this->cpu.state_.base -= duration;
455 if ( this->cpu.irq_time < future_hes_time ) this->cpu.irq_time -= duration;
456 if ( this->cpu.end_time < future_hes_time ) this->cpu.end_time -= duration;
457
458 adjust_time( &this->irq.timer, duration );
459 adjust_time( &this->irq.vdp, duration );
460 Apu_end_frame( &this->apu, duration );
461 Adpcm_end_frame( &this->adpcm, duration );
462
463 return 0;
464}
465
466blargg_err_t play_( struct Hes_Emu* this, long count, sample_t* out ) ICODE_ATTR;
467blargg_err_t play_( struct Hes_Emu* this, long count, sample_t* out )
468{
469 long remain = count;
470 while ( remain )
471 {
472 remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain );
473 if ( remain )
474 {
475 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) )
476 {
477 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
478 // Remute voices
479 Sound_mute_voices( this, this->mute_mask_ );
480 }
481
482 int msec = Buffer_length( &this->stereo_buf );
483 blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate_ / 1000;
484 RETURN_ERR( run_clocks( this, &clocks_emulated ) );
485 assert( clocks_emulated );
486 Buffer_end_frame( &this->stereo_buf, clocks_emulated );
487 }
488 }
489 return 0;
490}
491
492
493// Music emu
494
495blargg_err_t Hes_set_sample_rate( struct Hes_Emu* this, long rate )
496{
497 require( !this->sample_rate_ ); // sample rate can't be changed once set
498 Buffer_init( &this->stereo_buf );
499 RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) );
500
501 // Set bass frequency
502 Buffer_bass_freq( &this->stereo_buf, 60 );
503
504 this->sample_rate_ = rate;
505 return 0;
506}
507
508void Sound_mute_voice( struct Hes_Emu* this, int index, bool mute )
509{
510 require( (unsigned) index < (unsigned) this->voice_count_ );
511 int bit = 1 << index;
512 int mask = this->mute_mask_ | bit;
513 if ( !mute )
514 mask ^= bit;
515 Sound_mute_voices( this, mask );
516}
517
518void Sound_mute_voices( struct Hes_Emu* this, int mask )
519{
520 require( this->sample_rate_ ); // sample rate must be set first
521 this->mute_mask_ = mask;
522
523 // Set adpcm voice
524 struct channel_t ch = Buffer_channel( &this->stereo_buf );
525 if ( mask & (1 << this->voice_count_ ) )
526 Adpcm_set_output( &this->adpcm, 0, 0, 0, 0 );
527 else
528 Adpcm_set_output( &this->adpcm, 0, ch.center, ch.left, ch.right );
529
530 // Set apu voices
531 int i = this->voice_count_ - 1;
532 for ( ; i--; )
533 {
534 if ( mask & (1 << i) )
535 {
536 Apu_osc_output( &this->apu, i, 0, 0, 0 );
537 }
538 else
539 {
540 assert( (ch.center && ch.left && ch.right) ||
541 (!ch.center && !ch.left && !ch.right) ); // all or nothing
542 Apu_osc_output( &this->apu, i, ch.center, ch.left, ch.right );
543 }
544 }
545}
546
547void Sound_set_tempo( struct Hes_Emu* this, double t )
548{
549 require( this->sample_rate_ ); // sample rate must be set first
550 double const min = 0.02;
551 double const max = 4.00;
552 if ( t < min ) t = min;
553 if ( t > max ) t = max;
554 this->play_period = (hes_time_t) (period_60hz / t);
555 this->timer_base = (int) (1024 / t);
556 recalc_timer_load( this );
557 this->tempo_ = t;
558}
559
560void fill_buf( struct Hes_Emu* this ) ICODE_ATTR;
561blargg_err_t Hes_start_track( struct Hes_Emu* this, int track )
562{
563 clear_track_vars( this );
564
565 // Remap track if playlist available
566 if ( this->m3u.size > 0 ) {
567 struct entry_t* e = &this->m3u.entries[track];
568 track = e->track;
569 }
570
571 this->current_track_ = track;
572
573 Buffer_clear( &this->stereo_buf );
574
575 memset( this->cpu.ram, 0, sizeof this->cpu.ram ); // some HES music relies on zero fill
576 memset( this->sgx, 0, sizeof this->sgx );
577
578 Apu_reset( &this->apu );
579 Adpcm_reset( &this->adpcm );
580 Cpu_reset( &this->cpu );
581
582 unsigned i;
583 for ( i = 0; i < sizeof this->header.banks; i++ )
584 Cpu_set_mmr( this, i, this->header.banks [i] );
585 Cpu_set_mmr( this, page_count, 0xFF ); // unmapped beyond end of address space
586
587 this->irq.disables = timer_mask | vdp_mask;
588 this->irq.timer = future_hes_time;
589 this->irq.vdp = future_hes_time;
590
591 this->timer.enabled = false;
592 this->timer.raw_load= 0x80;
593 this->timer.count = this->timer.load;
594 this->timer.fired = false;
595 this->timer.last_time = 0;
596
597 this->vdp.latch = 0;
598 this->vdp.control = 0;
599 this->vdp.next_vbl = 0;
600
601 this->cpu.ram [0x1FF] = (idle_addr - 1) >> 8;
602 this->cpu.ram [0x1FE] = (idle_addr - 1) & 0xFF;
603 this->cpu.r.sp = 0xFD;
604 this->cpu.r.pc = get_le16( this->header.init_addr );
605 this->cpu.r.a = track;
606
607 recalc_timer_load( this );
608 this->last_frame_hook = 0;
609
610 this->emu_track_ended_ = false;
611 this->track_ended = false;
612
613 if ( !this->ignore_silence )
614 {
615 // play until non-silence or end of track
616 long end;
617 for ( end =this-> max_initial_silence * stereo * this->sample_rate_; this->emu_time < end; )
618 {
619 fill_buf( this );
620 if ( this->buf_remain | (int) this->emu_track_ended_ )
621 break;
622 }
623
624 this->emu_time = this->buf_remain;
625 this->out_time = 0;
626 this->silence_time = 0;
627 this->silence_count = 0;
628 }
629 /* return track_ended() ? warning() : 0; */
630 return 0;
631}
632
633// Tell/Seek
634
635blargg_long msec_to_samples( blargg_long msec, long sample_rate )
636{
637 blargg_long sec = msec / 1000;
638 msec -= sec * 1000;
639 return (sec * sample_rate + msec * sample_rate / 1000) * stereo;
640}
641
642long Track_tell( struct Hes_Emu* this )
643{
644 blargg_long rate = this->sample_rate_ * stereo;
645 blargg_long sec = this->out_time / rate;
646 return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate;
647}
648
649blargg_err_t Track_seek( struct Hes_Emu* this, long msec )
650{
651 blargg_long time = msec_to_samples( msec, this->sample_rate_ );
652 if ( time < this->out_time )
653 RETURN_ERR( Hes_start_track( this, this->current_track_ ) );
654 return Track_skip( this, time - this->out_time );
655}
656
657blargg_err_t skip_( struct Hes_Emu* this, long count ) ICODE_ATTR;
658blargg_err_t skip_( struct Hes_Emu* this, long count )
659{
660 // for long skip, mute sound
661 const long threshold = 30000;
662 if ( count > threshold )
663 {
664 int saved_mute = this->mute_mask_;
665 Sound_mute_voices( this, ~0 );
666
667 while ( count > threshold / 2 && !this->emu_track_ended_ )
668 {
669 RETURN_ERR( play_( this, buf_size, this->buf ) );
670 count -= buf_size;
671 }
672
673 Sound_mute_voices( this, saved_mute );
674 }
675
676 while ( count && !this->emu_track_ended_ )
677 {
678 long n = buf_size;
679 if ( n > count )
680 n = count;
681 count -= n;
682 RETURN_ERR( play_( this, n, this->buf ) );
683 }
684 return 0;
685}
686
687blargg_err_t Track_skip( struct Hes_Emu* this, long count )
688{
689 require( this->current_track_ >= 0 ); // start_track() must have been called already
690 this->out_time += count;
691
692 // remove from silence and buf first
693 {
694 long n = min( count, this->silence_count );
695 this->silence_count -= n;
696 count -= n;
697
698 n = min( count, this->buf_remain );
699 this->buf_remain -= n;
700 count -= n;
701 }
702
703 if ( count && !this->emu_track_ended_ )
704 {
705 this->emu_time += count;
706
707 // End track if error
708 if ( skip_( this, count ) )
709 this->emu_track_ended_ = true;
710 }
711
712 if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended
713 this->track_ended |= this->emu_track_ended_;
714
715 return 0;
716}
717
718
719
720// Fading
721
722void Track_set_fade( struct Hes_Emu* this, long start_msec, long length_msec )
723{
724 this->fade_step = this->sample_rate_ * length_msec / (fade_block_size * fade_shift * 1000 / stereo);
725 this->fade_start = msec_to_samples( start_msec, this->sample_rate_ );
726}
727
728// unit / pow( 2.0, (double) x / step )
729static int int_log( blargg_long x, int step, int unit ) ICODE_ATTR;
730static int int_log( blargg_long x, int step, int unit )
731{
732 int shift = x / step;
733 int fraction = (x - shift * step) * unit / step;
734 return ((unit - fraction) + (fraction >> 1)) >> shift;
735}
736
737void handle_fade( struct Hes_Emu* this, long out_count, sample_t* out ) ICODE_ATTR;
738void handle_fade( struct Hes_Emu* this, long out_count, sample_t* out )
739{
740 int i;
741 for ( i = 0; i < out_count; i += fade_block_size )
742 {
743 int const shift = 14;
744 int const unit = 1 << shift;
745 int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size,
746 this->fade_step, unit );
747 if ( gain < (unit >> fade_shift) )
748 this->track_ended = this->emu_track_ended_ = true;
749
750 sample_t* io = &out [i];
751 int count;
752 for ( count = min( fade_block_size, out_count - i ); count; --count )
753 {
754 *io = (sample_t) ((*io * gain) >> shift);
755 ++io;
756 }
757 }
758}
759
760// Silence detection
761
762void emu_play( struct Hes_Emu* this, long count, sample_t* out ) ICODE_ATTR;
763void emu_play( struct Hes_Emu* this, long count, sample_t* out )
764{
765 check( current_track_ >= 0 );
766 this->emu_time += count;
767 if ( this->current_track_ >= 0 && !this->emu_track_ended_ ) {
768
769 // End track if error
770 if ( play_( this, count, out ) )
771 this->emu_track_ended_ = true;
772 }
773 else
774 memset( out, 0, count * sizeof *out );
775}
776
777// number of consecutive silent samples at end
778static long count_silence( sample_t* begin, long size ) ICODE_ATTR;
779static long count_silence( sample_t* begin, long size )
780{
781 sample_t first = *begin;
782 *begin = silence_threshold; // sentinel
783 sample_t* p = begin + size;
784 while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { }
785 *begin = first;
786 return size - (p - begin);
787}
788
789// fill internal buffer and check it for silence
790void fill_buf( struct Hes_Emu* this )
791{
792 assert( !this->buf_remain );
793 if ( !this->emu_track_ended_ )
794 {
795 emu_play( this, buf_size, this->buf );
796 long silence = count_silence( this->buf, buf_size );
797 if ( silence < buf_size )
798 {
799 this->silence_time = this->emu_time - silence;
800 this->buf_remain = buf_size;
801 return;
802 }
803 }
804 this->silence_count += buf_size;
805}
806
807blargg_err_t Hes_play( struct Hes_Emu* this, long out_count, sample_t* out )
808{
809 if ( this->track_ended )
810 {
811 memset( out, 0, out_count * sizeof *out );
812 }
813 else
814 {
815 require( this->current_track_ >= 0 );
816 require( out_count % stereo == 0 );
817
818 assert( this->emu_time >= this->out_time );
819
820 // prints nifty graph of how far ahead we are when searching for silence
821 //dprintf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" );
822
823 long pos = 0;
824 if ( this->silence_count )
825 {
826 // during a run of silence, run emulator at >=2x speed so it gets ahead
827 long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time;
828 while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) )
829 fill_buf( this );
830
831 // fill with silence
832 pos = min( this->silence_count, out_count );
833 memset( out, 0, pos * sizeof *out );
834 this->silence_count -= pos;
835
836 if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate_ )
837 {
838 this->track_ended = this->emu_track_ended_ = true;
839 this->silence_count = 0;
840 this->buf_remain = 0;
841 }
842 }
843
844 if ( this->buf_remain )
845 {
846 // empty silence buf
847 long n = min( this->buf_remain, out_count - pos );
848 memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out );
849 this->buf_remain -= n;
850 pos += n;
851 }
852
853 // generate remaining samples normally
854 long remain = out_count - pos;
855 if ( remain )
856 {
857 emu_play( this, remain, out + pos );
858 this->track_ended |= this->emu_track_ended_;
859
860 if ( !this->ignore_silence || this->out_time > this->fade_start )
861 {
862 // check end for a new run of silence
863 long silence = count_silence( out + pos, remain );
864 if ( silence < remain )
865 this->silence_time = this->emu_time - silence;
866
867 if ( this->emu_time - this->silence_time >= buf_size )
868 fill_buf( this ); // cause silence detection on next play()
869 }
870 }
871
872 if ( this->out_time > this->fade_start )
873 handle_fade( this, out_count, out );
874 }
875 this->out_time += out_count;
876 return 0;
877}
diff --git a/apps/codecs/libgme/hes_emu.h b/apps/codecs/libgme/hes_emu.h
new file mode 100644
index 0000000000..18dbe0d506
--- /dev/null
+++ b/apps/codecs/libgme/hes_emu.h
@@ -0,0 +1,229 @@
1// TurboGrafx-16/PC Engine HES music file emulator
2
3// Game_Music_Emu 0.5.2
4#ifndef HES_EMU_H
5#define HES_EMU_H
6
7#include "blargg_source.h"
8
9#include "multi_buffer.h"
10#include "rom_data.h"
11#include "hes_apu.h"
12#include "hes_apu_adpcm.h"
13#include "hes_cpu.h"
14#include "m3u_playlist.h"
15
16typedef short sample_t;
17
18enum { buf_size = 2048 };
19
20// HES file header
21enum { header_size = 0x20 };
22struct header_t
23{
24 byte tag [4];
25 byte vers;
26 byte first_track;
27 byte init_addr [2];
28 byte banks [8];
29 byte data_tag [4];
30 byte size [4];
31 byte addr [4];
32 byte unused [4];
33};
34
35
36struct timer_t {
37 hes_time_t last_time;
38 blargg_long count;
39 blargg_long load;
40 int raw_load;
41 byte enabled;
42 byte fired;
43};
44
45struct vdp_t {
46 hes_time_t next_vbl;
47 byte latch;
48 byte control;
49};
50
51struct irq_t {
52 hes_time_t timer;
53 hes_time_t vdp;
54 byte disables;
55};
56
57
58struct Hes_Emu {
59 hes_time_t play_period;
60 hes_time_t last_frame_hook;
61 int timer_base;
62
63 struct timer_t timer;
64 struct vdp_t vdp;
65 struct irq_t irq;
66
67 // Sound
68 long clock_rate_;
69 long sample_rate_;
70 unsigned buf_changed_count;
71 int voice_count_;
72 double tempo_;
73 double gain_;
74
75 // track-specific
76 byte track_count;
77 volatile bool track_ended;
78 int current_track_;
79 blargg_long out_time; // number of samples played since start of track
80 blargg_long emu_time; // number of samples emulator has generated since start of track
81 bool emu_track_ended_; // emulator has reached end of track
82
83 // fading
84 blargg_long fade_start;
85 int fade_step;
86
87 // silence detection
88 // Disable automatic end-of-track detection and skipping of silence at beginning
89 bool ignore_silence;
90
91 int max_initial_silence;
92 int mute_mask_;
93 int silence_lookahead; // speed to run emulator when looking ahead for silence
94 long silence_time; // number of samples where most recent silence began
95 long silence_count; // number of samples of silence to play before using buf
96 long buf_remain; // number of samples left in silence buffer
97
98 // Larger files at the end
99 // Header for currently loaded file
100 struct header_t header;
101
102 // M3u Playlist
103 struct M3u_Playlist m3u;
104
105 // Hes Cpu
106 byte* write_pages [page_count + 1]; // 0 if unmapped or I/O space
107 struct Hes_Cpu cpu;
108
109 struct Hes_Apu apu;
110 struct Hes_Apu_Adpcm adpcm;
111
112 struct Stereo_Buffer stereo_buf;
113 sample_t buf [buf_size];
114
115 // rom & ram
116 struct Rom_Data rom;
117 byte sgx [3 * page_size + cpu_padding];
118};
119
120
121// Basic functionality
122// Initializes Hes_Emu structure
123void Hes_init( struct Hes_Emu* this );
124
125// Stops (clear) Hes_Emu structure
126void Hes_stop( struct Hes_Emu* this );
127
128// Loads a file from memory
129blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size );
130
131// Set output sample rate. Must be called only once before loading file.
132blargg_err_t Hes_set_sample_rate( struct Hes_Emu* this, long sample_rate );
133
134// Start a track, where 0 is the first track. Also clears warning string.
135blargg_err_t Hes_start_track( struct Hes_Emu* this, int );
136
137// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation
138// errors set warning string, and major errors also end track.
139blargg_err_t Hes_play( struct Hes_Emu* this, long count, sample_t* buf ) ICODE_ATTR;
140
141// Track status/control
142// Number of milliseconds (1000 msec = 1 second) played since ning of track
143long Track_tell( struct Hes_Emu* this );
144
145// Seek to new time in track. Seeking backwards or far forward can take a while.
146blargg_err_t Track_seek( struct Hes_Emu* this, long msec );
147
148// Skip n samples
149blargg_err_t Track_skip( struct Hes_Emu* this, long n );
150
151// Set start time and length of track fade out. Once fade ends track_ended() returns
152// true. Fade time can be changed while track is playing.
153void Track_set_fade( struct Hes_Emu* this, long start_msec, long length_msec );
154
155// Get track length in milliseconds
156static inline long Track_get_length( struct Hes_Emu* this, int n )
157{
158 long length = 120 * 1000; /* 2 minutes */
159 if ( (this->m3u.size > 0) && (n < this->m3u.size) ) {
160 struct entry_t* entry = &this->m3u.entries [n];
161 length = entry->length;
162 }
163
164 return length;
165}
166
167
168// Sound customization
169// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed.
170// Track length as returned by track_info() assumes a tempo of 1.0.
171void Sound_set_tempo( struct Hes_Emu* this, double );
172
173// Mute/unmute voice i, where voice 0 is first voice
174void Sound_mute_voice( struct Hes_Emu* this, int index, bool mute );
175
176// Set muting state of all voices at once using a bit mask, where -1 mutes them all,
177// 0 unmutes them all, 0x01 mutes just the first voice, etc.
178void Sound_mute_voices( struct Hes_Emu* this, int mask );
179
180// Change overall output amplitude, where 1.0 results in minimal clamping.
181// Must be called before set_sample_rate().
182static inline void Sound_set_gain( struct Hes_Emu* this, double g )
183{
184 assert( !this->sample_rate_ ); // you must set gain before setting sample rate
185 this->gain_ = g;
186}
187
188
189// Emulation (You shouldn't touch these)
190
191int Cpu_read( struct Hes_Emu* this, hes_addr_t ) ICODE_ATTR;
192void Cpu_write( struct Hes_Emu* this, hes_addr_t, int ) ICODE_ATTR;
193void Cpu_write_vdp( struct Hes_Emu* this, int addr, int data ) ICODE_ATTR;
194int Cpu_done( struct Hes_Emu* this ) ICODE_ATTR;
195
196int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t ) ICODE_ATTR;
197void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t, int data ) ICODE_ATTR;
198
199static inline byte const* Emu_cpu_set_mmr( struct Hes_Emu* this, int page, int bank )
200{
201 this->write_pages [page] = 0;
202 if ( bank < 0x80 )
203 return Rom_at_addr( &this->rom, bank * (blargg_long) page_size );
204
205 byte* data = 0;
206 switch ( bank )
207 {
208 case 0xF8:
209 data = this->cpu.ram;
210 break;
211
212 case 0xF9:
213 case 0xFA:
214 case 0xFB:
215 data = &this->sgx [(bank - 0xF9) * page_size];
216 break;
217
218 default:
219 if ( bank != 0xFF ) {
220 dprintf( "Unmapped bank $%02X\n", bank );
221 }
222 return this->rom.unmapped;
223 }
224
225 this->write_pages [page] = data;
226 return data;
227}
228
229#endif
diff --git a/apps/codecs/libgme/inflate/bbfuncs.c b/apps/codecs/libgme/inflate/bbfuncs.c
new file mode 100644
index 0000000000..3b23c3b6db
--- /dev/null
+++ b/apps/codecs/libgme/inflate/bbfuncs.c
@@ -0,0 +1,147 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "bbfuncs.h"
21
22#if defined(ROCKBOX)
23#include "codeclib.h"
24#endif
25
26void error_die(const char* msg)
27{
28 (void)msg;
29}
30
31void error_msg(const char* msg)
32{
33 (void)msg;
34}
35
36size_t safe_read(struct mbreader_t *md, void *buf, size_t count)
37{
38 ssize_t n;
39
40 do {
41 n = mbread(md, buf, count);
42 } while (n < 0&&n!=-1);
43
44 return n;
45}
46
47/*
48 * Read all of the supplied buffer from a file This does multiple reads as
49 *necessary. Returns the amount read, or -1 on an error. A short read is
50 *returned on an end of file.
51 */
52ssize_t full_read(struct mbreader_t *md, void *buf, size_t len)
53{
54 ssize_t cc;
55 ssize_t total;
56
57 total = 0;
58
59 while (len)
60 {
61 cc = safe_read(md, buf, len);
62
63 if (cc < 0)
64 return cc; /* read() returns -1 on failure. */
65
66 if (cc == 0)
67 break;
68
69 buf = ((char *)buf) + cc;
70 total += cc;
71 len -= cc;
72 }
73
74 return total;
75}
76
77/* Die with an error message if we can't read the entire buffer. */
78void xread(struct mbreader_t *md, void *buf, ssize_t count)
79{
80 if (count)
81 {
82 ssize_t size = full_read(md, buf, count);
83 if (size != count)
84 error_die("short read");
85 }
86}
87
88/* Die with an error message if we can't read one character. */
89unsigned char xread_char(struct mbreader_t *md)
90{
91 unsigned char tmp;
92
93 xread(md, &tmp, 1);
94
95 return tmp;
96}
97
98void check_header_gzip(struct mbreader_t *src_md)
99{
100 union {
101 unsigned char raw[8];
102 struct {
103 unsigned char method;
104 unsigned char flags;
105 unsigned int mtime;
106 unsigned char xtra_flags;
107 unsigned char os_flags;
108 } formatted;
109 } header;
110
111 xread(src_md, header.raw, 8);
112
113 /* Check the compression method */
114 if (header.formatted.method != 8)
115 error_die("Unknown compression method");
116
117 if (header.formatted.flags & 0x04)
118 {
119 /* bit 2 set: extra field present */
120 unsigned char extra_short;
121
122 extra_short = xread_char(src_md) + (xread_char(src_md) << 8);
123 while (extra_short > 0)
124 {
125 /* Ignore extra field */
126 xread_char(src_md);
127 extra_short--;
128 }
129 }
130
131 /* Discard original name if any */
132 if (header.formatted.flags & 0x08)
133 /* bit 3 set: original file name present */
134 while(xread_char(src_md) != 0) ;
135
136 /* Discard file comment if any */
137 if (header.formatted.flags & 0x10)
138 /* bit 4 set: file comment present */
139 while(xread_char(src_md) != 0) ;
140
141 /* Read the header checksum */
142 if (header.formatted.flags & 0x02)
143 {
144 xread_char(src_md);
145 xread_char(src_md);
146 }
147}
diff --git a/apps/codecs/libgme/inflate/bbfuncs.h b/apps/codecs/libgme/inflate/bbfuncs.h
new file mode 100644
index 0000000000..fe03ec1a3c
--- /dev/null
+++ b/apps/codecs/libgme/inflate/bbfuncs.h
@@ -0,0 +1,33 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef BBFUNCS_H
21#define BBFUNCS_H
22
23#include "mbreader.h"
24
25void error_die(const char* msg);
26void error_msg(const char* msg);
27size_t safe_read(struct mbreader_t *md, void *buf, size_t count);
28ssize_t full_read(struct mbreader_t *md, void *buf, size_t len);
29void xread(struct mbreader_t *md, void *buf, ssize_t count);
30unsigned char xread_char(struct mbreader_t *md);
31void check_header_gzip(struct mbreader_t *md);
32
33#endif
diff --git a/apps/codecs/libgme/inflate/inflate.c b/apps/codecs/libgme/inflate/inflate.c
new file mode 100644
index 0000000000..807dee302e
--- /dev/null
+++ b/apps/codecs/libgme/inflate/inflate.c
@@ -0,0 +1,1159 @@
1/*
2 * gunzip implementation for wikiviewer (c) Frederik M.J.V., 2006.
3 * some bug fixes by Adam Gashlin gunzip implementation for busybox
4 *
5 * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
6 *
7 * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
8 * based on gzip sources
9 *
10 * Adjusted further by Erik Andersen <andersen@codepoet.org> to support files as
11 *well as stdin/stdout, and to generally behave itself wrt command line
12 *handling.
13 *
14 * General cleanup to better adhere to the style guide and make use of standard
15 *busybox functions by Glenn McGrath <bug1@iinet.net.au>
16 *
17 * read_gz interface + associated hacking by Laurence Anderson
18 *
19 * Fixed huft_build() so decoding end-of-block code does not grab more bits than
20 *necessary (this is required by unzip applet), added inflate_cleanup() to free
21 *leaked bytebuffer memory (used in unzip.c), and some minor style guide
22 *cleanups by Ed Clark
23 *
24 * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
25 *Copyright (C) 1992-1993 Jean-loup Gailly The unzip code was written and put in
26 *the public domain by Mark Adler. Portions of the lzw code are derived from the
27 *public domain 'compress'
28 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
29 *Ken Turkowski, Dave Mack and Peter Jannesen.
30 *
31 *
32 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
33 */
34
35#include <inttypes.h>
36#ifndef NULL
37#define NULL 0
38#endif
39#define ENABLE_DESKTOP 0
40#define USE_DESKTOP(...)
41#include "mallocer.h"
42#include "bbfuncs.h"
43#include "inflate.h"
44#include "mallocer.h"
45
46#define TRIM_FILE_ON_ERROR 1
47
48typedef struct huft_s {
49 unsigned char e; /* number of extra bits or operation */
50 unsigned char b; /* number of bits in this code or subcode */
51 union {
52 unsigned short n; /* literal, length base, or distance base */
53 struct huft_s *t; /* pointer to next level of table */
54 } v;
55} huft_t;
56
57/*static void *mainmembuf;*/
58static void *huftbuffer1;
59static void *huftbuffer2;
60
61#define HUFT_MMP1 8
62#define HUFT_MMP2 9
63
64static struct mbreader_t *gunzip_src_md;
65static unsigned int gunzip_bytes_out; /* number of output bytes */
66static unsigned int gunzip_outbuf_count; /* bytes in output buffer */
67
68/* gunzip_window size--must be a power of two, and at least 32K for zip's
69 deflate method */
70enum {
71 gunzip_wsize = 0x8000
72};
73
74static unsigned char *gunzip_window;
75static uint32_t ifl_total;
76
77static uint32_t gunzip_crc;
78
79/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
80#define BMAX 16 /* maximum bit length of any code (16 for explode) */
81#define N_MAX 288 /* maximum number of codes in any set */
82
83/* bitbuffer */
84static unsigned int gunzip_bb; /* bit buffer */
85static unsigned char gunzip_bk; /* bits in bit buffer */
86
87/* These control the size of the bytebuffer */
88static unsigned int bytebuffer_max = 0x8000;
89static unsigned char *bytebuffer = NULL;
90static unsigned int bytebuffer_offset = 0;
91static unsigned int bytebuffer_size = 0;
92
93static const unsigned short mask_bits[] = {
94 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
95 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
96};
97
98/* Copy lengths for literal codes 257..285 */
99static const unsigned short cplens[] = {
100 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
101 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
102};
103
104/* note: see note #13 above about the 258 in this list. */
105/* Extra bits for literal codes 257..285 */
106static const unsigned char cplext[] = {
107 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
108 5, 5, 5, 0, 99, 99
109}; /* 99==invalid */
110
111/* Copy offsets for distance codes 0..29 */
112static const unsigned short cpdist[] = {
113 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
114 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
115};
116
117/* Extra bits for distance codes */
118static const unsigned char cpdext[] = {
119 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
120 11, 11, 12, 12, 13, 13
121};
122
123/* Tables for deflate from PKZIP's appnote.txt. */
124/* Order of the bit length code lengths */
125static const unsigned char border[] = {
126 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
127};
128
129static const uint32_t crc_table[256]= {
130 0,1996959894,-301047508,-1727442502,124634137,1886057615,
131 -379345611,-1637575261,249268274,2044508324,-522852066,
132 -1747789432,162941995,2125561021,-407360249,-1866523247,
133 498536548,1789927666,-205950648,-2067906082,450548861,
134 1843258603,-187386543,-2083289657,325883990,1684777152,
135 -43845254,-1973040660,335633487,1661365465,-99664541,
136 -1928851979,997073096,1281953886,-715111964,-1570279054,
137 1006888145,1258607687,-770865667,-1526024853,901097722,
138 1119000684,-608450090,-1396901568,853044451,1172266101,
139 -589951537,-1412350631,651767980,1373503546,-925412992,
140 -1076862698,565507253,1454621731,-809855591,-1195530993,
141 671266974,1594198024,-972236366,-1324619484,795835527,
142 1483230225,-1050600021,-1234817731,1994146192,31158534,
143 -1731059524,-271249366,1907459465,112637215,-1614814043,
144 -390540237,2013776290,251722036,-1777751922,-519137256,
145 2137656763,141376813,-1855689577,-429695999,1802195444,
146 476864866,-2056965928,-228458418,1812370925,453092731,
147 -2113342271,-183516073,1706088902,314042704,-1950435094,
148 -54949764,1658658271,366619977,-1932296973,-69972891,
149 1303535960,984961486,-1547960204,-725929758,1256170817,
150 1037604311,-1529756563,-740887301,1131014506,879679996,
151 -1385723834,-631195440,1141124467,855842277,-1442165665,
152 -586318647,1342533948,654459306,-1106571248,-921952122,
153 1466479909,544179635,-1184443383,-832445281,1591671054,
154 702138776,-1328506846,-942167884,1504918807,783551873,
155 -1212326853,-1061524307,-306674912,-1698712650,62317068,
156 1957810842,-355121351,-1647151185,81470997,1943803523,
157 -480048366,-1805370492,225274430,2053790376,-468791541,
158 -1828061283,167816743,2097651377,-267414716,-2029476910,
159 503444072,1762050814,-144550051,-2140837941,426522225,
160 1852507879,-19653770,-1982649376,282753626,1742555852,
161 -105259153,-1900089351,397917763,1622183637,-690576408,
162 -1580100738,953729732,1340076626,-776247311,-1497606297,
163 1068828381,1219638859,-670225446,-1358292148,906185462,
164 1090812512,-547295293,-1469587627,829329135,1181335161,
165 -882789492,-1134132454,628085408,1382605366,-871598187,
166 -1156888829,570562233,1426400815,-977650754,-1296233688,
167 733239954,1555261956,-1026031705,-1244606671,752459403,
168 1541320221,-1687895376,-328994266,1969922972,40735498,
169 -1677130071,-351390145,1913087877,83908371,-1782625662,
170 -491226604,2075208622,213261112,-1831694693,-438977011,
171 2094854071,198958881,-2032938284,-237706686,1759359992,
172 534414190,-2118248755,-155638181,1873836001,414664567,
173 -2012718362,-15766928,1711684554,285281116,-1889165569,
174 -127750551,1634467795,376229701,-1609899400,-686959890,
175 1308918612,956543938,-1486412191,-799009033,1231636301,
176 1047427035,-1362007478,-640263460,1088359270,936918000,
177 -1447252397,-558129467,1202900863,817233897,-1111625188,
178 -893730166,1404277552,615818150,-1160759803,-841546093,
179 1423857449,601450431,-1285129682,-1000256840,1567103746,
180 711928724,-1274298825,-1022587231,1510334235,755167117
181};
182
183static unsigned int fill_bitbuffer(unsigned int bitbuffer, unsigned int *current,
184 const unsigned int required)
185{
186 while (*current < required)
187 {
188 if (bytebuffer_offset >= bytebuffer_size)
189 {
190 /* Leave the first 4 bytes empty so we can always unwind the
191 bitbuffer to the front of the bytebuffer, leave 4 bytes free at
192 end of tail so we can easily top up buffer in
193 check_trailer_gzip() */
194 if (1 > (bytebuffer_size = safe_read(gunzip_src_md, &bytebuffer[4],
195 bytebuffer_max - 8)))
196 error_die("unexpected end of file");
197
198 bytebuffer_size += 4;
199 bytebuffer_offset = 4;
200 }
201
202 bitbuffer |= ((unsigned int) bytebuffer[bytebuffer_offset]) << *current;
203 bytebuffer_offset++;
204 *current += 8;
205 }
206 return(bitbuffer);
207}
208
209/*
210 * Free the malloc'ed tables built by huft_build(), which makes a linked list of
211 *the tables it made, with the links in a dummy first entry of each table.
212 * t: table to free
213 */
214static int huft_free(huft_t * t,unsigned char bufnum)
215{
216 wpw_reset_mempool(bufnum);
217 if(t==0)
218 {
219 }
220
221 return 0;
222}
223
224/* Given a list of code lengths and a maximum table size, make a set of tables
225 to decode that set of codes. Return zero on success, one if the given code
226 set is incomplete (the tables are still built in this case), two if the input
227 is invalid (all zero length codes or an oversubscribed set of lengths), and
228 three if not enough memory.
229 *
230 * b: code lengths in bits (all assumed <= BMAX) n: number of codes
231 *(assumed <= N_MAX) s: number of simple-valued codes (0..s-1) d: list of
232 *base values for non-simple codes e: list of extra bits for non-simple codes
233 *t: result: starting table m: maximum lookup bits, returns actual bufnum:
234 *the number of the memory pool to fetch memory from
235 */
236static
237int huft_build(unsigned int *b, const unsigned int n,
238 const unsigned int s, const unsigned short *d,
239 const unsigned char *e, huft_t ** t, unsigned int *m,
240 unsigned char bufnum)
241{
242 unsigned a=0; /* counter for codes of length k */
243 unsigned c[BMAX + 1]; /* bit length count table */
244 unsigned eob_len=0; /* length of end-of-block code (value 256) */
245 unsigned f=0; /* i repeats in table every f entries */
246 int g=0; /* maximum code length */
247 int htl=0; /* table level */
248 unsigned i=0; /* counter, current code */
249 unsigned j=0; /* counter */
250 int k=0; /* number of bits in current code */
251 unsigned *p; /* pointer into c[], b[], or v[] */
252 huft_t *q; /* points to current table */
253 huft_t r; /* table entry for structure assignment */
254 huft_t *u[BMAX]; /* table stack */
255 unsigned v[N_MAX]; /* values in order of bit length */
256 int ws[BMAX+1]; /* bits decoded stack */
257 int w=0; /* bits decoded */
258 unsigned x[BMAX + 1]; /* bit offsets, then code stack */
259 unsigned *xp; /* pointer into x */
260 int y=0; /* number of dummy codes added */
261 unsigned z=0; /* number of entries in current table */
262
263 /* Length of EOB code, if any */
264 eob_len = n > 256 ? b[256] : BMAX;
265
266 /* Generate counts for each bit length */
267 memset((void *)c, 0, sizeof(c));
268 p = b;
269 i = n;
270 do {
271 c[*p]++; /* assume all entries <= BMAX */
272 p++; /* Can't combine with above line (Solaris bug) */
273 } while (--i);
274 if (c[0] == n) /* null input--all zero length codes */
275 {
276 *t = (huft_t *) NULL;
277 *m = 0;
278 return 2;
279 }
280
281 /* Find minimum and maximum length, bound *m by those */
282 for (j = 1; (c[j] == 0) && (j <= BMAX); j++) ;
283
284 k = j; /* minimum code length */
285 for (i = BMAX; (c[i] == 0) && i; i--) ;
286
287 g = i; /* maximum code length */
288 *m = (*m < j) ? j : ((*m > i) ? i : *m);
289
290 /* Adjust last length count to fill out codes, if needed */
291 for (y = 1 << j; j < i; j++, y <<= 1)
292 {
293 if ((y -= c[j]) < 0)
294 return 2; /* bad input: more codes than bits */
295 }
296
297 if ((y -= c[i]) < 0)
298 return 2;
299
300 c[i] += y;
301
302 /* Generate starting offsets into the value table for each length */
303 x[1] = j = 0;
304 p = c + 1;
305 xp = x + 2;
306 while (--i) /* note that i == g from above */
307 {
308 *xp++ = (j += *p++);
309 }
310
311 /* Make a table of values in order of bit lengths */
312 p = b;
313 i = 0;
314 do {
315 if ((j = *p++) != 0)
316 v[x[j]++] = i;
317 } while (++i < n);
318
319 /* Generate the Huffman codes and for each, make the table entries */
320 x[0] = i = 0; /* first Huffman code is zero */
321 p = v; /* grab values in bit order */
322 htl = -1; /* no tables yet--level -1 */
323 w = ws[0] = 0; /* bits decoded */
324 u[0] = (huft_t *) NULL; /* just to keep compilers happy */
325 q = (huft_t *) NULL; /* ditto */
326 z = 0; /* ditto */
327
328 /* go through the bit lengths (k already is bits in shortest code) */
329 for (; k <= g; k++)
330 {
331 a = c[k];
332 while (a--)
333 {
334 /* here i is the Huffman code of length k bits for value *p */
335 /* make tables up to required level */
336 while (k > ws[htl + 1])
337 {
338 w = ws[++htl];
339
340 /* compute minimum size table less than or equal to *m bits */
341 z = (z = g - w) > *m ? *m : z; /* upper limit on table size */
342 if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
343 { /* too few codes for k-w bit table */
344 f -= a + 1; /* deduct codes from patterns left */
345 xp = c + k;
346 while (++j < z) /* try smaller tables up to z bits */
347 {
348 if ((f <<= 1) <= *++xp)
349 break; /* enough codes to use up j bits */
350
351 f -= *xp; /* else deduct codes from patterns */
352 }
353 }
354
355 j = ((unsigned)(w + j) > eob_len && (unsigned)w < eob_len)
356 ? eob_len - w : j; /* make EOB code end at table */
357 z = 1 << j; /* table entries for j-bit table */
358 ws[htl+1] = w + j; /* set bits decoded in stack */
359
360 /* allocate and link in new table */
361 q = (huft_t *) wpw_malloc(bufnum,(z + 1) * sizeof(huft_t));
362 if(q==0)
363 return 3;
364
365 *t = q + 1; /* link to list for huft_free() */
366 t = &(q->v.t);
367 u[htl] = ++q; /* table starts after link */
368
369 /* connect to last table, if there is one */
370 if (htl)
371 {
372 x[htl] = i; /* save pattern for backing up */
373
374 /* bits to dump before this table */
375 r.b = (unsigned char) (w - ws[htl - 1]);
376 r.e = (unsigned char) (16 + j); /* bits in this table */
377 r.v.t = q; /* pointer to this table */
378 j = (i & ((1 << w) - 1)) >> ws[htl - 1];
379 u[htl - 1][j] = r; /* connect to last table */
380 }
381 }
382
383 /* set up table entry in r */
384 r.b = (unsigned char) (k - w);
385 if (p >= v + n)
386 r.e = 99; /* out of values--invalid code */
387 else if (*p < s)
388 {
389 r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB
390 code */
391 r.v.n = (unsigned short) (*p++); /* simple code is just the
392 value */
393 }
394 else
395 {
396 r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists
397 */
398 r.v.n = d[*p++ - s];
399 }
400
401 /* fill code-like entries with r */
402 f = 1 << (k - w);
403 for (j = i >> w; j < z; j += f)
404 {
405 q[j] = r;
406 }
407
408 /* backwards increment the k-bit code i */
409 for (j = 1 << (k - 1); i &j; j >>= 1)
410 {
411 i ^= j;
412 }
413 i ^= j;
414
415 /* backup over finished tables */
416 while ((i & ((1 << w) - 1)) != x[htl])
417 {
418 w = ws[--htl];
419 }
420 }
421 }
422
423 /* return actual size of base table */
424 *m = ws[1];
425
426 /* Return true (1) if we were given an incomplete table */
427 return y != 0 && g != 1;
428}
429
430/*
431 * inflate (decompress) the codes in a deflated (compressed) block. Return an
432 *error code or zero if it all goes ok.
433 *
434 * tl, td: literal/length and distance decoder tables bl, bd: number of bits
435 *decoded by tl[] and td[]
436 */
437static int inflate_codes_resumeCopy = 0;
438static int inflate_codes(huft_t * my_tl, huft_t * my_td,
439 const unsigned int my_bl, const unsigned int my_bd,
440 int setup)
441{
442 static unsigned int e; /* table entry flag/number of extra bits */
443 static unsigned int n, d; /* length and index for copy */
444 static unsigned int w; /* current gunzip_window position */
445 static huft_t *t; /* pointer to table entry */
446 static unsigned int ml, md; /* masks for bl and bd bits */
447 static unsigned int b; /* bit buffer */
448 static unsigned int k; /* number of bits in bit buffer */
449 static huft_t *tl, *td;
450 static unsigned int bl, bd;
451
452 if (setup) /* 1st time we are called, copy in variables */
453 {
454 tl = my_tl;
455 td = my_td;
456 bl = my_bl;
457 bd = my_bd;
458 /* make local copies of globals */
459 b = gunzip_bb; /* initialize bit buffer */
460 k = gunzip_bk;
461 w = gunzip_outbuf_count; /* initialize gunzip_window position
462 */
463
464 /* inflate the coded data */
465 ml = mask_bits[bl]; /* precompute masks for speed */
466 md = mask_bits[bd];
467 return 0; /* Don't actually do anything the first time */
468 }
469
470 if (inflate_codes_resumeCopy) goto do_copy;
471
472 while (1) /* do until end of block */
473 {
474 b = fill_bitbuffer(b, &k, bl);
475 if ((e = (t = tl + ((unsigned) b & ml))->e) > 16)
476 do {
477 if (e == 99)
478 error_die("inflate_codes error 1");
479
480 b >>= t->b;
481 k -= t->b;
482 e -= 16;
483 b = fill_bitbuffer(b, &k, e);
484 } while ((e =
485 (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
486
487 b >>= t->b;
488 k -= t->b;
489 if (e == 16) /* then it's a literal */
490 {
491 gunzip_window[w++] = (unsigned char) t->v.n;
492 if (w == gunzip_wsize)
493 {
494 gunzip_outbuf_count = (w);
495 w = 0;
496 return 1; /* We have a block to read */
497 }
498 }
499 else /* it's an EOB or a length */
500 { /* exit if end of block */
501 if (e == 15)
502 break;
503
504 /* get length of block to copy */
505 b = fill_bitbuffer(b, &k, e);
506 n = t->v.n + ((unsigned) b & mask_bits[e]);
507 b >>= e;
508 k -= e;
509
510 /* decode distance of block to copy */
511 b = fill_bitbuffer(b, &k, bd);
512 if ((e = (t = td + ((unsigned) b & md))->e) > 16)
513 do {
514 if (e == 99)
515 error_die("inflate_codes error 2");
516
517 b >>= t->b;
518 k -= t->b;
519 e -= 16;
520 b = fill_bitbuffer(b, &k, e);
521 } while ((e =
522 (t =
523 t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
524
525 b >>= t->b;
526 k -= t->b;
527 b = fill_bitbuffer(b, &k, e);
528 d = w - t->v.n - ((unsigned) b & mask_bits[e]);
529 b >>= e;
530 k -= e;
531
532 /* do the copy */
533do_copy: do {
534 n -= (e =
535 (e =
536 gunzip_wsize - ((d &= gunzip_wsize - 1) > w ? d : w)) > n ? n : e);
537 /* copy to new buffer to prevent possible overwrite */
538 if (w - d >= e) /* (this test assumes unsigned comparison)
539 */
540 {
541 memcpy(gunzip_window + w, gunzip_window + d, e);
542 w += e;
543 d += e;
544 }
545 else
546 {
547 /* do it slow to avoid memcpy() overlap */
548 /* !NOMEMCPY */
549 do {
550 gunzip_window[w++] = gunzip_window[d++];
551 } while (--e);
552 }
553
554 if (w == gunzip_wsize)
555 {
556 gunzip_outbuf_count = (w);
557 if (n) inflate_codes_resumeCopy = 1;
558 else inflate_codes_resumeCopy = 0;
559
560 w = 0;
561 return 1;
562 }
563 } while (n);
564 inflate_codes_resumeCopy = 0;
565 }
566 }
567
568 /* restore the globals from the locals */
569 gunzip_outbuf_count = w; /* restore global gunzip_window pointer */
570 gunzip_bb = b; /* restore global bit buffer */
571 gunzip_bk = k;
572
573 /* normally just after call to inflate_codes, but save code by putting it
574 here */
575 /* free the decoding tables, return */
576 huft_free(tl,HUFT_MMP1);
577 huft_free(td,HUFT_MMP2);
578
579 /* done */
580 return 0;
581}
582
583static int inflate_stored(int my_n, int my_b_stored, int my_k_stored, int setup)
584{
585 static unsigned int n, b_stored, k_stored, w;
586 if (setup)
587 {
588 n = my_n;
589 b_stored = my_b_stored;
590 k_stored = my_k_stored;
591 w = gunzip_outbuf_count; /* initialize gunzip_window position */
592 return 0; /* Don't do anything first time */
593 }
594
595 /* read and output the compressed data */
596 while (n--)
597 {
598 b_stored = fill_bitbuffer(b_stored, &k_stored, 8);
599 gunzip_window[w++] = (unsigned char) b_stored;
600 if (w == gunzip_wsize)
601 {
602 gunzip_outbuf_count = (w);
603 w = 0;
604 b_stored >>= 8;
605 k_stored -= 8;
606 return 1; /* We have a block */
607 }
608
609 b_stored >>= 8;
610 k_stored -= 8;
611 }
612
613 /* restore the globals from the locals */
614 gunzip_outbuf_count = w; /* restore global gunzip_window pointer */
615 gunzip_bb = b_stored; /* restore global bit buffer */
616 gunzip_bk = k_stored;
617 return 0; /* Finished */
618}
619
620/*
621 * decompress an inflated block e: last block flag
622 *
623 * GLOBAL VARIABLES: bb, kk,
624 */
625/* Return values: -1 = inflate_stored, -2 = inflate_codes */
626static int inflate_block(int *e)
627{
628 unsigned t; /* block type */
629 unsigned int b; /* bit buffer */
630 unsigned int k; /* number of bits in bit buffer */
631
632 /* make local bit buffer */
633
634 b = gunzip_bb;
635 k = gunzip_bk;
636
637 /* read in last block bit */
638 b = fill_bitbuffer(b, &k, 1);
639 *e = (int) b & 1;
640 b >>= 1;
641 k -= 1;
642
643 /* read in block type */
644 b = fill_bitbuffer(b, &k, 2);
645 t = (unsigned) b & 3;
646 b >>= 2;
647 k -= 2;
648
649 /* restore the global bit buffer */
650 gunzip_bb = b;
651 gunzip_bk = k;
652
653 /* inflate that block type */
654 switch (t)
655 {
656 case 0: /* Inflate stored */
657 {
658 unsigned int n=0; /* number of bytes in block */
659 unsigned int b_stored=0; /* bit buffer */
660 unsigned int k_stored=0; /* number of bits in bit buffer */
661
662 /* make local copies of globals */
663 b_stored = gunzip_bb; /* initialize bit buffer */
664 k_stored = gunzip_bk;
665
666 /* go to byte boundary */
667 n = k_stored & 7;
668 b_stored >>= n;
669 k_stored -= n;
670
671 /* get the length and its complement */
672 b_stored = fill_bitbuffer(b_stored, &k_stored, 16);
673 n = ((unsigned) b_stored & 0xffff);
674 b_stored >>= 16;
675 k_stored -= 16;
676
677 b_stored = fill_bitbuffer(b_stored, &k_stored, 16);
678 if (n != (unsigned) ((~b_stored) & 0xffff))
679 return 1; /* error in compressed data */
680
681 b_stored >>= 16;
682 k_stored -= 16;
683
684 inflate_stored(n, b_stored, k_stored, 1); /* Setup inflate_stored */
685 return -1;
686 }
687 case 1: /* Inflate fixed decompress an inflated type 1 (fixed
688 Huffman codes) block. We should either replace this
689 with a custom decoder, or at least precompute the
690 Huffman tables.
691 */
692 {
693 int i; /* temporary variable */
694 huft_t *tl; /* literal/length code table */
695 huft_t *td; /* distance code table */
696 unsigned int bl; /* lookup bits for tl */
697 unsigned int bd; /* lookup bits for td */
698 unsigned int l[288]; /* length list for huft_build */
699
700 /* set up literal table */
701 for (i = 0; i < 144; i++)
702 {
703 l[i] = 8;
704 }
705 for (; i < 256; i++)
706 {
707 l[i] = 9;
708 }
709 for (; i < 280; i++)
710 {
711 l[i] = 7;
712 }
713 for (; i < 288; i++) /* make a complete, but wrong code set */
714 {
715 l[i] = 8;
716 }
717 bl = 7;
718 if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl,HUFT_MMP1)) != 0)
719 return i;
720
721 /* set up distance table */
722 for (i = 0; i < 30; i++) /* make an incomplete code set */
723 {
724 l[i] = 5;
725 }
726 bd = 5;
727 if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd,HUFT_MMP2)) > 1)
728 {
729 huft_free(tl,HUFT_MMP1);
730 return i;
731 }
732
733 /* decompress until an end-of-block code */
734 inflate_codes(tl, td, bl, bd, 1); /* Setup inflate_codes */
735
736 /* huft_free code moved into inflate_codes */
737
738 return -2;
739 }
740 case 2: /* Inflate dynamic */
741 {
742 const int dbits = 6; /* bits in base distance lookup table */
743 const int lbits = 9; /* bits in base literal/length lookup table */
744
745 huft_t *tl; /* literal/length code table */
746 huft_t *td; /* distance code table */
747 unsigned int i; /* temporary variables */
748 unsigned int j;
749 unsigned int l; /* last length */
750 unsigned int m; /* mask for bit lengths table */
751 unsigned int n; /* number of lengths to get */
752 unsigned int bl; /* lookup bits for tl */
753 unsigned int bd; /* lookup bits for td */
754 unsigned int nb; /* number of bit length codes */
755 unsigned int nl; /* number of literal/length codes */
756 unsigned int nd; /* number of distance codes */
757
758 unsigned int ll[286 + 30]; /* literal/length and distance code
759 lengths */
760 unsigned int b_dynamic; /* bit buffer */
761 unsigned int k_dynamic; /* number of bits in bit buffer */
762
763 /* make local bit buffer */
764 b_dynamic = gunzip_bb;
765 k_dynamic = gunzip_bk;
766
767 /* read in table lengths */
768 b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5);
769 nl = 257 + ((unsigned int) b_dynamic & 0x1f); /* number of
770 literal/length codes
771 */
772
773 b_dynamic >>= 5;
774 k_dynamic -= 5;
775 b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5);
776 nd = 1 + ((unsigned int) b_dynamic & 0x1f); /* number of distance
777 codes */
778
779 b_dynamic >>= 5;
780 k_dynamic -= 5;
781 b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 4);
782 nb = 4 + ((unsigned int) b_dynamic & 0xf); /* number of bit length
783 codes */
784
785 b_dynamic >>= 4;
786 k_dynamic -= 4;
787 if (nl > 286 || nd > 30)
788 return 1; /* bad lengths */
789
790 /* read in bit-length-code lengths */
791 for (j = 0; j < nb; j++)
792 {
793 b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3);
794 ll[border[j]] = (unsigned int) b_dynamic & 7;
795 b_dynamic >>= 3;
796 k_dynamic -= 3;
797 }
798 for (; j < 19; j++)
799 {
800 ll[border[j]] = 0;
801 }
802
803 /* build decoding table for trees--single level, 7 bit lookup */
804 bl = 7;
805 i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl,HUFT_MMP1);
806 if (i != 0)
807 {
808 if (i == 1)
809 huft_free(tl,HUFT_MMP1);
810
811 return i; /* incomplete code set */
812 }
813
814 /* read in literal and distance code lengths */
815 n = nl + nd;
816 m = mask_bits[bl];
817 i = l = 0;
818 while ((unsigned int) i < n)
819 {
820 b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, (unsigned int)bl);
821 j = (td = tl + ((unsigned int) b_dynamic & m))->b;
822 b_dynamic >>= j;
823 k_dynamic -= j;
824 j = td->v.n;
825 if (j < 16) /* length of code in bits (0..15) */
826 ll[i++] = l = j; /* save last length in l */
827 else if (j == 16) /* repeat last length 3 to 6 times */
828 {
829 b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 2);
830 j = 3 + ((unsigned int) b_dynamic & 3);
831 b_dynamic >>= 2;
832 k_dynamic -= 2;
833 if ((unsigned int) i + j > n)
834 return 1;
835
836 while (j--)
837 {
838 ll[i++] = l;
839 }
840 }
841 else if (j == 17) /* 3 to 10 zero length codes */
842 {
843 b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3);
844 j = 3 + ((unsigned int) b_dynamic & 7);
845 b_dynamic >>= 3;
846 k_dynamic -= 3;
847 if ((unsigned int) i + j > n)
848 return 1;
849
850 while (j--)
851 {
852 ll[i++] = 0;
853 }
854 l = 0;
855 }
856 else /* j == 18: 11 to 138 zero length codes */
857 {
858 b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 7);
859 j = 11 + ((unsigned int) b_dynamic & 0x7f);
860 b_dynamic >>= 7;
861 k_dynamic -= 7;
862 if ((unsigned int) i + j > n)
863 return 1;
864
865 while (j--)
866 {
867 ll[i++] = 0;
868 }
869 l = 0;
870 }
871 }
872
873 /* free decoding table for trees */
874 huft_free(tl,HUFT_MMP1);
875
876 /* restore the global bit buffer */
877 gunzip_bb = b_dynamic;
878 gunzip_bk = k_dynamic;
879
880 /* build the decoding tables for literal/length and distance codes */
881 bl = lbits;
882
883 if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl,HUFT_MMP1)) != 0)
884 {
885 if (i == 1)
886 {
887 error_die("Incomplete literal tree");
888 huft_free(tl,HUFT_MMP1);
889 }
890
891 return i; /* incomplete code set */
892 }
893
894 bd = dbits;
895 if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd,HUFT_MMP2)) != 0)
896 {
897 if (i == 1)
898 {
899 error_die("incomplete distance tree");
900 huft_free(td,HUFT_MMP2);
901 }
902
903 huft_free(tl,HUFT_MMP1);
904 return i; /* incomplete code set */
905 }
906
907 /* decompress until an end-of-block code */
908 inflate_codes(tl, td, bl, bd, 1); /* Setup inflate_codes */
909
910 /* huft_free code moved into inflate_codes */
911
912 return -2;
913 }
914 default:
915 /* bad block type */
916 error_die("bad block type");
917 }
918 return 0;
919}
920
921static void calculate_gunzip_crc(void)
922{
923 unsigned int n;
924 for (n = 0; n < gunzip_outbuf_count; n++)
925 {
926 gunzip_crc = crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff]
927 ^ (gunzip_crc >> 8);
928 }
929 gunzip_bytes_out += gunzip_outbuf_count;
930}
931
932static int inflate_get_next_window_method = -1; /* Method == -1 for stored, -2
933 for codes */
934static int inflate_get_next_window_e = 0;
935static int inflate_get_next_window_needAnotherBlock = 1;
936
937static int inflate_get_next_window(void)
938{
939 gunzip_outbuf_count = 0;
940
941 while(1)
942 {
943 int ret=0;
944 if (inflate_get_next_window_needAnotherBlock)
945 {
946 if(inflate_get_next_window_e)
947 {
948 calculate_gunzip_crc();
949 inflate_get_next_window_e = 0;
950 inflate_get_next_window_needAnotherBlock = 1;
951 return 0;
952 } /* Last block */
953
954 inflate_get_next_window_method = inflate_block(&inflate_get_next_window_e);
955 inflate_get_next_window_needAnotherBlock = 0;
956 }
957
958 switch (inflate_get_next_window_method)
959 {
960 case -1: ret = inflate_stored(0,0,0,0);
961 break;
962 case -2: ret = inflate_codes(0,0,0,0,0);
963 break;
964 default:
965 error_die("inflate error");
966 }
967
968 if (ret == 1)
969 {
970 calculate_gunzip_crc();
971 return 1; /* More data left */
972 }
973 else inflate_get_next_window_needAnotherBlock = 1; /* End of that
974 block */
975 }
976 /* Doesnt get here */
977}
978
979/* Initialise bytebuffer, be careful not to overfill the buffer */
980static void inflate_init(unsigned int bufsize)
981{
982 /* Set the bytebuffer size, default is same as gunzip_wsize */
983 bytebuffer_max = bufsize + 8;
984 bytebuffer_offset = 4;
985 bytebuffer_size = 0;
986}
987
988static void inflate_cleanup(void)
989{
990 /* free(bytebuffer); */
991}
992
993USE_DESKTOP(long long) static int
994inflate_unzip(struct mbreader_t *in,char* outbuffer,uint32_t outbuflen)
995{
996 USE_DESKTOP(long long total = 0; )
997 typedef void (*sig_type)(int);
998
999 /* Allocate all global buffers (for DYN_ALLOC option) */
1000 gunzip_outbuf_count = 0;
1001 gunzip_bytes_out = 0;
1002 gunzip_src_md = in;
1003
1004 /* initialize gunzip_window, bit buffer */
1005 gunzip_bk = 0;
1006 gunzip_bb = 0;
1007
1008 /* Create the crc table */
1009 gunzip_crc = ~0;
1010
1011 /* Allocate space for buffer */
1012 while(1)
1013 {
1014 int ret = inflate_get_next_window();
1015 if((signed int)outbuflen-(signed int)gunzip_outbuf_count<0)
1016 {
1017 error_msg("write_error");
1018 #ifdef TRIM_FILE_ON_ERROR
1019 return USE_DESKTOP(total) + 0;
1020 #else
1021 return -1;
1022 #endif
1023 }
1024
1025 memcpy(outbuffer,gunzip_window,gunzip_outbuf_count);
1026 outbuffer+=sizeof(char)*gunzip_outbuf_count;
1027 ifl_total+=sizeof(char)*gunzip_outbuf_count;
1028 outbuflen-=gunzip_outbuf_count;
1029 USE_DESKTOP(total += gunzip_outbuf_count; )
1030 if (ret == 0) break;
1031 }
1032
1033 /* Store unused bytes in a global buffer so calling applets can access it */
1034 if (gunzip_bk >= 8)
1035 {
1036 /* Undo too much lookahead. The next read will be byte aligned so we can
1037 discard unused bits in the last meaningful byte. */
1038 bytebuffer_offset--;
1039 bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff;
1040 gunzip_bb >>= 8;
1041 gunzip_bk -= 8;
1042 }
1043
1044 return USE_DESKTOP(total) + 0;
1045}
1046
1047USE_DESKTOP(long long) static int
1048inflate_gunzip(struct mbreader_t *in,char* outbuffer,uint32_t outbuflen)
1049{
1050 uint32_t stored_crc = 0;
1051 unsigned int count;
1052 USE_DESKTOP(long long total = ) inflate_unzip(in, outbuffer,outbuflen);
1053
1054 USE_DESKTOP(if (total < 0) return total;
1055
1056 )
1057
1058 /* top up the input buffer with the rest of the trailer */
1059 count = bytebuffer_size - bytebuffer_offset;
1060 if (count < 8)
1061 {
1062 xread(in, &bytebuffer[bytebuffer_size], 8 - count);
1063 bytebuffer_size += 8 - count;
1064 }
1065
1066 for (count = 0; count != 4; count++)
1067 {
1068 stored_crc |= (bytebuffer[bytebuffer_offset] << (count * 8));
1069 bytebuffer_offset++;
1070 }
1071
1072 /* Validate decompression - crc */
1073 if (stored_crc != (~gunzip_crc))
1074 {
1075 error_msg("crc error");
1076
1077 #ifdef TRIM_FILE_ON_ERROR
1078 return USE_DESKTOP(total) + 0;
1079 #else
1080 return -1;
1081 #endif
1082 }
1083
1084 /* Validate decompression - size */
1085 if ((signed int)gunzip_bytes_out !=
1086 (bytebuffer[bytebuffer_offset] | (bytebuffer[bytebuffer_offset+1] << 8) |
1087 (bytebuffer[bytebuffer_offset+2] << 16) | (bytebuffer[bytebuffer_offset+3] << 24)))
1088 {
1089 error_msg("incorrect length");
1090 return -1;
1091 }
1092
1093 return USE_DESKTOP(total) + 0;
1094}
1095
1096/*An allocated memory buffer at least 0x13100 (72448) bytes long*/
1097uint32_t decompress(const char *inbuffer,uint32_t inbuflen,char* outbuffer,uint32_t outbuflen,uint32_t offset,char* membuf)
1098{
1099 signed char status=0;
1100 int exitcode=0;
1101 struct mbreader_t src_md;
1102 ifl_total=0;
1103 /* reset statics */
1104 inflate_codes_resumeCopy = 0;
1105 inflate_get_next_window_method = -1; /* Method == -1 for stored, -2 for
1106 codes */
1107 inflate_get_next_window_e = 0;
1108 inflate_get_next_window_needAnotherBlock = 1;
1109 /* init */
1110 inflate_init(0x8000-8);
1111 /*Memory init*/
1112 huftbuffer1=membuf;
1113 huftbuffer2=membuf+0x2A00;
1114 gunzip_window=membuf+0x2A00+0xA00;
1115 bytebuffer=membuf+0x2A00+0xA00+0x8000;
1116 wpw_init_mempool_pdm(HUFT_MMP1,(unsigned char*)huftbuffer1,0x2A00);
1117 wpw_init_mempool_pdm(HUFT_MMP2,(unsigned char*)huftbuffer2,0xA00);
1118
1119 /* Initialize memory buffer reader */
1120 src_md.ptr = inbuffer;
1121 src_md.size = inbuflen;
1122 src_md.offset = offset;
1123
1124 if ((exitcode=xread_char(&src_md)) == 0x1f)
1125 {
1126 unsigned char magic2;
1127 magic2 = xread_char(&src_md);
1128 if (magic2 == 0x8b)
1129 {
1130 check_header_gzip(&src_md); /* FIXME: xfunc? _or_die? */
1131 status = inflate_gunzip(&src_md, outbuffer,outbuflen);
1132 }
1133 else
1134 {
1135 error_msg("invalid magic");
1136 exitcode = -1;
1137 }
1138
1139 if (status < 0)
1140 {
1141 error_msg("error inflating");
1142 exitcode = -1;
1143 }
1144 }
1145 else
1146 {
1147 error_msg("invalid magic");
1148 exitcode = -1;
1149 }
1150
1151 inflate_cleanup();
1152 wpw_destroy_mempool(HUFT_MMP1);
1153 wpw_destroy_mempool(HUFT_MMP2);
1154
1155 if(exitcode==-1)
1156 return 0;
1157
1158 return ifl_total;
1159}
diff --git a/apps/codecs/libgme/inflate/inflate.h b/apps/codecs/libgme/inflate/inflate.h
new file mode 100644
index 0000000000..05164621b9
--- /dev/null
+++ b/apps/codecs/libgme/inflate/inflate.h
@@ -0,0 +1,30 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef INFLATE_H
21#define INFLATE_H
22#include <inttypes.h>
23
24#if defined(ROCKBOX)
25#include "codeclib.h"
26#endif
27
28uint32_t decompress(const char *inbuffer,uint32_t inbuflen,char* outbuffer,uint32_t outbuflen,
29 uint32_t offset,char* membuf);
30#endif
diff --git a/apps/codecs/libgme/inflate/mallocer.c b/apps/codecs/libgme/inflate/mallocer.c
new file mode 100644
index 0000000000..41abedd09f
--- /dev/null
+++ b/apps/codecs/libgme/inflate/mallocer.c
@@ -0,0 +1,86 @@
1
2/*
3 Based on the wiki viewer mallocer
4 Copyright (C) 2005 Dave Chapman
5
6 @ Modified to decompress memory buffer by gama
7 */
8
9#include "mallocer.h"
10#include "codeclib.h"
11
12unsigned char* mallocbuffer[MEMPOOL_MAX];
13long memory_ptr[MEMPOOL_MAX];
14size_t buffersize[MEMPOOL_MAX];
15
16int wpw_init_mempool(unsigned char mempool)
17{
18 memory_ptr[mempool] = 0;
19 mallocbuffer[mempool] = (unsigned char *)ci->codec_get_buffer(&buffersize[mempool]);
20 // memset(mallocbuf[mempool], 0, bufsize[mempool]);
21 return 0;
22}
23
24int wpw_init_mempool_pdm(unsigned char mempool,
25 unsigned char* mem,long memsize)
26{
27 memory_ptr[mempool] = 0;
28 mallocbuffer[mempool] = mem;
29 buffersize[mempool]=memsize;
30 return 0;
31}
32
33void wpw_reset_mempool(unsigned char mempool)
34{
35 memory_ptr[mempool]=0;
36}
37
38void wpw_destroy_mempool(unsigned char mempool)
39{
40 memory_ptr[mempool] = 0;
41 mallocbuffer[mempool] =0;
42 buffersize[mempool]=0;
43}
44
45long wpw_available(unsigned char mempool)
46{
47 return buffersize[mempool]-memory_ptr[mempool];
48}
49
50void* wpw_malloc(unsigned char mempool,size_t size)
51{
52 void* x;
53
54 if (memory_ptr[mempool] + size > buffersize[mempool] )
55 return NULL;
56
57 x=&mallocbuffer[mempool][memory_ptr[mempool]];
58 memory_ptr[mempool]+=(size+3)&~3; /* Keep memory 32-bit aligned */
59
60 return(x);
61}
62
63void* wpw_calloc(unsigned char mempool,size_t nmemb, size_t size)
64{
65 void* x;
66 x = wpw_malloc(mempool,nmemb*size);
67 if (x == NULL)
68 return NULL;
69
70 memset(x,0,nmemb*size);
71 return(x);
72}
73
74void wpw_free(unsigned char mempool,void* ptr)
75{
76 (void)ptr;
77 (void)mempool;
78}
79
80void* wpw_realloc(unsigned char mempool,void* ptr, size_t size)
81{
82 void* x;
83 (void)ptr;
84 x = wpw_malloc(mempool,size);
85 return(x);
86}
diff --git a/apps/codecs/libgme/inflate/mallocer.h b/apps/codecs/libgme/inflate/mallocer.h
new file mode 100644
index 0000000000..091643443c
--- /dev/null
+++ b/apps/codecs/libgme/inflate/mallocer.h
@@ -0,0 +1,16 @@
1
2#define MEMPOOL_MAX 10
3#include <inttypes.h>
4#include <stdlib.h>
5
6int wpw_init_mempool(unsigned char mempool);
7int wpw_init_mempool_pdm(unsigned char mempool,
8 unsigned char* mem,long memsize);
9
10void wpw_reset_mempool(unsigned char mempool);
11void wpw_destroy_mempool(unsigned char mempool);
12void* wpw_malloc(unsigned char mempool,size_t size);
13void* wpw_calloc(unsigned char mempool,size_t nmemb, size_t size);
14void wpw_free(unsigned char mempool,void* ptr);
15void* wpw_realloc(unsigned char mempool,void* ptr, size_t size);
16long wpw_available(unsigned char mempool);
diff --git a/apps/codecs/libgme/inflate/mbreader.c b/apps/codecs/libgme/inflate/mbreader.c
new file mode 100644
index 0000000000..96e45cd6c8
--- /dev/null
+++ b/apps/codecs/libgme/inflate/mbreader.c
@@ -0,0 +1,16 @@
1
2/* Memory buffer reader, simulates file read
3 @ gama
4*/
5
6#include "mbreader.h"
7
8int mbread(struct mbreader_t *md, void *buf, size_t n)
9{
10 if (!md) return -1;
11 size_t read_bytes = (md->offset+n) > md->size ?
12 md->size-md->offset : n;
13 memcpy(buf,md->ptr + md->offset,read_bytes);
14 md->offset += read_bytes;
15 return read_bytes;
16}
diff --git a/apps/codecs/libgme/inflate/mbreader.h b/apps/codecs/libgme/inflate/mbreader.h
new file mode 100644
index 0000000000..6427f18231
--- /dev/null
+++ b/apps/codecs/libgme/inflate/mbreader.h
@@ -0,0 +1,15 @@
1
2#ifndef MBREADER_H
3#define MBREADER_H
4
5#include "codeclib.h"
6
7struct mbreader_t {
8 const char *ptr;
9 size_t size;
10 size_t offset;
11};
12
13int mbread(struct mbreader_t *md, void *buf, size_t n);
14
15#endif
diff --git a/apps/codecs/libgme/kss_cpu.c b/apps/codecs/libgme/kss_cpu.c
new file mode 100644
index 0000000000..891a7df255
--- /dev/null
+++ b/apps/codecs/libgme/kss_cpu.c
@@ -0,0 +1,35 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "kss_emu.h"
4
5#include "blargg_endian.h"
6//#include "z80_cpu_log.h"
7
8/* Copyright (C) 2006-2008 Shay Green. This module is free software; you
9can redistribute it and/or modify it under the terms of the GNU Lesser
10General Public License as published by the Free Software Foundation; either
11version 2.1 of the License, or (at your option) any later version. This
12module is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15details. You should have received a copy of the GNU Lesser General Public
16License along with this module; if not, write to the Free Software Foundation,
17Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19#include "blargg_source.h"
20
21#define OUT_PORT( addr, data ) cpu_out( this, TIME(), addr, data )
22#define IN_PORT( addr ) cpu_in( this, TIME(), addr )
23#define WRITE_MEM( addr, data ) {FLUSH_TIME(); cpu_write( this, addr, data );}
24#define IDLE_ADDR idle_addr
25
26#define CPU_BEGIN \
27bool run_cpu( struct Kss_Emu* this, kss_time_t end_time )\
28{\
29 struct Z80_Cpu *cpu = &this->cpu; \
30 Z80_set_end_time( cpu, end_time );
31
32 #include "z80_cpu_run.h"
33
34 return warning;
35}
diff --git a/apps/codecs/libgme/kss_emu.c b/apps/codecs/libgme/kss_emu.c
new file mode 100644
index 0000000000..b01034234a
--- /dev/null
+++ b/apps/codecs/libgme/kss_emu.c
@@ -0,0 +1,883 @@
1// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/
2
3#include "kss_emu.h"
4
5#include "blargg_endian.h"
6
7/* Copyright (C) 2006 Shay Green. This module is free software; you
8can redistribute it and/or modify it under the terms of the GNU Lesser
9General Public License as published by the Free Software Foundation; either
10version 2.1 of the License, or (at your option) any later version. This
11module is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14details. You should have received a copy of the GNU Lesser General Public
15License along with this module; if not, write to the Free Software Foundation,
16Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17
18#include "blargg_source.h"
19
20long const clock_rate = 3579545;
21
22const char gme_wrong_file_type [] = "Wrong file type for this emulator";
23
24int const stereo = 2; // number of channels for stereo
25int const silence_max = 6; // seconds
26int const silence_threshold = 0x10;
27long const fade_block_size = 512;
28int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
29
30void clear_track_vars( struct Kss_Emu* this )
31{
32 this->current_track = -1;
33 this->out_time = 0;
34 this->emu_time = 0;
35 this->emu_track_ended_ = true;
36 this->track_ended = true;
37 this->fade_start = INT_MAX / 2 + 1;
38 this->fade_step = 1;
39 this->silence_time = 0;
40 this->silence_count = 0;
41 this->buf_remain = 0;
42 // warning(); // clear warning
43}
44
45static blargg_err_t init_opl_apu( enum opl_type_t type, struct Opl_Apu* out )
46{
47 blip_time_t const period = 72;
48 int const rate = clock_rate / period;
49 return Opl_init( out, rate * period, rate, period, type );
50}
51
52void Kss_init( struct Kss_Emu* this )
53{
54 this->sample_rate = 0;
55 this->mute_mask_ = 0;
56 this->tempo = 1.0;
57 this->gain = 1.0;
58 this->chip_flags = 0;
59
60 // defaults
61 this->max_initial_silence = 2;
62 this->silence_lookahead = 6;
63 this->ignore_silence = false;
64
65 this->voice_count = 0;
66 clear_track_vars( this );
67
68 memset( this->unmapped_read, 0xFF, sizeof this->unmapped_read );
69
70 // Init all stuff
71 Buffer_init( &this->stereo_buffer );
72
73 Z80_init( &this->cpu );
74 Rom_init( &this->rom, page_size );
75
76 // Initialize all apus just once (?)
77 Sms_apu_init( &this->sms.psg);
78 Ay_apu_init( &this->msx.psg );
79 Scc_init( &this->msx.scc );
80
81#ifndef KSS_EMU_NO_FMOPL
82 init_opl_apu( type_smsfmunit, &this->sms.fm );
83 init_opl_apu( type_msxmusic, &this->msx.music );
84 init_opl_apu( type_msxaudio, &this->msx.audio );
85#endif
86}
87
88// Track info
89
90static blargg_err_t check_kss_header( void const* header )
91{
92 if ( memcmp( header, "KSCC", 4 ) && memcmp( header, "KSSX", 4 ) )
93 return gme_wrong_file_type;
94 return 0;
95}
96
97// Setup
98
99void update_gain( struct Kss_Emu* this )
100{
101 double g = this->gain;
102 if ( msx_music_enabled( this ) || msx_audio_enabled( this )
103 || sms_fm_enabled( this ) )
104 {
105 g *= 0.75;
106 }
107 else
108 {
109 if ( this->scc_accessed )
110 g *= 1.2;
111 }
112
113 if ( sms_psg_enabled( this ) ) Sms_apu_volume( &this->sms.psg, g );
114 if ( sms_fm_enabled( this ) ) Opl_volume( &this->sms.fm, g );
115 if ( msx_psg_enabled( this ) ) Ay_apu_volume( &this->msx.psg, g );
116 if ( msx_scc_enabled( this ) ) Scc_volume( &this->msx.scc, g );
117 if ( msx_music_enabled( this ) ) Opl_volume( &this->msx.music, g );
118 if ( msx_audio_enabled( this ) ) Opl_volume( &this->msx.audio, g );
119}
120
121blargg_err_t Kss_load_mem( struct Kss_Emu* this, const void* data, long size )
122{
123 /* warning( core.warning() ); */
124 memset( &this->header, 0, sizeof this->header );
125 assert( offsetof (header_t,msx_audio_vol) == header_size - 1 );
126 RETURN_ERR( Rom_load( &this->rom, data, size, header_base_size, &this->header, 0 ) );
127
128 RETURN_ERR( check_kss_header( this->header.tag ) );
129
130 this->chip_flags = 0;
131 this->header.last_track [0] = 255;
132 if ( this->header.tag [3] == 'C' )
133 {
134 if ( this->header.extra_header )
135 {
136 this->header.extra_header = 0;
137 /* warning( "Unknown data in header" ); */
138 }
139 if ( this->header.device_flags & ~0x0F )
140 {
141 this->header.device_flags &= 0x0F;
142 /* warning( "Unknown data in header" ); */
143 }
144 }
145 else if ( this->header.extra_header )
146 {
147 if ( this->header.extra_header != header_ext_size )
148 {
149 this->header.extra_header = 0;
150 /* warning( "Invalid extra_header_size" ); */
151 }
152 else
153 {
154 memcpy( this->header.data_size, this->rom.file_data, header_ext_size );
155 }
156 }
157
158 #ifndef NDEBUG
159 {
160 int ram_mode = this->header.device_flags & 0x84; // MSX
161 if ( this->header.device_flags & 0x02 ) // SMS
162 ram_mode = (this->header.device_flags & 0x88);
163
164 if ( ram_mode )
165 blargg_dprintf_( "RAM not supported\n" ); // TODO: support
166 }
167 #endif
168
169 this->track_count = get_le16( this->header.last_track ) + 1;
170 this->m3u.size = 0;
171
172 this->scc_enabled = false;
173 if ( this->header.device_flags & 0x02 ) // Sega Master System
174 {
175 int const osc_count = sms_osc_count + opl_osc_count;
176
177 // sms.psg
178 this->voice_count = sms_osc_count;
179 this->chip_flags |= sms_psg_flag;
180
181 // sms.fm
182 if ( this->header.device_flags & 0x01 )
183 {
184 this->voice_count = osc_count;
185 this->chip_flags |= sms_fm_flag;
186 }
187 }
188 else // MSX
189 {
190 int const osc_count = ay_osc_count + opl_osc_count;
191
192 // msx.psg
193 this->voice_count = ay_osc_count;
194 this->chip_flags |= msx_psg_flag;
195
196 /* if ( this->header.device_flags & 0x10 )
197 warning( "MSX stereo not supported" ); */
198
199 // msx.music
200 if ( this->header.device_flags & 0x01 )
201 {
202 this->voice_count = osc_count;
203 this->chip_flags |= msx_music_flag;
204 }
205
206 #ifndef KSS_EMU_NO_FMOPL
207 // msx.audio
208 if ( this->header.device_flags & 0x08 )
209 {
210 this->voice_count = osc_count;
211 this->chip_flags |= msx_audio_flag;
212 }
213 #endif
214
215 if ( !(this->header.device_flags & 0x80) )
216 {
217 if ( !(this->header.device_flags & 0x84) )
218 this->scc_enabled = scc_enabled_true;
219
220 // msx.scc
221 this->chip_flags |= msx_scc_flag;
222 this->voice_count = ay_osc_count + scc_osc_count;
223 }
224 }
225
226 this->silence_lookahead = 6;
227 if ( sms_fm_enabled( this ) || msx_music_enabled( this ) || msx_audio_enabled( this ) )
228 {
229 if ( !Opl_supported() )
230 ; /* warning( "FM sound not supported" ); */
231 else
232 this->silence_lookahead = 3; // Opl_Apu is really slow
233 }
234
235 this->clock_rate_ = clock_rate;
236 Buffer_clock_rate( &this->stereo_buffer, clock_rate );
237 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buffer );
238
239 Sound_set_tempo( this, this->tempo );
240 Sound_mute_voices( this, this->mute_mask_ );
241 return 0;
242}
243
244void set_voice( struct Kss_Emu* this, int i, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right )
245{
246 if ( sms_psg_enabled( this ) ) // Sega Master System
247 {
248 i -= sms_osc_count;
249 if ( i < 0 )
250 {
251 Sms_apu_set_output( &this->sms.psg, i + sms_osc_count, center, left, right );
252 return;
253 }
254
255 if ( sms_fm_enabled( this ) && i < opl_osc_count )
256 Opl_set_output( &this->sms.fm, center );
257 }
258 else if ( msx_psg_enabled( this ) ) // MSX
259 {
260 i -= ay_osc_count;
261 if ( i < 0 )
262 {
263 Ay_apu_set_output( &this->msx.psg, i + ay_osc_count, center );
264 return;
265 }
266
267 if ( msx_scc_enabled( this ) && i < scc_osc_count ) Scc_set_output( &this->msx.scc, i, center );
268 if ( msx_music_enabled( this ) && i < opl_osc_count ) Opl_set_output( &this->msx.music, center );
269 if ( msx_audio_enabled( this ) && i < opl_osc_count ) Opl_set_output( &this->msx.audio, center );
270 }
271}
272
273// Emulation
274
275void jsr( struct Kss_Emu* this, byte const addr [] )
276{
277 this->ram [--this->cpu.r.sp] = idle_addr >> 8;
278 this->ram [--this->cpu.r.sp] = idle_addr & 0xFF;
279 this->cpu.r.pc = get_le16( addr );
280}
281
282void set_bank( struct Kss_Emu* this, int logical, int physical )
283{
284 int const bank_size = (16 * 1024L) >> (this->header.bank_mode >> 7 & 1);
285
286 int addr = 0x8000;
287 if ( logical && bank_size == 8 * 1024 )
288 addr = 0xA000;
289
290 physical -= this->header.first_bank;
291 if ( (unsigned) physical >= (unsigned) this->bank_count )
292 {
293 byte* data = this->ram + addr;
294 Z80_map_mem( &this->cpu, addr, bank_size, data, data );
295 }
296 else
297 {
298 int offset, phys = physical * bank_size;
299 for ( offset = 0; offset < bank_size; offset += page_size )
300 Z80_map_mem( &this->cpu, addr + offset, page_size,
301 this->unmapped_write, Rom_at_addr( &this->rom, phys + offset ) );
302
303 }
304}
305
306void cpu_write( struct Kss_Emu* this, addr_t addr, int data )
307{
308 *Z80_write( &this->cpu, addr ) = data;
309 if ( (addr & this->scc_enabled) == 0x8000 ) {
310 // TODO: SCC+ support
311
312 data &= 0xFF;
313 switch ( addr )
314 {
315 case 0x9000:
316 set_bank( this, 0, data );
317 return;
318
319 case 0xB000:
320 set_bank( this, 1, data );
321 return;
322
323 case 0xBFFE: // selects between mapping areas (we just always enable both)
324 if ( data == 0 || data == 0x20 )
325 return;
326 }
327
328 int scc_addr = (addr & 0xDFFF) - 0x9800;
329 if ( msx_scc_enabled( this ) && (unsigned) scc_addr < 0xB0 )
330 {
331 this->scc_accessed = true;
332 //if ( (unsigned) (scc_addr - 0x90) < 0x10 )
333 // scc_addr -= 0x10; // 0x90-0x9F mirrors to 0x80-0x8F
334 if ( scc_addr < scc_reg_count )
335 Scc_write( &this->msx.scc, Z80_time( &this->cpu ), addr, data );
336 return;
337 }
338 }
339}
340
341void cpu_out( struct Kss_Emu* this, kss_time_t time, kss_addr_t addr, int data )
342{
343 data &= 0xFF;
344 switch ( addr & 0xFF )
345 {
346 case 0xA0:
347 if ( msx_psg_enabled( this ) )
348 Ay_apu_write_addr( &this->msx.psg, data );
349 return;
350
351 case 0xA1:
352 if ( msx_psg_enabled( this ) )
353 Ay_apu_write_data( &this->msx.psg, time, data );
354 return;
355
356 case 0x06:
357 if ( sms_psg_enabled( this ) && (this->header.device_flags & 0x04) )
358 {
359 Sms_apu_write_ggstereo( &this->sms.psg, time, data );
360 return;
361 }
362 break;
363
364 case 0x7E:
365 case 0x7F:
366 if ( sms_psg_enabled( this ) )
367 {
368 Sms_apu_write_data( &this->sms.psg, time, data );
369 return;
370 }
371 break;
372
373 #define OPL_WRITE_HANDLER( base, name, opl )\
374 case base : if ( name##_enabled( this ) ) { Opl_write_addr( opl, data ); return; } break;\
375 case base+1: if ( name##_enabled( this ) ) { Opl_write_data( opl, time, data ); return; } break;
376
377 OPL_WRITE_HANDLER( 0x7C, msx_music, &this->msx.music )
378 OPL_WRITE_HANDLER( 0xC0, msx_audio, &this->msx.audio )
379 OPL_WRITE_HANDLER( 0xF0, sms_fm, &this->sms.fm )
380
381 case 0xFE:
382 set_bank( this, 0, data );
383 return;
384
385 #ifndef NDEBUG
386 case 0xA8: // PPI
387 return;
388 #endif
389 }
390
391 /* cpu_out( time, addr, data ); */
392}
393
394int cpu_in( struct Kss_Emu* this, kss_time_t time, kss_addr_t addr )
395{
396 switch ( addr & 0xFF )
397 {
398 case 0xC0:
399 case 0xC1:
400 if ( msx_audio_enabled( this ) )
401 return Opl_read( &this->msx.audio, time, addr & 1 );
402 break;
403
404 case 0xA2:
405 if ( msx_psg_enabled( this ) )
406 return Ay_apu_read( &this->msx.psg );
407 break;
408
409 #ifndef NDEBUG
410 case 0xA8: // PPI
411 return 0;
412 #endif
413 }
414
415 /* return cpu_in( time, addr ); */
416 return 0xFF;
417}
418
419blargg_err_t run_clocks( struct Kss_Emu* this, blip_time_t* duration_ )
420{
421 blip_time_t duration = *duration_;
422 RETURN_ERR( end_frame( this, duration ) );
423
424 if ( sms_psg_enabled( this ) ) Sms_apu_end_frame( &this->sms.psg, duration );
425 if ( sms_fm_enabled( this ) ) Opl_end_frame( &this->sms.fm, duration );
426 if ( msx_psg_enabled( this ) ) Ay_apu_end_frame( &this->msx.psg, duration );
427 if ( msx_scc_enabled( this ) ) Scc_end_frame( &this->msx.scc, duration );
428 if ( msx_music_enabled( this ) ) Opl_end_frame( &this->msx.music, duration );
429 if ( msx_audio_enabled( this ) ) Opl_end_frame( &this->msx.audio, duration );
430
431 return 0;
432}
433
434blargg_err_t end_frame( struct Kss_Emu* this, kss_time_t end )
435{
436 while ( Z80_time( &this->cpu ) < end )
437 {
438 kss_time_t next = min( end, this->next_play );
439 run_cpu( this, next );
440 if ( this->cpu.r.pc == idle_addr )
441 Z80_set_time( &this->cpu, next );
442
443 if ( Z80_time( &this->cpu ) >= this->next_play )
444 {
445 this->next_play += this->play_period;
446 if ( this->cpu.r.pc == idle_addr )
447 {
448 if ( !this->gain_updated )
449 {
450 this->gain_updated = true;
451 update_gain( this );
452 }
453
454 jsr( this, this->header.play_addr );
455 }
456 }
457 }
458
459 this->next_play -= end;
460 check( this->next_play >= 0 );
461 Z80_adjust_time( &this->cpu, -end );
462
463 return 0;
464}
465
466// MUSIC
467
468
469blargg_err_t Kss_set_sample_rate( struct Kss_Emu* this, long rate )
470{
471 require( !this->sample_rate ); // sample rate can't be changed once set
472 RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buffer, rate, 1000 / 20 ) );
473
474 // Set bass frequency
475 Buffer_bass_freq( &this->stereo_buffer, 180 );
476 this->sample_rate = rate;
477 return 0;
478}
479
480void Sound_mute_voice( struct Kss_Emu* this, int index, bool mute )
481{
482 require( (unsigned) index < (unsigned) this->voice_count );
483 int bit = 1 << index;
484 int mask = this->mute_mask_ | bit;
485 if ( !mute )
486 mask ^= bit;
487 Sound_mute_voices( this, mask );
488}
489
490void Sound_mute_voices( struct Kss_Emu* this, int mask )
491{
492 require( this->sample_rate ); // sample rate must be set first
493 this->mute_mask_ = mask;
494
495 int i;
496 for ( i = this->voice_count; i--; )
497 {
498 if ( mask & (1 << i) )
499 {
500 set_voice( this, i, 0, 0, 0 );
501 }
502 else
503 {
504 struct channel_t ch = Buffer_channel( &this->stereo_buffer );
505 assert( (ch.center && ch.left && ch.right) ||
506 (!ch.center && !ch.left && !ch.right) ); // all or nothing
507 set_voice( this, i, ch.center, ch.left, ch.right );
508 }
509 }
510}
511
512void Sound_set_tempo( struct Kss_Emu* this, double t )
513{
514 require( this->sample_rate ); // sample rate must be set first
515 double const min = 0.02;
516 double const max = 4.00;
517 if ( t < min ) t = min;
518 if ( t > max ) t = max;
519 this->tempo = t;
520
521 blip_time_t period =
522 (this->header.device_flags & 0x40 ? clock_rate / 50 : clock_rate / 60);
523 this->play_period = (blip_time_t) (period / t);
524}
525
526void fill_buf( struct Kss_Emu* this );
527blargg_err_t Kss_start_track( struct Kss_Emu* this, int track )
528{
529 clear_track_vars( this );
530
531 // Remap track if playlist available
532 if ( this->m3u.size > 0 ) {
533 struct entry_t* e = &this->m3u.entries[track];
534 track = e->track;
535 }
536
537 this->current_track = track;
538
539 Buffer_clear( &this->stereo_buffer );
540
541 if ( sms_psg_enabled( this ) ) Sms_apu_reset( &this->sms.psg, 0, 0 );
542 if ( sms_fm_enabled( this ) ) Opl_reset( &this->sms.fm );
543 if ( msx_psg_enabled( this ) ) Ay_apu_reset( &this->msx.psg );
544 if ( msx_scc_enabled( this ) ) Scc_reset( &this->msx.scc );
545 if ( msx_music_enabled( this ) ) Opl_reset( &this->msx.music );
546 if ( msx_audio_enabled( this ) ) Opl_reset( &this->msx.audio );
547
548 this->scc_accessed = false;
549 update_gain( this );
550
551 memset( this->ram, 0xC9, 0x4000 );
552 memset( this->ram + 0x4000, 0, sizeof this->ram - 0x4000 );
553
554 // copy driver code to lo RAM
555 static byte const bios [] = {
556 0xD3, 0xA0, 0xF5, 0x7B, 0xD3, 0xA1, 0xF1, 0xC9, // $0001: WRTPSG
557 0xD3, 0xA0, 0xDB, 0xA2, 0xC9 // $0009: RDPSG
558 };
559 static byte const vectors [] = {
560 0xC3, 0x01, 0x00, // $0093: WRTPSG vector
561 0xC3, 0x09, 0x00, // $0096: RDPSG vector
562 };
563 memcpy( this->ram + 0x01, bios, sizeof bios );
564 memcpy( this->ram + 0x93, vectors, sizeof vectors );
565
566 // copy non-banked data into RAM
567 int load_addr = get_le16( this->header.load_addr );
568 int orig_load_size = get_le16( this->header.load_size );
569 int load_size = min( orig_load_size, (int) this->rom.file_size );
570 load_size = min( load_size, (int) mem_size - load_addr );
571 /* if ( load_size != orig_load_size )
572 warning( "Excessive data size" ); */
573 memcpy( this->ram + load_addr, this->rom.file_data + this->header.extra_header, load_size );
574
575 Rom_set_addr( &this->rom, -load_size - this->header.extra_header );
576
577 // check available bank data
578 int const bank_size = (16 * 1024L) >> (this->header.bank_mode >> 7 & 1);
579 int max_banks = (this->rom.file_size - load_size + bank_size - 1) / bank_size;
580 this->bank_count = this->header.bank_mode & 0x7F;
581 if ( this->bank_count > max_banks )
582 {
583 this->bank_count = max_banks;
584 /* warning( "Bank data missing" ); */
585 }
586 //dprintf( "load_size : $%X\n", load_size );
587 //dprintf( "bank_size : $%X\n", bank_size );
588 //dprintf( "bank_count: %d (%d claimed)\n", bank_count, this->header.bank_mode & 0x7F );
589
590 this->ram [idle_addr] = 0xFF;
591 Z80_reset( &this->cpu, this->unmapped_write, this->unmapped_read );
592 Z80_map_mem( &this->cpu, 0, mem_size, this->ram, this->ram );
593
594 this->cpu.r.sp = 0xF380;
595 this->cpu.r.b.a = track;
596 this->cpu.r.b.h = 0;
597 this->next_play = this->play_period;
598 this->gain_updated = false;
599 jsr( this, this->header.init_addr );
600
601 this->emu_track_ended_ = false;
602 this->track_ended = false;
603
604 if ( !this->ignore_silence )
605 {
606 // play until non-silence or end of track
607 long end;
608 for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; )
609 {
610 fill_buf( this );
611 if ( this->buf_remain | (int) this->emu_track_ended_ )
612 break;
613 }
614
615 this->emu_time = this->buf_remain;
616 this->out_time = 0;
617 this->silence_time = 0;
618 this->silence_count = 0;
619 }
620 /* return track_ended() ? warning() : 0; */
621 return 0;
622}
623
624// Tell/Seek
625
626blargg_long msec_to_samples( blargg_long msec, long sample_rate )
627{
628 blargg_long sec = msec / 1000;
629 msec -= sec * 1000;
630 return (sec * sample_rate + msec * sample_rate / 1000) * stereo;
631}
632
633long Track_tell( struct Kss_Emu* this )
634{
635 blargg_long rate = this->sample_rate * stereo;
636 blargg_long sec = this->out_time / rate;
637 return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate;
638}
639
640blargg_err_t Track_seek( struct Kss_Emu* this, long msec )
641{
642 blargg_long time = msec_to_samples( msec, this->sample_rate );
643 if ( time < this->out_time )
644 RETURN_ERR( Kss_start_track( this, this->current_track ) );
645 return Track_skip( this, time - this->out_time );
646}
647
648blargg_err_t play_( struct Kss_Emu* this, long count, sample_t* out );
649blargg_err_t skip_( struct Kss_Emu* this, long count )
650{
651 // for long skip, mute sound
652 const long threshold = 30000;
653 if ( count > threshold )
654 {
655 int saved_mute = this->mute_mask_;
656 Sound_mute_voices( this, ~0 );
657
658 while ( count > threshold / 2 && !this->emu_track_ended_ )
659 {
660 RETURN_ERR( play_( this, buf_size, this->buf ) );
661 count -= buf_size;
662 }
663
664 Sound_mute_voices( this, saved_mute );
665 }
666
667 while ( count && !this->emu_track_ended_ )
668 {
669 long n = buf_size;
670 if ( n > count )
671 n = count;
672 count -= n;
673 RETURN_ERR( play_( this, n, this->buf ) );
674 }
675 return 0;
676}
677
678blargg_err_t Track_skip( struct Kss_Emu* this, long count )
679{
680 require( this->current_track >= 0 ); // start_track() must have been called already
681 this->out_time += count;
682
683 // remove from silence and buf first
684 {
685 long n = min( count, this->silence_count );
686 this->silence_count -= n;
687 count -= n;
688
689 n = min( count, this->buf_remain );
690 this->buf_remain -= n;
691 count -= n;
692 }
693
694 if ( count && !this->emu_track_ended_ )
695 {
696 this->emu_time += count;
697 if ( skip_( this, count ) )
698 this->emu_track_ended_ = true;
699 }
700
701 if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended
702 this->track_ended |= this->emu_track_ended_;
703
704 return 0;
705}
706
707// Fading
708
709void Track_set_fade( struct Kss_Emu* this, long start_msec, long length_msec )
710{
711 this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo);
712 this->fade_start = msec_to_samples( start_msec, this->sample_rate );
713}
714
715// unit / pow( 2.0, (double) x / step )
716static int int_log( blargg_long x, int step, int unit )
717{
718 int shift = x / step;
719 int fraction = (x - shift * step) * unit / step;
720 return ((unit - fraction) + (fraction >> 1)) >> shift;
721}
722
723void handle_fade( struct Kss_Emu *this, long out_count, sample_t* out )
724{
725 int i;
726 for ( i = 0; i < out_count; i += fade_block_size )
727 {
728 int const shift = 14;
729 int const unit = 1 << shift;
730 int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size,
731 this->fade_step, unit );
732 if ( gain < (unit >> fade_shift) )
733 this->track_ended = this->emu_track_ended_ = true;
734
735 sample_t* io = &out [i];
736 int count;
737 for ( count = min( fade_block_size, out_count - i ); count; --count )
738 {
739 *io = (sample_t) ((*io * gain) >> shift);
740 ++io;
741 }
742 }
743}
744
745// Silence detection
746
747void emu_play( struct Kss_Emu* this, long count, sample_t* out )
748{
749 check( current_track_ >= 0 );
750 this->emu_time += count;
751 if ( this->current_track >= 0 && !this->emu_track_ended_ ) {
752 if ( play_( this, count, out ) )
753 this->emu_track_ended_ = true;
754 }
755 else
756 memset( out, 0, count * sizeof *out );
757}
758
759// number of consecutive silent samples at end
760static long count_silence( sample_t* begin, long size )
761{
762 sample_t first = *begin;
763 *begin = silence_threshold; // sentinel
764 sample_t* p = begin + size;
765 while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { }
766 *begin = first;
767 return size - (p - begin);
768}
769
770// fill internal buffer and check it for silence
771void fill_buf( struct Kss_Emu* this )
772{
773 assert( !this->buf_remain );
774 if ( !this->emu_track_ended_ )
775 {
776 emu_play( this, buf_size, this->buf );
777 long silence = count_silence( this->buf, buf_size );
778 if ( silence < buf_size )
779 {
780 this->silence_time = this->emu_time - silence;
781 this->buf_remain = buf_size;
782 return;
783 }
784 }
785 this->silence_count += buf_size;
786}
787
788blargg_err_t Kss_play( struct Kss_Emu* this, long out_count, sample_t* out )
789{
790 if ( this->track_ended )
791 {
792 memset( out, 0, out_count * sizeof *out );
793 }
794 else
795 {
796 require( this->current_track >= 0 );
797 require( out_count % stereo == 0 );
798
799 assert( this->emu_time >= this->out_time );
800
801 // prints nifty graph of how far ahead we are when searching for silence
802 //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" );
803
804 long pos = 0;
805 if ( this->silence_count )
806 {
807 // during a run of silence, run emulator at >=2x speed so it gets ahead
808 long ahead_time = this->silence_lookahead * (this->out_time + out_count -this->silence_time) + this->silence_time;
809 while ( this->emu_time < ahead_time && !(this->buf_remain |this-> emu_track_ended_) )
810 fill_buf( this );
811
812 // fill with silence
813 pos = min( this->silence_count, out_count );
814 memset( out, 0, pos * sizeof *out );
815 this->silence_count -= pos;
816
817 if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate )
818 {
819 this->track_ended = this->emu_track_ended_ = true;
820 this->silence_count = 0;
821 this->buf_remain = 0;
822 }
823 }
824
825 if ( this->buf_remain )
826 {
827 // empty silence buf
828 long n = min( this->buf_remain, out_count - pos );
829 memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out );
830 this->buf_remain -= n;
831 pos += n;
832 }
833
834 // generate remaining samples normally
835 long remain = out_count - pos;
836 if ( remain )
837 {
838 emu_play( this, remain, out + pos );
839 this->track_ended |= this->emu_track_ended_;
840
841 if ( !this->ignore_silence || this->out_time > this->fade_start )
842 {
843 // check end for a new run of silence
844 long silence = count_silence( out + pos, remain );
845 if ( silence < remain )
846 this->silence_time = this->emu_time - silence;
847
848 if ( this->emu_time - this->silence_time >= buf_size )
849 fill_buf( this ); // cause silence detection on next play()
850 }
851 }
852
853 if ( this->out_time > this->fade_start )
854 handle_fade( this, out_count, out );
855 }
856 this->out_time += out_count;
857 return 0;
858}
859
860blargg_err_t play_( struct Kss_Emu* this, long count, sample_t* out )
861{
862 long remain = count;
863 while ( remain )
864 {
865 remain -= Buffer_read_samples( &this->stereo_buffer, &out [count - remain], remain );
866 if ( remain )
867 {
868 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buffer ) )
869 {
870 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buffer );
871 Sound_mute_voices( this, this->mute_mask_ );
872 }
873 int msec = Buffer_length( &this->stereo_buffer );
874 /* blip_time_t clocks_emulated = (blargg_long) msec * clock_rate_ / 1000; */
875 blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100;
876 RETURN_ERR( run_clocks( this, &clocks_emulated ) );
877 assert( clocks_emulated );
878 Buffer_end_frame( &this->stereo_buffer, clocks_emulated );
879 }
880 }
881 return 0;
882}
883
diff --git a/apps/codecs/libgme/kss_emu.h b/apps/codecs/libgme/kss_emu.h
new file mode 100644
index 0000000000..81db2ae708
--- /dev/null
+++ b/apps/codecs/libgme/kss_emu.h
@@ -0,0 +1,228 @@
1// MSX computer KSS music file emulator
2
3// Game_Music_Emu 0.5.5
4#ifndef KSS_EMU_H
5#define KSS_EMU_H
6
7#include "gme.h"
8#include "blargg_common.h"
9
10#include "rom_data.h"
11#include "multi_buffer.h"
12
13#include "kss_scc_apu.h"
14#include "z80_cpu.h"
15#include "sms_apu.h"
16#include "ay_apu.h"
17#include "opl_apu.h"
18#include "m3u_playlist.h"
19
20typedef short sample_t;
21typedef int kss_time_t;
22typedef int kss_addr_t;
23typedef struct Z80_Cpu Kss_Cpu;
24
25// Sound chip flags
26enum {
27 sms_psg_flag = 1 << 0,
28 sms_fm_flag = 1 << 1,
29 msx_psg_flag = 1 << 2,
30 msx_scc_flag = 1 << 3,
31 msx_music_flag = 1 << 4,
32 msx_audio_flag = 1 << 5
33};
34
35enum { idle_addr = 0xFFFF };
36enum { scc_enabled_true = 0xC000 };
37enum { mem_size = 0x10000 };
38enum { buf_size = 2048 };
39
40// KSS file header
41enum { header_size = 0x20 };
42enum { header_base_size = 0x10 };
43enum { header_ext_size = header_size - header_base_size };
44
45struct header_t
46{
47 byte tag [4];
48 byte load_addr [2];
49 byte load_size [2];
50 byte init_addr [2];
51 byte play_addr [2];
52 byte first_bank;
53 byte bank_mode;
54 byte extra_header;
55 byte device_flags;
56
57 // KSSX extended data, if extra_header==0x10
58 byte data_size [4];
59 byte unused [4];
60 byte first_track [2];
61 byte last_track [2]; // if no extended data, we set this to 0xFF
62 byte psg_vol;
63 byte scc_vol;
64 byte msx_music_vol;
65 byte msx_audio_vol;
66};
67
68struct sms_t {
69 struct Sms_Apu psg;
70 struct Opl_Apu fm;
71};
72
73struct msx_t {
74 struct Ay_Apu psg;
75 struct Scc_Apu scc;
76 struct Opl_Apu music;
77 struct Opl_Apu audio;
78};
79
80struct Kss_Emu {
81 struct header_t header;
82
83 int chip_flags;
84 bool scc_accessed;
85 bool gain_updated;
86
87 int track_count;
88
89 unsigned scc_enabled; // 0 or 0xC000
90 int bank_count;
91
92 blip_time_t play_period;
93 blip_time_t next_play;
94 int ay_latch;
95
96 // general
97 int max_initial_silence;
98 int voice_count;
99 int mute_mask_;
100 double tempo;
101 double gain;
102
103 long sample_rate;
104
105 // track-specific
106 int current_track;
107 blargg_long out_time; // number of samples played since start of track
108 blargg_long emu_time; // number of samples emulator has generated since start of track
109 bool emu_track_ended_; // emulator has reached end of track
110 volatile bool track_ended;
111
112 // fading
113 blargg_long fade_start;
114 int fade_step;
115
116 // silence detection
117 int silence_lookahead; // speed to run emulator when looking ahead for silence
118 bool ignore_silence;
119 long silence_time; // number of samples where most recent silence began
120 long silence_count; // number of samples of silence to play before using buf
121 long buf_remain; // number of samples left in silence buffer
122
123 struct Stereo_Buffer stereo_buffer; // NULL if using custom buffer
124 long clock_rate_;
125 unsigned buf_changed_count;
126
127 // M3u Playlist
128 struct M3u_Playlist m3u;
129
130 // large items
131 sample_t buf [buf_size];
132
133 struct sms_t sms;
134 struct msx_t msx;
135
136 Kss_Cpu cpu;
137 struct Rom_Data rom;
138
139 byte unmapped_read [0x100];
140 byte unmapped_write [page_size];
141 byte ram [mem_size + cpu_padding];
142};
143
144// Basic functionality (see Gme_File.h for file loading/track info functions)
145
146void Kss_init( struct Kss_Emu* this );
147blargg_err_t Kss_load_mem( struct Kss_Emu* this, const void* data, long size );
148blargg_err_t end_frame( struct Kss_Emu* this, kss_time_t );
149
150// Set output sample rate. Must be called only once before loading file.
151blargg_err_t Kss_set_sample_rate( struct Kss_Emu* this, long sample_rate );
152
153// Start a track, where 0 is the first track. Also clears warning string.
154blargg_err_t Kss_start_track( struct Kss_Emu* this, int track );
155
156// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation
157// errors set warning string, and major errors also end track.
158blargg_err_t Kss_play( struct Kss_Emu* this, long count, sample_t* buf ) ICODE_ATTR;
159
160// Track status/control
161
162// Number of milliseconds (1000 msec = 1 second) played since beginning of track
163long Track_tell( struct Kss_Emu* this );
164
165// Seek to new time in track. Seeking backwards or far forward can take a while.
166blargg_err_t Track_seek( struct Kss_Emu* this, long msec );
167
168// Skip n samples
169blargg_err_t Track_skip( struct Kss_Emu* this, long n );
170
171// Set start time and length of track fade out. Once fade ends track_ended() returns
172// true. Fade time can be changed while track is playing.
173void Track_set_fade( struct Kss_Emu* this, long start_msec, long length_msec );
174
175// Get track length in milliseconds
176static inline long Track_get_length( struct Kss_Emu* this, int n )
177{
178 long length = 0;
179
180 if ( (this->m3u.size > 0) && (n < this->m3u.size) ) {
181 struct entry_t* entry = &this->m3u.entries [n];
182 length = entry->length;
183 }
184
185 if ( length <= 0 )
186 length = 120 * 1000; /* 2 minutes */
187
188 return length;
189}
190
191// Sound customization
192
193// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed.
194// Track length as returned by track_info() assumes a tempo of 1.0.
195void Sound_set_tempo( struct Kss_Emu* this, double t );
196
197// Mute/unmute voice i, where voice 0 is first voice
198void Sound_mute_voice( struct Kss_Emu* this, int index, bool mute );
199
200// Set muting state of all voices at once using a bit mask, where -1 mutes them all,
201// 0 unmutes them all, 0x01 mutes just the first voice, etc.
202void Sound_mute_voices( struct Kss_Emu* this, int mask );
203
204// Change overall output amplitude, where 1.0 results in minimal clamping.
205// Must be called before set_sample_rate().
206static inline void Sound_set_gain( struct Kss_Emu* this, double g )
207{
208 assert( !this->sample_rate ); // you must set gain before setting sample rate
209 this->gain = g;
210}
211
212// Emulation (You shouldn't touch these
213void cpu_write( struct Kss_Emu* this, kss_addr_t, int ) ICODE_ATTR;
214int cpu_in( struct Kss_Emu* this, kss_time_t, kss_addr_t ) ICODE_ATTR;
215void cpu_out( struct Kss_Emu* this, kss_time_t, kss_addr_t, int ) ICODE_ATTR;
216
217void cpu_write_( struct Kss_Emu* this, kss_addr_t addr, int data ) ICODE_ATTR;
218bool run_cpu( struct Kss_Emu* this, kss_time_t end ) ICODE_ATTR;
219void jsr( struct Kss_Emu* this, byte const addr [] ) ICODE_ATTR;
220
221static inline int sms_psg_enabled( struct Kss_Emu* this ) { return this->chip_flags & sms_psg_flag; }
222static inline int sms_fm_enabled( struct Kss_Emu* this ) { return this->chip_flags & sms_fm_flag; }
223static inline int msx_psg_enabled( struct Kss_Emu* this ) { return this->chip_flags & msx_psg_flag; }
224static inline int msx_scc_enabled( struct Kss_Emu* this ) { return this->chip_flags & msx_scc_flag; }
225static inline int msx_music_enabled( struct Kss_Emu* this ) { return this->chip_flags & msx_music_flag;}
226static inline int msx_audio_enabled( struct Kss_Emu* this ) { return this->chip_flags & msx_audio_flag;}
227
228#endif
diff --git a/apps/codecs/libgme/kss_scc_apu.c b/apps/codecs/libgme/kss_scc_apu.c
new file mode 100644
index 0000000000..0e71b1ce3b
--- /dev/null
+++ b/apps/codecs/libgme/kss_scc_apu.c
@@ -0,0 +1,166 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "kss_scc_apu.h"
4
5/* Copyright (C) 2006-2008 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18// Tones above this frequency are treated as disabled tone at half volume.
19// Power of two is more efficient (avoids division).
20extern int const inaudible_freq;
21
22int const wave_size = 0x20;
23
24static void set_output( struct Scc_Apu* this, struct Blip_Buffer* buf )
25{
26 int i;
27 for ( i = 0; i < scc_osc_count; ++i )
28 Scc_set_output( this, i, buf );
29}
30
31void Scc_volume( struct Scc_Apu* this, double v )
32{
33 Synth_volume( &this->synth, 0.43 / scc_osc_count / scc_amp_range * v );
34}
35
36void Scc_reset( struct Scc_Apu* this )
37{
38 this->last_time = 0;
39
40 int i;
41 for ( i = scc_osc_count; --i >= 0; )
42 memset( &this->oscs [i], 0, offsetof (struct scc_osc_t,output) );
43
44 memset( this->regs, 0, sizeof this->regs );
45}
46
47void Scc_init( struct Scc_Apu* this )
48{
49 Synth_init( &this->synth);
50
51 set_output( this, NULL );
52 Scc_volume( this, 1.0 );
53 Scc_reset( this );
54}
55
56static void run_until( struct Scc_Apu* this, blip_time_t end_time )
57{
58 int index;
59 for ( index = 0; index < scc_osc_count; index++ )
60 {
61 struct scc_osc_t* osc = &this->oscs [index];
62
63 struct Blip_Buffer* const output = osc->output;
64 if ( !output )
65 continue;
66
67 blip_time_t period = (this->regs [0xA0 + index * 2 + 1] & 0x0F) * 0x100 +
68 this->regs [0xA0 + index * 2] + 1;
69 int volume = 0;
70 if ( this->regs [0xAF] & (1 << index) )
71 {
72 blip_time_t inaudible_period = (unsigned) (Blip_clock_rate( output ) +
73 inaudible_freq * 32) / (unsigned) (inaudible_freq * 16);
74 if ( period > inaudible_period )
75 volume = (this->regs [0xAA + index] & 0x0F) * (scc_amp_range / 256 / 15);
76 }
77
78 int8_t const* wave = (int8_t*) this->regs + index * wave_size;
79 /*if ( index == osc_count - 1 )
80 wave -= wave_size; // last two oscs share same wave RAM*/
81
82 {
83 int delta = wave [osc->phase] * volume - osc->last_amp;
84 if ( delta )
85 {
86 osc->last_amp += delta;
87 Blip_set_modified( output );
88 Synth_offset( &this->synth, this->last_time, delta, output );
89 }
90 }
91
92 blip_time_t time = this->last_time + osc->delay;
93 if ( time < end_time )
94 {
95 int phase = osc->phase;
96 if ( !volume )
97 {
98 // maintain phase
99 int count = (end_time - time + period - 1) / period;
100 phase += count; // will be masked below
101 time += count * period;
102 }
103 else
104 {
105 int last_wave = wave [phase];
106 phase = (phase + 1) & (wave_size - 1); // pre-advance for optimal inner loop
107 do
108 {
109 int delta = wave [phase] - last_wave;
110 phase = (phase + 1) & (wave_size - 1);
111 if ( delta )
112 {
113 last_wave += delta;
114 Synth_offset_inline( &this->synth, time, delta * volume, output );
115 }
116 time += period;
117 }
118 while ( time < end_time );
119
120 osc->last_amp = last_wave * volume;
121 Blip_set_modified( output );
122 phase--; // undo pre-advance
123 }
124 osc->phase = phase & (wave_size - 1);
125 }
126 osc->delay = time - end_time;
127 }
128 this->last_time = end_time;
129}
130
131void Scc_write( struct Scc_Apu* this, blip_time_t time, int addr, int data )
132{
133 //assert( (unsigned) addr < reg_count );
134 assert( ( addr >= 0x9800 && addr <= 0x988F ) || ( addr >= 0xB800 && addr <= 0xB8AF ) );
135 run_until( this, time );
136
137 addr -= 0x9800;
138 if ( ( unsigned ) addr < 0x90 )
139 {
140 if ( ( unsigned ) addr < 0x60 )
141 this->regs [addr] = data;
142 else if ( ( unsigned ) addr < 0x80 )
143 {
144 this->regs [addr] = this->regs[addr + 0x20] = data;
145 }
146 else if ( ( unsigned ) addr < 0x90 )
147 {
148 this->regs [addr + 0x20] = data;
149 }
150 }
151 else
152 {
153 addr -= 0xB800 - 0x9800;
154 if ( ( unsigned ) addr < 0xB0 )
155 this->regs [addr] = data;
156 }
157}
158
159void Scc_end_frame( struct Scc_Apu* this, blip_time_t end_time )
160{
161 if ( end_time > this->last_time )
162 run_until( this, end_time );
163
164 this->last_time -= end_time;
165 assert( this->last_time >= 0 );
166}
diff --git a/apps/codecs/libgme/kss_scc_apu.h b/apps/codecs/libgme/kss_scc_apu.h
new file mode 100644
index 0000000000..f31228a39d
--- /dev/null
+++ b/apps/codecs/libgme/kss_scc_apu.h
@@ -0,0 +1,51 @@
1// Konami SCC sound chip emulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef KSS_SCC_APU_H
5#define KSS_SCC_APU_H
6
7#include "blargg_common.h"
8#include "blip_buffer.h"
9
10enum { scc_reg_count = 0xB0 }; // 0 <= reg < reg_count
11enum { scc_osc_count = 5 };
12enum { scc_amp_range = 0x8000 };
13
14struct scc_osc_t
15{
16 int delay;
17 int phase;
18 int last_amp;
19 struct Blip_Buffer* output;
20};
21
22struct Scc_Apu {
23 struct scc_osc_t oscs [scc_osc_count];
24 blip_time_t last_time;
25 unsigned char regs [scc_reg_count];
26
27 struct Blip_Synth synth;
28};
29
30void Scc_init( struct Scc_Apu* this );
31
32// Resets sound chip
33void Scc_reset( struct Scc_Apu* this );
34
35// Set overall volume, where 1.0 is normal
36void Scc_volume( struct Scc_Apu* this, double v );
37
38static inline void Scc_set_output( struct Scc_Apu* this, int index, struct Blip_Buffer* b )
39{
40 assert( (unsigned) index < scc_osc_count );
41 this->oscs [index].output = b;
42}
43
44// Emulates to time t, then writes data to reg
45void Scc_write( struct Scc_Apu* this, blip_time_t time, int addr, int data ) ICODE_ATTR;
46
47// Emulates to time t, then subtracts t from the current time.
48// OK if previous write call had time slightly after t.
49void Scc_end_frame( struct Scc_Apu* this, blip_time_t end_time ) ICODE_ATTR;
50
51#endif
diff --git a/apps/codecs/libgme/libay.make b/apps/codecs/libgme/libay.make
new file mode 100644
index 0000000000..5eee8ac1e4
--- /dev/null
+++ b/apps/codecs/libgme/libay.make
@@ -0,0 +1,21 @@
1
2# libay
3AYLIB := $(CODECDIR)/libay.a
4AYLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/AYSOURCES)
5AYLIB_OBJ := $(call c2obj, $(AYLIB_SRC))
6OTHER_SRC += $(AYLIB_SRC)
7
8$(AYLIB): $(AYLIB_OBJ)
9 $(SILENT)$(shell rm -f $@)
10 $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
11
12AYFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_AY_TYPE
13ifeq ($(CPU),arm)
14 AYFLAGS += -O3
15else
16 AYFLAGS += -O2
17endif
18
19$(CODECDIR)/libgme/%.o: $(ROOTDIR)/apps/codecs/libgme/%.c
20 $(SILENT)mkdir -p $(dir $@)
21 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(AYFLAGS) -c $< -o $@
diff --git a/apps/codecs/libgme/libgbs.make b/apps/codecs/libgme/libgbs.make
new file mode 100644
index 0000000000..cf6ff01274
--- /dev/null
+++ b/apps/codecs/libgme/libgbs.make
@@ -0,0 +1,21 @@
1
2# libgbs
3GBSLIB := $(CODECDIR)/libgbs.a
4GBSLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/GBSSOURCES)
5GBSLIB_OBJ := $(call c2obj, $(GBSLIB_SRC))
6OTHER_SRC += $(GBSLIB_SRC)
7
8$(GBSLIB): $(GBSLIB_OBJ)
9 $(SILENT)$(shell rm -f $@)
10 $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
11
12GBSFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_GBS_TYPE
13ifeq ($(CPU),arm)
14 GBSFLAGS += -O3
15else
16 GBSFLAGS += -O2
17endif
18
19$(CODECDIR)/libgme/%.o: $(ROOTDIR)/apps/codecs/libgme/%.c
20 $(SILENT)mkdir -p $(dir $@)
21 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(GBSFLAGS) -c $< -o $@
diff --git a/apps/codecs/libgme/libhes.make b/apps/codecs/libgme/libhes.make
new file mode 100644
index 0000000000..e0018565fb
--- /dev/null
+++ b/apps/codecs/libgme/libhes.make
@@ -0,0 +1,21 @@
1
2# libhes
3HESLIB := $(CODECDIR)/libhes.a
4HESLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/HESSOURCES)
5HESLIB_OBJ := $(call c2obj, $(HESLIB_SRC))
6OTHER_SRC += $(HESLIB_SRC)
7
8$(HESLIB): $(HESLIB_OBJ)
9 $(SILENT)$(shell rm -f $@)
10 $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
11
12HESFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_HES_TYPE
13ifeq ($(CPU),arm)
14 HESFLAGS += -O3
15else
16 HESFLAGS += -O2
17endif
18
19$(CODECDIR)/libgme/%.o: $(ROOTDIR)/apps/codecs/libgme/%.c
20 $(SILENT)mkdir -p $(dir $@)
21 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(HESFLAGS) -c $< -o $@
diff --git a/apps/codecs/libgme/libkss.make b/apps/codecs/libgme/libkss.make
new file mode 100644
index 0000000000..0e2dd54bc2
--- /dev/null
+++ b/apps/codecs/libgme/libkss.make
@@ -0,0 +1,21 @@
1
2# libkss
3KSSLIB := $(CODECDIR)/libkss.a
4KSSLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/KSSSOURCES)
5KSSLIB_OBJ := $(call c2obj, $(KSSLIB_SRC))
6OTHER_SRC += $(KSSLIB_SRC)
7
8$(KSSLIB): $(KSSLIB_OBJ)
9 $(SILENT)$(shell rm -f $@)
10 $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
11
12KSSFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_KSS_TYPE
13ifeq ($(CPU),arm)
14 KSSFLAGS += -O3
15else
16 KSSFLAGS += -O2
17endif
18
19$(CODECDIR)/libgme/%.o: $(ROOTDIR)/apps/codecs/libgme/%.c
20 $(SILENT)mkdir -p $(dir $@)
21 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(KSSFLAGS) -c $< -o $@
diff --git a/apps/codecs/libgme/libnsf.make b/apps/codecs/libgme/libnsf.make
new file mode 100644
index 0000000000..8b9df7526f
--- /dev/null
+++ b/apps/codecs/libgme/libnsf.make
@@ -0,0 +1,21 @@
1
2# libnsf
3NSFLIB := $(CODECDIR)/libnsf.a
4NSFLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/NSFSOURCES)
5NSFLIB_OBJ := $(call c2obj, $(NSFLIB_SRC))
6OTHER_SRC += $(NSFLIB_SRC)
7
8$(NSFLIB): $(NSFLIB_OBJ)
9 $(SILENT)$(shell rm -f $@)
10 $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
11
12NSFFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_NSF_TYPE
13ifeq ($(CPU),arm)
14 NSFFLAGS += -O3
15else
16 NSFFLAGS += -O2
17endif
18
19$(CODECDIR)/libgme/%.o: $(ROOTDIR)/apps/codecs/libgme/%.c
20 $(SILENT)mkdir -p $(dir $@)
21 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(NSFFLAGS) -c $< -o $@
diff --git a/apps/codecs/libgme/libsgc.make b/apps/codecs/libgme/libsgc.make
new file mode 100644
index 0000000000..0defe788c6
--- /dev/null
+++ b/apps/codecs/libgme/libsgc.make
@@ -0,0 +1,21 @@
1
2# libsgc
3SGCLIB := $(CODECDIR)/libsgc.a
4SGCLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/SGCSOURCES)
5SGCLIB_OBJ := $(call c2obj, $(SGCLIB_SRC))
6OTHER_SRC += $(SGCLIB_SRC)
7
8$(SGCLIB): $(SGCLIB_OBJ)
9 $(SILENT)$(shell rm -f $@)
10 $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
11
12SGCFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_SGC_TYPE
13ifeq ($(CPU),arm)
14 SGCFLAGS += -O3
15else
16 SGCFLAGS += -O2
17endif
18
19$(CODECDIR)/libgme/%.o: $(ROOTDIR)/apps/codecs/libgme/%.c
20 $(SILENT)mkdir -p $(dir $@)
21 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(SGCFLAGS) -c $< -o $@
diff --git a/apps/codecs/libgme/libvgm.make b/apps/codecs/libgme/libvgm.make
new file mode 100644
index 0000000000..f0e7cbb598
--- /dev/null
+++ b/apps/codecs/libgme/libvgm.make
@@ -0,0 +1,21 @@
1
2# libvgm
3VGMLIB := $(CODECDIR)/libvgm.a
4VGMLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/VGMSOURCES)
5VGMLIB_OBJ := $(call c2obj, $(VGMLIB_SRC))
6OTHER_SRC += $(VGMLIB_SRC)
7
8$(VGMLIB): $(VGMLIB_OBJ)
9 $(SILENT)$(shell rm -f $@)
10 $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
11
12VGMFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_VGM_TYPE
13ifeq ($(CPU),arm)
14 VGMFLAGS += -O3
15else
16 VGMFLAGS += -O2
17endif
18
19$(CODECDIR)/libgme/%.o: $(ROOTDIR)/apps/codecs/libgme/%.c
20 $(SILENT)mkdir -p $(dir $@)
21 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(VGMFLAGS) -c $< -o $@
diff --git a/apps/codecs/libgme/m3u_playlist.h b/apps/codecs/libgme/m3u_playlist.h
new file mode 100644
index 0000000000..06a5d3024b
--- /dev/null
+++ b/apps/codecs/libgme/m3u_playlist.h
@@ -0,0 +1,31 @@
1// M3U entries parser, with support for subtrack information
2
3// Game_Music_Emu 0.5.2
4#ifndef M3U_PLAYLIST_H
5#define M3U_PLAYILST_H
6
7#include "blargg_common.h"
8
9struct entry_t
10{
11 unsigned char track; // 1-based
12 int length; // milliseconds
13};
14
15/* Short version of the m3u playlist */
16struct M3u_Playlist
17{
18 unsigned char size;
19 struct entry_t *entries;
20};
21
22static inline void M3u_load_data(struct M3u_Playlist* this, void *addr)
23{
24 if( addr == NULL ) return;
25 /* m3u entries data must be at offset 100,
26 the first 99 bytes are used by metadata info */
27 this->size = *(unsigned char *)(addr + 99);
28 this->entries = (struct entry_t *)(addr+100);
29}
30
31#endif
diff --git a/apps/codecs/libgme/msxtypes.h b/apps/codecs/libgme/msxtypes.h
new file mode 100644
index 0000000000..6224e0760c
--- /dev/null
+++ b/apps/codecs/libgme/msxtypes.h
@@ -0,0 +1,36 @@
1#ifndef MSX_TYPES
2#define MSX_TYPES
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8
9#ifdef __GNUC__
10#define __int64 long long
11#endif
12
13#ifdef _WIN32
14#define DIR_SEPARATOR "\\"
15#else
16#define DIR_SEPARATOR "/"
17#endif
18
19/* So far, only support for MSVC types
20 */
21typedef unsigned char UInt8;
22#ifndef __CARBON__
23typedef unsigned short UInt16;
24typedef unsigned int UInt32;
25typedef unsigned __int64 UInt64;
26#endif
27typedef signed char Int8;
28typedef signed short Int16;
29typedef signed int Int32;
30
31#ifdef __cplusplus
32}
33#endif
34
35
36#endif
diff --git a/apps/codecs/libgme/multi_buffer.c b/apps/codecs/libgme/multi_buffer.c
new file mode 100644
index 0000000000..26cb8cdec6
--- /dev/null
+++ b/apps/codecs/libgme/multi_buffer.c
@@ -0,0 +1,226 @@
1// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
2
3#include "multi_buffer.h"
4
5/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18#ifdef BLARGG_ENABLE_OPTIMIZER
19 #include BLARGG_ENABLE_OPTIMIZER
20#endif
21
22// Stereo_Buffer
23
24void Buffer_init( struct Stereo_Buffer* this )
25{
26 Blip_init( &this->bufs [0] );
27 Blip_init( &this->bufs [1] );
28 Blip_init( &this->bufs [2] );
29
30 this->chan.center = &this->bufs [0];
31 this->chan.left = &this->bufs [1];
32 this->chan.right = &this->bufs [2];
33
34 this->length_ = 0;
35 this->sample_rate_ = 0;
36 this->channels_changed_count_ = 1;
37 this->samples_per_frame_ = 2;
38}
39
40blargg_err_t Buffer_set_sample_rate( struct Stereo_Buffer* this, long rate, int msec )
41{
42 int i;
43 for ( i = 0; i < buf_count; i++ )
44 RETURN_ERR( Blip_set_sample_rate( &this->bufs[i], rate, msec ) );
45
46 this->sample_rate_ = Blip_sample_rate( &this->bufs [0] );
47 this->length_ = Blip_length( &this->bufs [0] );
48 return 0;
49}
50
51void Buffer_clock_rate( struct Stereo_Buffer* this, long rate )
52{
53 int i;
54 for ( i = 0; i < buf_count; i++ )
55 Blip_set_clock_rate( &this->bufs [i], rate );
56}
57
58void Buffer_bass_freq( struct Stereo_Buffer* this, int bass )
59{
60 unsigned i;
61 for ( i = 0; i < buf_count; i++ )
62 Blip_bass_freq( &this->bufs [i], bass );
63}
64
65struct channel_t Buffer_channel( struct Stereo_Buffer* this )
66{
67 return this->chan;
68}
69
70void Buffer_clear( struct Stereo_Buffer* this )
71{
72 this->stereo_added = 0;
73 this->was_stereo = false;
74 int i;
75 for ( i = 0; i < buf_count; i++ )
76 Blip_clear( &this->bufs [i], 1 );
77}
78
79void Buffer_end_frame( struct Stereo_Buffer* this, blip_time_t clock_count )
80{
81 this->stereo_added = 0;
82 unsigned i;
83 for ( i = 0; i < buf_count; i++ )
84 {
85 this->stereo_added |= Blip_clear_modified( &this->bufs [i] ) << i;
86 Blip_end_frame( &this->bufs [i], clock_count );
87 }
88}
89
90long Buffer_read_samples( struct Stereo_Buffer* this, blip_sample_t* out, long count )
91{
92 require( !(count & 1) ); // count must be even
93 count = (unsigned) count / 2;
94
95 long avail = Blip_samples_avail( &this->bufs [0] );
96 if ( count > avail )
97 count = avail;
98 if ( count )
99 {
100 int bufs_used = this->stereo_added | this->was_stereo;
101 //dprintf( "%X\n", bufs_used );
102 if ( bufs_used <= 1 )
103 {
104 Buffer_mix_mono( this, out, count );
105 Blip_remove_samples( &this->bufs [0], count );
106 Blip_remove_silence( &this->bufs [1], count );
107 Blip_remove_silence( &this->bufs [2], count );
108 }
109 else if ( bufs_used & 1 )
110 {
111 Buffer_mix_stereo( this, out, count );
112 Blip_remove_samples( &this->bufs [0], count );
113 Blip_remove_samples( &this->bufs [1], count );
114 Blip_remove_samples( &this->bufs [2], count );
115 }
116 else
117 {
118 Buffer_mix_stereo_no_center( this, out, count );
119 Blip_remove_silence( &this->bufs [0], count );
120 Blip_remove_samples( &this->bufs [1], count );
121 Blip_remove_samples( &this->bufs [2], count );
122 }
123
124 // to do: this might miss opportunities for optimization
125 if ( !Blip_samples_avail( &this->bufs [0] ) )
126 {
127 this->was_stereo = this->stereo_added;
128 this->stereo_added = 0;
129 }
130 }
131
132 return count * 2;
133}
134
135unsigned Buffer_channels_changed_count( struct Stereo_Buffer* this )
136{
137 return this->channels_changed_count_;
138}
139
140void Buffer_channels_changed( struct Stereo_Buffer* this )
141{
142 this->channels_changed_count_++;
143}
144
145void Buffer_mix_stereo( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count )
146{
147 blip_sample_t* BLIP_RESTRICT out = out_;
148 int const bass = BLIP_READER_BASS( this->bufs [1] );
149 BLIP_READER_BEGIN( left, this->bufs [1] );
150 BLIP_READER_BEGIN( right, this->bufs [2] );
151 BLIP_READER_BEGIN( center, this->bufs [0] );
152
153 for ( ; count; --count )
154 {
155 int c = BLIP_READER_READ( center );
156 blargg_long l = c + BLIP_READER_READ( left );
157 blargg_long r = c + BLIP_READER_READ( right );
158 if ( (int16_t) l != l )
159 l = 0x7FFF - (l >> 24);
160
161 BLIP_READER_NEXT( center, bass );
162 if ( (int16_t) r != r )
163 r = 0x7FFF - (r >> 24);
164
165 BLIP_READER_NEXT( left, bass );
166 BLIP_READER_NEXT( right, bass );
167
168 out [0] = l;
169 out [1] = r;
170 out += 2;
171 }
172
173 BLIP_READER_END( center, this->bufs [0] );
174 BLIP_READER_END( right, this->bufs [2] );
175 BLIP_READER_END( left, this->bufs [1] );
176}
177
178void Buffer_mix_stereo_no_center( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count )
179{
180 blip_sample_t* BLIP_RESTRICT out = out_;
181 int const bass = BLIP_READER_BASS( this->bufs [1] );
182 BLIP_READER_BEGIN( left, this->bufs [1] );
183 BLIP_READER_BEGIN( right, this->bufs [2] );
184
185 for ( ; count; --count )
186 {
187 blargg_long l = BLIP_READER_READ( left );
188 if ( (int16_t) l != l )
189 l = 0x7FFF - (l >> 24);
190
191 blargg_long r = BLIP_READER_READ( right );
192 if ( (int16_t) r != r )
193 r = 0x7FFF - (r >> 24);
194
195 BLIP_READER_NEXT( left, bass );
196 BLIP_READER_NEXT( right, bass );
197
198 out [0] = l;
199 out [1] = r;
200 out += 2;
201 }
202
203 BLIP_READER_END( right, this->bufs [2] );
204 BLIP_READER_END( left, this->bufs [1] );
205}
206
207void Buffer_mix_mono( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count )
208{
209 blip_sample_t* BLIP_RESTRICT out = out_;
210 int const bass = BLIP_READER_BASS( this->bufs [0] );
211 BLIP_READER_BEGIN( center, this->bufs [0] );
212
213 for ( ; count; --count )
214 {
215 blargg_long s = BLIP_READER_READ( center );
216 if ( (int16_t) s != s )
217 s = 0x7FFF - (s >> 24);
218
219 BLIP_READER_NEXT( center, bass );
220 out [0] = s;
221 out [1] = s;
222 out += 2;
223 }
224
225 BLIP_READER_END( center, this->bufs [0] );
226}
diff --git a/apps/codecs/libgme/multi_buffer.h b/apps/codecs/libgme/multi_buffer.h
new file mode 100644
index 0000000000..26f302380c
--- /dev/null
+++ b/apps/codecs/libgme/multi_buffer.h
@@ -0,0 +1,72 @@
1// Multi-channel sound buffer interface, and basic mono and stereo buffers
2
3// Blip_Buffer 0.4.1
4#ifndef MULTI_BUFFER_H
5#define MULTI_BUFFER_H
6
7#include "blargg_common.h"
8#include "blip_buffer.h"
9
10// Get indexed channel, from 0 to channel count - 1
11struct channel_t {
12 struct Blip_Buffer* center;
13 struct Blip_Buffer* left;
14 struct Blip_Buffer* right;
15};
16
17enum { type_index_mask = 0xFF };
18enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type };
19enum { buf_count = 3 };
20
21struct Stereo_Buffer {
22 struct Blip_Buffer bufs [buf_count];
23 struct channel_t chan;
24 int stereo_added;
25 int was_stereo;
26
27 unsigned channels_changed_count_;
28 long sample_rate_;
29 int length_;
30 int samples_per_frame_;
31};
32
33// Initializes Stereo_Buffer structure
34void Buffer_init( struct Stereo_Buffer* this );
35
36blargg_err_t Buffer_set_sample_rate( struct Stereo_Buffer* this, long, int msec );
37void Buffer_clock_rate( struct Stereo_Buffer* this, long );
38void Buffer_bass_freq( struct Stereo_Buffer* this, int );
39void Buffer_clear( struct Stereo_Buffer* this );
40struct channel_t Buffer_channel( struct Stereo_Buffer* this );
41void Buffer_end_frame( struct Stereo_Buffer* this, blip_time_t ) ICODE_ATTR;
42
43long Buffer_read_samples( struct Stereo_Buffer* this, blip_sample_t*, long ) ICODE_ATTR;
44
45// Count of changes to channel configuration. Incremented whenever
46// a change is made to any of the Blip_Buffers for any channel.
47unsigned Buffer_channels_changed_count( struct Stereo_Buffer* this ) ICODE_ATTR;
48void Buffer_channels_changed( struct Stereo_Buffer* this ) ICODE_ATTR;
49
50void Buffer_mix_stereo_no_center( struct Stereo_Buffer* this, blip_sample_t*, blargg_long ) ICODE_ATTR;
51void Buffer_mix_stereo( struct Stereo_Buffer* this, blip_sample_t*, blargg_long ) ICODE_ATTR;
52void Buffer_mix_mono( struct Stereo_Buffer* this, blip_sample_t*, blargg_long ) ICODE_ATTR;
53
54// Number of samples per output frame (1 = mono, 2 = stereo)
55static inline int Buffer_samples_per_frame( struct Stereo_Buffer* this )
56{
57 return this->samples_per_frame_;
58}
59
60// See Blip_Buffer.h
61static inline long Buffer_sample_rate( struct Stereo_Buffer* this )
62{
63 return this->sample_rate_;
64}
65
66// Length of buffer, in milliseconds
67static inline int Buffer_length( struct Stereo_Buffer* this )
68{
69 return this->length_;
70}
71
72#endif
diff --git a/apps/codecs/libgme/nes_apu.c b/apps/codecs/libgme/nes_apu.c
new file mode 100644
index 0000000000..8f1f37645e
--- /dev/null
+++ b/apps/codecs/libgme/nes_apu.c
@@ -0,0 +1,393 @@
1// Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/
2
3#include "nes_apu.h"
4
5/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18int const amp_range = 15;
19
20void Apu_init( struct Nes_Apu* this )
21{
22 this->tempo_ = 1.0;
23 this->dmc.apu = this;
24 this->dmc.prg_reader = NULL;
25 this->irq_notifier_ = NULL;
26
27 Synth_init( &this->square_synth );
28 Synth_init( &this->triangle.synth );
29 Synth_init( &this->noise.synth );
30 Synth_init( &this->dmc.synth );
31
32 Square_set_synth( &this->square1, &this->square_synth );
33 Square_set_synth( &this->square2, &this->square_synth );
34
35 this->oscs [0] = &this->square1.osc;
36 this->oscs [1] = &this->square2.osc;
37 this->oscs [2] = &this->triangle.osc;
38 this->oscs [3] = &this->noise.osc;
39 this->oscs [4] = &this->dmc.osc;
40
41 Apu_output( this, NULL );
42 Apu_volume( this, 1.0 );
43 Apu_reset( this, false, 0 );
44}
45
46static double nonlinear_tnd_gain( void ) { return 0.75; }
47void Apu_enable_nonlinear( struct Nes_Apu* this, double v )
48{
49 this->dmc.nonlinear = true;
50 Synth_volume( &this->square_synth, 1.3 * 0.25751258 / 0.742467605 * 0.25 / amp_range * v );
51
52 const double tnd = 0.48 / 202 * nonlinear_tnd_gain();
53 Synth_volume( &this->triangle.synth, 3.0 * tnd );
54 Synth_volume( &this->noise.synth, 2.0 * tnd );
55 Synth_volume( &this->dmc.synth, tnd );
56
57 this->square1 .osc.last_amp = 0;
58 this->square2 .osc.last_amp = 0;
59 this->triangle.osc.last_amp = 0;
60 this->noise .osc.last_amp = 0;
61 this->dmc .osc.last_amp = 0;
62}
63
64void Apu_volume( struct Nes_Apu* this, double v )
65{
66 this->dmc.nonlinear = false;
67 Synth_volume( &this->square_synth, 0.1128 / amp_range * v );
68 Synth_volume( &this->triangle.synth,0.12765 / amp_range * v );
69 Synth_volume( &this->noise.synth, 0.0741 / amp_range * v );
70 Synth_volume( &this->dmc.synth, 0.42545 / 127 * v );
71}
72
73void Apu_output( struct Nes_Apu* this, struct Blip_Buffer* buffer )
74{
75 int i;
76 for ( i = 0; i < apu_osc_count; i++ )
77 Apu_osc_output( this, i, buffer );
78}
79
80void Apu_set_tempo( struct Nes_Apu* this, double t )
81{
82 this->tempo_ = t;
83 this->frame_period = (this->dmc.pal_mode ? 8314 : 7458);
84 if ( t != 1.0 )
85 this->frame_period = (int) (this->frame_period / t) & ~1; // must be even
86}
87
88void Apu_reset( struct Nes_Apu* this, bool pal_mode, int initial_dmc_dac )
89{
90 this->dmc.pal_mode = pal_mode;
91 Apu_set_tempo( this, this->tempo_ );
92
93 Square_reset( &this->square1 );
94 Square_reset( &this->square2 );
95 Triangle_reset( &this->triangle );
96 Noise_reset( &this->noise );
97 Dmc_reset( &this->dmc );
98
99 this->last_time = 0;
100 this->last_dmc_time = 0;
101 this->osc_enables = 0;
102 this->irq_flag = false;
103 this->earliest_irq_ = apu_no_irq;
104 this->frame_delay = 1;
105 Apu_write_register( this, 0, 0x4017, 0x00 );
106 Apu_write_register( this, 0, 0x4015, 0x00 );
107
108 addr_t addr;
109 for ( addr = apu_io_addr; addr <= 0x4013; addr++ )
110 Apu_write_register( this, 0, addr, (addr & 3) ? 0x00 : 0x10 );
111
112 this->dmc.dac = initial_dmc_dac;
113 if ( !this->dmc.nonlinear )
114 this->triangle.osc.last_amp = 15;
115 if ( !this->dmc.nonlinear ) // TODO: remove?
116 this->dmc.osc.last_amp = initial_dmc_dac; // prevent output transition
117}
118
119void Apu_irq_changed( struct Nes_Apu* this )
120{
121 nes_time_t new_irq = this->dmc.next_irq;
122 if ( this->dmc.irq_flag | this->irq_flag ) {
123 new_irq = 0;
124 }
125 else if ( new_irq > this->next_irq ) {
126 new_irq = this->next_irq;
127 }
128
129 if ( new_irq != this->earliest_irq_ ) {
130 this->earliest_irq_ = new_irq;
131 if ( this->irq_notifier_ )
132 this->irq_notifier_( this->irq_data );
133 }
134}
135
136// frames
137
138void Apu_run_until( struct Nes_Apu* this, nes_time_t end_time )
139{
140 require( end_time >= this->last_dmc_time );
141 if ( end_time > Apu_next_dmc_read_time( this ) )
142 {
143 nes_time_t start = this->last_dmc_time;
144 this->last_dmc_time = end_time;
145 Dmc_run( &this->dmc, start, end_time );
146 }
147}
148
149void run_until_( struct Nes_Apu* this, nes_time_t end_time )
150{
151 require( end_time >= this->last_time );
152
153 if ( end_time == this->last_time )
154 return;
155
156 if ( this->last_dmc_time < end_time )
157 {
158 nes_time_t start = this->last_dmc_time;
159 this->last_dmc_time = end_time;
160 Dmc_run( &this->dmc, start, end_time );
161 }
162
163 while ( true )
164 {
165 // earlier of next frame time or end time
166 nes_time_t time = this->last_time + this->frame_delay;
167 if ( time > end_time )
168 time = end_time;
169 this->frame_delay -= time - this->last_time;
170
171 // run oscs to present
172 Square_run( &this->square1, this->last_time, time );
173 Square_run( &this->square2, this->last_time, time );
174 Triangle_run( &this->triangle, this->last_time, time );
175 Noise_run( &this->noise, this->last_time, time );
176 this->last_time = time;
177
178 if ( time == end_time )
179 break; // no more frames to run
180
181 // take frame-specific actions
182 this->frame_delay = this->frame_period;
183 switch ( this->frame++ )
184 {
185 case 0:
186 if ( !(this->frame_mode & 0xC0) ) {
187 this->next_irq = time + this->frame_period * 4 + 2;
188 this->irq_flag = true;
189 }
190 // fall through
191 case 2:
192 // clock length and sweep on frames 0 and 2
193 Osc_clock_length( &this->square1.osc, 0x20 );
194 Osc_clock_length( &this->square2.osc, 0x20 );
195 Osc_clock_length( &this->noise.osc, 0x20 );
196 Osc_clock_length( &this->triangle.osc, 0x80 ); // different bit for halt flag on triangle
197
198 Square_clock_sweep( &this->square1, -1 );
199 Square_clock_sweep( &this->square2, 0 );
200
201 // frame 2 is slightly shorter in mode 1
202 if ( this->dmc.pal_mode && this->frame == 3 )
203 this->frame_delay -= 2;
204 break;
205
206 case 1:
207 // frame 1 is slightly shorter in mode 0
208 if ( !this->dmc.pal_mode )
209 this->frame_delay -= 2;
210 break;
211
212 case 3:
213 this->frame = 0;
214
215 // frame 3 is almost twice as long in mode 1
216 if ( this->frame_mode & 0x80 )
217 this->frame_delay += this->frame_period - (this->dmc.pal_mode ? 2 : 6);
218 break;
219 }
220
221 // clock envelopes and linear counter every frame
222 Triangle_clock_linear_counter( &this->triangle );
223 Square_clock_envelope( &this->square1 );
224 Square_clock_envelope( &this->square2 );
225 Noise_clock_envelope( &this->noise );
226 }
227}
228
229static inline void zero_apu_osc( struct Nes_Osc* osc, struct Blip_Synth* synth, nes_time_t time )
230{
231 struct Blip_Buffer* output = osc->output;
232 int last_amp = osc->last_amp;
233 osc->last_amp = 0;
234 if ( output && last_amp )
235 Synth_offset( synth, time, -osc->last_amp, output );
236}
237
238void Apu_end_frame( struct Nes_Apu* this, nes_time_t end_time )
239{
240 if ( end_time > this->last_time )
241 run_until_( this, end_time );
242
243 if ( this->dmc.nonlinear )
244 {
245 zero_apu_osc( &this->square1.osc, this->square1.synth, this->last_time );
246 zero_apu_osc( &this->square2.osc, this->square2.synth, this->last_time );
247 zero_apu_osc( &this->triangle.osc, &this->triangle.synth, this->last_time );
248 zero_apu_osc( &this->noise.osc, &this->noise.synth, this->last_time );
249 zero_apu_osc( &this->dmc.osc, &this->dmc.synth, this->last_time );
250 }
251
252 // make times relative to new frame
253 this->last_time -= end_time;
254 require( this->last_time >= 0 );
255
256 this->last_dmc_time -= end_time;
257 require( this->last_dmc_time >= 0 );
258
259 if ( this->next_irq != apu_no_irq ) {
260 this->next_irq -= end_time;
261 check( this->next_irq >= 0 );
262 }
263 if ( this->dmc.next_irq != apu_no_irq ) {
264 this->dmc.next_irq -= end_time;
265 check( this->dmc.next_irq >= 0 );
266 }
267 if ( this->earliest_irq_ != apu_no_irq ) {
268 this->earliest_irq_ -= end_time;
269 if ( this->earliest_irq_ < 0 )
270 this->earliest_irq_ = 0;
271 }
272}
273
274// registers
275
276static const unsigned char length_table [0x20] ICONST_ATTR = {
277 0x0A, 0xFE, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06,
278 0xA0, 0x08, 0x3C, 0x0A, 0x0E, 0x0C, 0x1A, 0x0E,
279 0x0C, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16,
280 0xC0, 0x18, 0x48, 0x1A, 0x10, 0x1C, 0x20, 0x1E
281};
282
283void Apu_write_register( struct Nes_Apu* this, nes_time_t time, addr_t addr, int data )
284{
285 require( addr > 0x20 ); // addr must be actual address (i.e. 0x40xx)
286 require( (unsigned) data <= 0xFF );
287
288 // Ignore addresses outside range
289 if ( (unsigned) (addr - apu_io_addr) >= apu_io_size )
290 return;
291
292 run_until_( this, time );
293
294 if ( addr < 0x4014 )
295 {
296 // Write to channel
297 int osc_index = (addr - apu_io_addr) >> 2;
298 struct Nes_Osc* osc = this->oscs [osc_index];
299
300 int reg = addr & 3;
301 osc->regs [reg] = data;
302 osc->reg_written [reg] = true;
303
304 if ( osc_index == 4 )
305 {
306 // handle DMC specially
307 Dmc_write_register( &this->dmc, reg, data );
308 }
309 else if ( reg == 3 )
310 {
311 // load length counter
312 if ( (this->osc_enables >> osc_index) & 1 )
313 osc->length_counter = length_table [(data >> 3) & 0x1F];
314
315 // reset square phase
316 if ( osc_index == 0 ) this->square1.phase = square_phase_range - 1;
317 else if ( osc_index == 1 ) this->square2.phase = square_phase_range - 1;
318 }
319 }
320 else if ( addr == 0x4015 )
321 {
322 // Channel enables
323 int i;
324 for ( i = apu_osc_count; i--; )
325 if ( !((data >> i) & 1) )
326 this->oscs [i]->length_counter = 0;
327
328 bool recalc_irq = this->dmc.irq_flag;
329 this->dmc.irq_flag = false;
330
331 int old_enables = this->osc_enables;
332 this->osc_enables = data;
333 if ( !(data & 0x10) ) {
334 this->dmc.next_irq = apu_no_irq;
335 recalc_irq = true;
336 }
337 else if ( !(old_enables & 0x10) ) {
338 Dmc_start( &this->dmc ); // dmc just enabled
339 }
340
341 if ( recalc_irq )
342 Apu_irq_changed( this );
343 }
344 else if ( addr == 0x4017 )
345 {
346 // Frame mode
347 this->frame_mode = data;
348
349 bool irq_enabled = !(data & 0x40);
350 this->irq_flag &= irq_enabled;
351 this->next_irq = apu_no_irq;
352
353 // mode 1
354 this->frame_delay = (this->frame_delay & 1);
355 this->frame = 0;
356
357 if ( !(data & 0x80) )
358 {
359 // mode 0
360 this->frame = 1;
361 this->frame_delay += this->frame_period;
362 if ( irq_enabled )
363 this->next_irq = time + this->frame_delay + this->frame_period * 3 + 1;
364 }
365
366 Apu_irq_changed( this );
367 }
368}
369
370int Apu_read_status( struct Nes_Apu* this, nes_time_t time )
371{
372 run_until_( this, time - 1 );
373
374 int result = (this->dmc.irq_flag << 7) | (this->irq_flag << 6);
375
376 int i;
377 for ( i = 0; i < apu_osc_count; i++ )
378 if ( this->oscs [i]->length_counter )
379 result |= 1 << i;
380
381 run_until_( this, time );
382
383 if ( this->irq_flag )
384 {
385 result |= 0x40;
386 this->irq_flag = false;
387 Apu_irq_changed( this );
388 }
389
390 //debug_printf( "%6d/%d Read $4015->$%02X\n", frame_delay, frame, result );
391
392 return result;
393}
diff --git a/apps/codecs/libgme/nes_apu.h b/apps/codecs/libgme/nes_apu.h
new file mode 100644
index 0000000000..6a2c2805e1
--- /dev/null
+++ b/apps/codecs/libgme/nes_apu.h
@@ -0,0 +1,134 @@
1// NES 2A03 APU sound chip emulator
2
3// Nes_Snd_Emu 0.1.8
4#ifndef NES_APU_H
5#define NES_APU_H
6
7#include "blargg_common.h"
8#include "nes_oscs.h"
9
10enum { apu_status_addr = 0x4015 };
11enum { apu_osc_count = 5 };
12enum { apu_no_irq = INT_MAX / 2 + 1 };
13enum { apu_irq_waiting = 0 };
14
15enum { apu_io_addr = 0x4000 };
16enum { apu_io_size = 0x18 };
17
18struct apu_state_t;
19
20struct Nes_Apu {
21 nes_time_t last_dmc_time;
22 int osc_enables;
23
24 struct Nes_Osc* oscs [apu_osc_count];
25 struct Nes_Square square1;
26 struct Nes_Square square2;
27 struct Nes_Noise noise;
28 struct Nes_Triangle triangle;
29 struct Nes_Dmc dmc;
30
31 double tempo_;
32 nes_time_t last_time; // has been run until this time in current frame
33 nes_time_t earliest_irq_;
34 nes_time_t next_irq;
35 int frame_period;
36 int frame_delay; // cycles until frame counter runs next
37 int frame; // current frame (0-3)
38 int frame_mode;
39 bool irq_flag;
40
41 void (*irq_notifier_)( void* user_data );
42 void* irq_data;
43
44 Synth square_synth; // shared by squares
45};
46
47// Init Nes apu
48void Apu_init( struct Nes_Apu* this );
49
50// Set buffer to generate all sound into, or disable sound if NULL
51void Apu_output( struct Nes_Apu* this, struct Blip_Buffer* ) ICODE_ATTR;
52
53// All time values are the number of cpu clock cycles relative to the
54// beginning of the current time frame. Before resetting the cpu clock
55// count, call end_frame( last_cpu_time ).
56
57// Write to register (0x4000-0x4017, except 0x4014 and 0x4016)
58void Apu_write_register( struct Nes_Apu* this, nes_time_t, addr_t, int data ) ICODE_ATTR;
59
60// Read from status register at 0x4015
61int Apu_read_status( struct Nes_Apu* this, nes_time_t ) ICODE_ATTR;
62
63// Run all oscillators up to specified time, end current time frame, then
64// start a new time frame at time 0. Time frames have no effect on emulation
65// and each can be whatever length is convenient.
66void Apu_end_frame( struct Nes_Apu* this, nes_time_t ) ICODE_ATTR;
67
68// Additional optional features (can be ignored without any problem)
69
70// Reset internal frame counter, registers, and all oscillators.
71// Use PAL timing if pal_timing is true, otherwise use NTSC timing.
72// Set the DMC oscillator's initial DAC value to initial_dmc_dac without
73// any audible click.
74void Apu_reset( struct Nes_Apu* this, bool pal_mode, int initial_dmc_dac );
75
76// Adjust frame period
77void Apu_set_tempo( struct Nes_Apu* this, double );
78
79// Set overall volume (default is 1.0)
80void Apu_volume( struct Nes_Apu* this, double );
81
82// Run DMC until specified time, so that any DMC memory reads can be
83// accounted for (i.e. inserting cpu wait states).
84void Apu_run_until( struct Nes_Apu* this, nes_time_t ) ICODE_ATTR;
85
86// Set sound output of specific oscillator to buffer. If buffer is NULL,
87// the specified oscillator is muted and emulation accuracy is reduced.
88// The oscillators are indexed as follows: 0) Square 1, 1) Square 2,
89// 2) Triangle, 3) Noise, 4) DMC.
90static inline void Apu_osc_output( struct Nes_Apu* this, int osc, struct Blip_Buffer* buf )
91{
92 assert( (unsigned) osc < apu_osc_count );
93 this->oscs [osc]->output = buf;
94}
95
96// Set memory reader callback used by DMC oscillator to fetch samples.
97// When callback is invoked, 'user_data' is passed unchanged as the
98// first parameter.
99static inline void Apu_dmc_reader( struct Nes_Apu* this, int (*func)( void*, addr_t ), void* user_data )
100{
101 this->dmc.prg_reader_data = user_data;
102 this->dmc.prg_reader = func;
103}
104
105// Set IRQ time callback that is invoked when the time of earliest IRQ
106// may have changed, or NULL to disable. When callback is invoked,
107// 'user_data' is passed unchanged as the first parameter.
108static inline void Apu_irq_notifier( struct Nes_Apu* this, void (*func)( void* user_data ), void* user_data )
109{
110 this->irq_notifier_ = func;
111 this->irq_data = user_data;
112}
113
114// Count number of DMC reads that would occur if 'run_until( t )' were executed.
115// If last_read is not NULL, set *last_read to the earliest time that
116// 'count_dmc_reads( time )' would result in the same result.
117static inline int Apu_count_dmc_reads( struct Nes_Apu* this, nes_time_t time, nes_time_t* last_read )
118{
119 return Dmc_count_reads( &this->dmc, time, last_read );
120}
121
122static inline nes_time_t Dmc_next_read_time( struct Nes_Dmc* this )
123{
124 if ( this->osc.length_counter == 0 )
125 return apu_no_irq; // not reading
126
127 return this->apu->last_dmc_time + this->osc.delay + (long) (this->bits_remain - 1) * this->period;
128}
129
130// Time when next DMC memory read will occur
131static inline nes_time_t Apu_next_dmc_read_time( struct Nes_Apu* this ) { return Dmc_next_read_time( &this->dmc ); }
132void Apu_irq_changed( struct Nes_Apu* this ) ICODE_ATTR;
133
134#endif
diff --git a/apps/codecs/libgme/nes_cpu.c b/apps/codecs/libgme/nes_cpu.c
new file mode 100644
index 0000000000..d255cf5485
--- /dev/null
+++ b/apps/codecs/libgme/nes_cpu.c
@@ -0,0 +1,62 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "nes_cpu.h"
4
5#include "blargg_endian.h"
6
7/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
8can redistribute it and/or modify it under the terms of the GNU Lesser
9General Public License as published by the Free Software Foundation; either
10version 2.1 of the License, or (at your option) any later version. This
11module is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14details. You should have received a copy of the GNU Lesser General Public
15License along with this module; if not, write to the Free Software Foundation,
16Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17
18#include "blargg_source.h"
19
20inline void set_code_page( struct Nes_Cpu* this, int i, void const* p )
21{
22 byte const* p2 = STATIC_CAST(byte const*,p) - NES_CPU_OFFSET( i * page_size );
23 this->cpu_state->code_map [i] = p2;
24 this->cpu_state_.code_map [i] = p2;
25}
26
27void Cpu_map_code( struct Nes_Cpu* this, addr_t start, int size, void const* data, int mirror_size )
28{
29 // address range must begin and end on page boundaries
30 require( start % page_size == 0 );
31 require( size % page_size == 0 );
32 require( start + size <= 0x10000 );
33 require( mirror_size % page_size == 0 );
34
35 int offset;
36 for ( offset = 0; offset < size; offset += page_size )
37 set_code_page( this, NES_CPU_PAGE( start + offset ),
38 STATIC_CAST(char const*,data) + (offset & ((unsigned) mirror_size - 1)) );
39}
40
41void Cpu_reset( struct Nes_Cpu* this, void const* unmapped_page )
42{
43 check( this->cpu_state == &this->cpu_state_ );
44 this->cpu_state = &this->cpu_state_;
45
46 this->r.flags = irq_inhibit_mask;
47 this->r.sp = 0xFF;
48 this->r.pc = 0;
49 this->r.a = 0;
50 this->r.x = 0;
51 this->r.y = 0;
52
53 this->cpu_state_.time = 0;
54 this->cpu_state_.base = 0;
55 this->irq_time = future_time;
56 this->end_time = future_time;
57
58 set_code_page( this, page_count, unmapped_page );
59 Cpu_map_code( this, 0, 0x10000, unmapped_page, page_size );
60
61 blargg_verify_byte_order();
62}
diff --git a/apps/codecs/libgme/nes_cpu.h b/apps/codecs/libgme/nes_cpu.h
new file mode 100644
index 0000000000..7129ffd925
--- /dev/null
+++ b/apps/codecs/libgme/nes_cpu.h
@@ -0,0 +1,106 @@
1// NES cpu emulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef NES_CPU_H
5#define NES_CPU_H
6
7#include "blargg_common.h"
8#include "blargg_source.h"
9
10typedef int nes_time_t;
11typedef int addr_t;
12
13enum { page_bits = 11 };
14enum { page_size = 1 << page_bits };
15enum { page_count = 0x10000 >> page_bits };
16
17// Unmapped page should be filled with this
18enum { halt_opcode = 0x22 };
19
20enum { future_time = INT_MAX/2 + 1 };
21enum { irq_inhibit_mask = 0x04 };
22
23// Can read this many bytes past end of a page
24enum { cpu_padding = 8 };
25
26struct registers_t {
27 uint16_t pc;
28 uint8_t a;
29 uint8_t x;
30 uint8_t y;
31 uint8_t flags;
32 uint8_t sp;
33};
34
35struct cpu_state_t {
36 uint8_t const* code_map [page_count + 1];
37 nes_time_t base;
38 int time;
39};
40
41struct Nes_Cpu {
42 // NES 6502 registers. NOT kept updated during emulation.
43 struct registers_t r;
44 nes_time_t irq_time;
45 nes_time_t end_time;
46
47 struct cpu_state_t* cpu_state; // points to cpu_state_ or a local copy
48 struct cpu_state_t cpu_state_;
49};
50
51static inline void Cpu_init( struct Nes_Cpu* this ) { this->cpu_state = &this->cpu_state_; }
52
53// Clears registers and maps all pages to unmapped_page
54void Cpu_reset( struct Nes_Cpu* this, void const* unmapped_page );
55
56// Maps code memory (memory accessed via the program counter). Start and size
57// must be multiple of page_size. If mirror_size is non-zero, the first
58// mirror_size bytes are repeated over the range. mirror_size must be a
59// multiple of page_size.
60void Cpu_map_code( struct Nes_Cpu* this, addr_t start, int size, void const* code, int mirror_size );
61
62// Time of beginning of next instruction to be executed
63static inline nes_time_t Cpu_time( struct Nes_Cpu* this ) { return this->cpu_state->time + this->cpu_state->base; }
64static inline void Cpu_set_time( struct Nes_Cpu* this, nes_time_t t ) { this->cpu_state->time = t - this->cpu_state->base; }
65static inline void Cpu_adjust_time( struct Nes_Cpu* this, int delta ) { this->cpu_state->time += delta; }
66
67// Clocks past end (negative if before)
68static inline int Cpu_time_past_end( struct Nes_Cpu* this ) { return this->cpu_state->time; }
69
70#define NES_CPU_PAGE( addr ) ((unsigned) (addr) >> page_bits)
71
72#ifdef BLARGG_NONPORTABLE
73 #define NES_CPU_OFFSET( addr ) (addr)
74#else
75 #define NES_CPU_OFFSET( addr ) ((addr) & (page_size - 1))
76#endif
77
78// Accesses emulated memory as cpu does
79static inline uint8_t const* Cpu_get_code( struct Nes_Cpu* this, addr_t addr )
80{
81 return this->cpu_state_.code_map [NES_CPU_PAGE( addr )] + NES_CPU_OFFSET( addr );
82}
83
84static inline void Cpu_update_end_time( struct Nes_Cpu* this, nes_time_t end, nes_time_t irq )
85{
86 if ( end > irq && !(this->r.flags & irq_inhibit_mask) )
87 end = irq;
88
89 this->cpu_state->time += this->cpu_state->base - end;
90 this->cpu_state->base = end;
91}
92
93// Time of next IRQ
94static inline void Cpu_set_irq_time( struct Nes_Cpu* this, nes_time_t t )
95{
96 this->irq_time = t;
97 Cpu_update_end_time( this, this->end_time, t );
98}
99
100static inline void Cpu_set_end_time( struct Nes_Cpu* this, nes_time_t t )
101{
102 this->end_time = t;
103 Cpu_update_end_time( this, t, this->irq_time );
104}
105
106#endif
diff --git a/apps/codecs/libgme/nes_cpu_io.h b/apps/codecs/libgme/nes_cpu_io.h
new file mode 100644
index 0000000000..4f9d416c2d
--- /dev/null
+++ b/apps/codecs/libgme/nes_cpu_io.h
@@ -0,0 +1,94 @@
1
2#include "nsf_emu.h"
3
4#ifndef NSF_EMU_APU_ONLY
5 #include "nes_namco_apu.h"
6 #include "nes_fds_apu.h"
7 #include "nes_mmc5_apu.h"
8#endif
9
10#include "blargg_source.h"
11
12int Cpu_read( struct Nsf_Emu* this, nes_addr_t addr )
13{
14 int result = this->cpu.low_mem [addr & 0x7FF];
15 if ( addr & 0xE000 )
16 {
17 result = *Cpu_get_code( &this->cpu, addr );
18 if ( addr < sram_addr )
19 {
20 if ( addr == status_addr )
21 result = Apu_read_status( &this->apu, Cpu_time( &this->cpu ) );
22 else
23 {
24 #ifndef NSF_EMU_APU_ONLY
25 if ( namco_enabled( this ) && addr == namco_data_reg_addr )
26 return Namco_read_data( &this->namco );
27
28 if ( fds_enabled( this ) && (unsigned) (addr - fds_io_addr) < fds_io_size )
29 return Fds_read( &this->fds, Cpu_time( &this->cpu ), addr );
30
31 if ( mmc5_enabled( this ) ) {
32 int i = addr - 0x5C00;
33 if ( (unsigned) i < mmc5_exram_size )
34 return this->mmc5.exram [i];
35
36 int m = addr - 0x5205;
37 if ( (unsigned) m < 2 )
38 return (this->mmc5_mul [0] * this->mmc5_mul [1]) >> (m * 8) & 0xFF;
39 }
40 #endif
41 result = addr >> 8; // simulate open bus
42 }
43 }
44 }
45
46 /* if ( addr != 0x2002 )
47 debug_printf( "Read unmapped $%.4X\n", (unsigned) addr ); */
48
49 return result;
50}
51
52void Cpu_write( struct Nsf_Emu* this, nes_addr_t addr, int data )
53{
54 int offset = addr - sram_addr;
55 if ( (unsigned) offset < sram_size )
56 {
57 this->sram [offset] = data;
58 }
59 else
60 {
61 // after sram because cpu handles most low_ram accesses internally already
62 int temp = addr & (low_ram_size-1); // also handles wrap-around
63 if ( !(addr & 0xE000) )
64 {
65 this->cpu.low_mem [temp] = data;
66 }
67 else
68 {
69 int bank = addr - banks_addr;
70 if ( (unsigned) bank < bank_count )
71 {
72 Write_bank( this, bank, data );
73 }
74 else if ( (unsigned) (addr - start_addr) <= end_addr - start_addr )
75 {
76 Apu_write_register( &this->apu, Cpu_time( &this->cpu ), addr, data );
77 }
78 else
79 {
80 #ifndef NSF_EMU_APU_ONLY
81 // 0x8000-0xDFFF is writable
82 int i = addr - 0x8000;
83 if ( fds_enabled( this ) && (unsigned) i < fdsram_size )
84 fdsram( this ) [i] = data;
85 else
86 #endif
87 Cpu_write_misc( this, addr, data );
88 }
89 }
90 }
91}
92
93#define CPU_READ( emu, addr, time ) Cpu_read( emu, addr )
94#define CPU_WRITE( emu, addr, data, time ) Cpu_write( emu, addr, data )
diff --git a/apps/codecs/libgme/nes_cpu_run.h b/apps/codecs/libgme/nes_cpu_run.h
new file mode 100644
index 0000000000..5b964d5070
--- /dev/null
+++ b/apps/codecs/libgme/nes_cpu_run.h
@@ -0,0 +1,1122 @@
1// NES 6502 cpu emulator run function
2
3#if 0
4/* Define these macros in the source file before #including this file.
5- Parameters might be expressions, so they are best evaluated only once,
6though they NEVER have side-effects, so multiple evaluation is OK.
7- Output parameters might be a multiple-assignment expression like "a=x",
8so they must NOT be parenthesized.
9- Except where noted, time() and related functions will NOT work
10correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and
11CACHE_TIME() allow the time changing functions to work.
12- Macros "returning" void may use a {} statement block. */
13
14 // 0 <= addr <= 0xFFFF + page_size
15 // time functions can be used
16 int READ_MEM( addr_t );
17 void WRITE_MEM( addr_t, int data );
18 // 0 <= READ_MEM() <= 0xFF
19
20 // 0 <= addr <= 0x1FF
21 int READ_LOW( addr_t );
22 void WRITE_LOW( addr_t, int data );
23 // 0 <= READ_LOW() <= 0xFF
24
25 // Often-used instructions attempt these before using a normal memory access.
26 // Optional; defaults to READ_MEM() and WRITE_MEM()
27 bool CAN_READ_FAST( addr_t ); // if true, uses result of READ_FAST
28 void READ_FAST( addr_t, int& out ); // ALWAYS called BEFORE CAN_READ_FAST
29 bool CAN_WRITE_FAST( addr_t ); // if true, uses WRITE_FAST instead of WRITE_MEM
30 void WRITE_FAST( addr_t, int data );
31
32 // Used by instructions most often used to access the NES PPU (LDA abs and BIT abs).
33 // Optional; defaults to READ_MEM.
34 void READ_PPU( addr_t, int& out );
35 // 0 <= out <= 0xFF
36
37// The following can be used within macros:
38
39 // Current time
40 time_t TIME();
41
42 // Allows use of time functions
43 void FLUSH_TIME();
44
45 // Must be used before end of macro if FLUSH_TIME() was used earlier
46 void CACHE_TIME();
47
48// Configuration (optional; commented behavior if defined)
49
50 // Emulates dummy reads for indexed instructions
51 #define NES_CPU_DUMMY_READS 1
52
53 // Optimizes as if map_code( 0, 0x10000 + cpu_padding, FLAT_MEM ) is always in effect
54 #define FLAT_MEM my_mem_array
55
56 // Expanded just before beginning of code, to help debugger
57 #define CPU_BEGIN void my_run_cpu() {
58
59#endif
60
61/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
62can redistribute it and/or modify it under the terms of the GNU Lesser
63General Public License as published by the Free Software Foundation; either
64version 2.1 of the License, or (at your option) any later version. This
65module is distributed in the hope that it will be useful, but WITHOUT ANY
66WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
67FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
68details. You should have received a copy of the GNU Lesser General Public
69License along with this module; if not, write to the Free Software Foundation,
70Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
71
72// Allows MWCW debugger to step through code properly
73#ifdef CPU_BEGIN
74 CPU_BEGIN
75#endif
76
77// Time
78#define TIME() (s_time + s.base)
79#define FLUSH_TIME() {s.time = s_time - time_offset;}
80#define CACHE_TIME() {s_time = s.time + time_offset;}
81
82// Defaults
83#ifndef CAN_WRITE_FAST
84 #define CAN_WRITE_FAST( addr ) 0
85 #define WRITE_FAST( addr, data )
86#endif
87
88#ifndef CAN_READ_FAST
89 #define CAN_READ_FAST( addr ) 0
90 #define READ_FAST( addr, out )
91#endif
92
93#ifndef READ_PPU
94 #define READ_PPU( addr, out )\
95 {\
96 FLUSH_TIME();\
97 out = READ_MEM( addr );\
98 CACHE_TIME();\
99 }
100#endif
101
102#define READ_STACK READ_LOW
103#define WRITE_STACK WRITE_LOW
104
105// Dummy reads
106#ifdef NES_CPU_DUMMY_READS
107 // TODO: optimize time handling
108 #define DUMMY_READ( addr, idx ) \
109 if ( (addr & 0xFF) < idx )\
110 {\
111 int const time_offset = 1;\
112 FLUSH_TIME();\
113 READ_MEM( (addr - 0x100) );\
114 CACHE_TIME();\
115 }
116#else
117 #define DUMMY_READ( addr, idx )
118#endif
119
120// Code
121#ifdef FLAT_MEM
122 #define CODE_PAGE( addr ) (FLAT_MEM)
123 #define CODE_OFFSET( addr ) (addr)
124#else
125 #define CODE_PAGE( addr ) (s.code_map [NES_CPU_PAGE( addr )])
126 #define CODE_OFFSET( addr ) NES_CPU_OFFSET( addr )
127#endif
128#define READ_CODE( addr ) (CODE_PAGE( addr ) [CODE_OFFSET( addr )])
129
130// Stack
131#define SET_SP( v ) (sp = ((v) + 1) | 0x100)
132#define GET_SP() ((sp - 1) & 0xFF)
133#define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100)
134
135// Truncation
136#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */
137#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */
138#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */
139
140// Flags with hex value for clarity when used as mask.
141// Stored in indicated variable during emulation.
142int const n80 = 0x80; // nz
143int const v40 = 0x40; // flags
144int const r20 = 0x20;
145int const b10 = 0x10;
146int const d08 = 0x08; // flags
147int const i04 = 0x04; // flags
148int const z02 = 0x02; // nz
149int const c01 = 0x01; // c
150
151#define IS_NEG (nz & 0x8080)
152
153#define GET_FLAGS( out ) \
154{\
155 out = flags & (v40 | d08 | i04);\
156 out += ((nz >> 8) | nz) & n80;\
157 out += c >> 8 & c01;\
158 if ( !BYTE( nz ) )\
159 out += z02;\
160}
161
162#define SET_FLAGS( in ) \
163{\
164 flags = in & (v40 | d08 | i04);\
165 c = nz = in << 8;\
166 nz += ~in & z02;\
167}
168
169{
170 int const time_offset = 0;
171
172 // Local state
173 struct cpu_state_t s;
174 #ifdef FLAT_MEM
175 s.base = cpu->cpu_state_.base;
176 #else
177 s = cpu->cpu_state_;
178 #endif
179 cpu->cpu_state = &s;
180 int s_time = cpu->cpu_state_.time; // helps even on x86
181
182 // Registers
183 int pc = cpu->r.pc;
184 int a = cpu->r.a;
185 int x = cpu->r.x;
186 int y = cpu->r.y;
187 int sp;
188 SET_SP( cpu->r.sp );
189
190 // Flags
191 int flags;
192 int c; // carry set if (c & 0x100) != 0
193 int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
194 {
195 int temp = cpu->r.flags;
196 SET_FLAGS( temp );
197 }
198
199loop:
200
201 // Check all values
202 check( (unsigned) sp - 0x100 < 0x100 );
203 check( (unsigned) pc < 0x10000 );
204 check( (unsigned) a < 0x100 );
205 check( (unsigned) x < 0x100 );
206 check( (unsigned) y < 0x100 );
207
208 // Read instruction
209 byte const* instr = CODE_PAGE( pc );
210 int opcode;
211
212 if ( CODE_OFFSET(~0) == ~0 )
213 {
214 opcode = instr [pc];
215 pc++;
216 instr += pc;
217 }
218 else
219 {
220 instr += CODE_OFFSET( pc );
221 opcode = *instr++;
222 pc++;
223 }
224
225 // local to function in case it helps optimizer
226 static byte const clock_table [256] =
227 {// 0 1 2 3 4 5 6 7 8 9 A B C D E F
228 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0
229 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1
230 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2
231 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3
232 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4
233 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5
234 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6
235 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7
236 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8
237 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9
238 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A
239 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B
240 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C
241 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D
242 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E
243 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F
244 }; // 0x00 was 7 and 0x22 was 2
245
246 // Update time
247 if ( s_time >= 0 )
248 goto out_of_time;
249
250 #ifdef CPU_INSTR_HOOK
251 { CPU_INSTR_HOOK( (pc-1), (&instr [-1]), a, x, y, GET_SP(), TIME() ); }
252 #endif
253
254 s_time += clock_table [opcode];
255
256 int data;
257 data = *instr;
258
259 switch ( opcode )
260 {
261
262// Macros
263
264#define GET_MSB() (instr [1])
265#define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB())
266#define GET_ADDR() GET_LE16( instr )
267
268#define PAGE_PENALTY( lsb ) s_time += (lsb) >> 8;
269
270#define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop;
271
272#define IND_Y( cross, out ) {\
273 int temp = READ_LOW( data ) + y;\
274 out = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\
275 cross( temp );\
276 }
277
278#define IND_X( out ) {\
279 int temp = data + x;\
280 out = 0x100 * READ_LOW( BYTE( temp + 1 ) ) + READ_LOW( BYTE( temp ) );\
281 }
282
283#define ARITH_ADDR_MODES( op )\
284case op - 0x04: /* (ind,x) */\
285 IND_X( data )\
286 goto ptr##op;\
287case op + 0x0C: /* (ind),y */\
288 IND_Y( PAGE_PENALTY, data )\
289 goto ptr##op;\
290case op + 0x10: /* zp,X */\
291 data = BYTE( data + x );\
292case op + 0x00: /* zp */\
293 data = READ_LOW( data );\
294 goto imm##op;\
295case op + 0x14: /* abs,Y */\
296 data += y;\
297 goto ind##op;\
298case op + 0x18: /* abs,X */\
299 data += x;\
300ind##op:\
301 PAGE_PENALTY( data );\
302case op + 0x08: /* abs */\
303 ADD_PAGE( data );\
304ptr##op:\
305 FLUSH_TIME();\
306 data = READ_MEM( data );\
307 CACHE_TIME();\
308case op + 0x04: /* imm */\
309imm##op:
310
311// TODO: more efficient way to handle negative branch that wraps PC around
312#define BRANCH( cond )\
313{\
314 ++pc;\
315 if ( !(cond) ) goto loop;\
316 s_time++;\
317 int offset = SBYTE( data );\
318 s_time += (BYTE(pc) + offset) >> 8 & 1;\
319 pc = WORD( pc + offset );\
320 goto loop;\
321}
322
323// Often-Used
324
325 case 0xB5: // LDA zp,x
326 a = nz = READ_LOW( BYTE( data + x ) );
327 pc++;
328 goto loop;
329
330 case 0xA5: // LDA zp
331 a = nz = READ_LOW( data );
332 pc++;
333 goto loop;
334
335 case 0xD0: // BNE
336 BRANCH( BYTE( nz ) );
337
338 case 0x20: { // JSR
339 int temp = pc + 1;
340 pc = GET_ADDR();
341 WRITE_STACK( SP( -1 ), temp >> 8 );
342 sp = SP( -2 );
343 WRITE_STACK( sp, temp );
344 goto loop;
345 }
346
347 case 0x4C: // JMP abs
348 pc = GET_ADDR();
349 goto loop;
350
351 case 0xE8: // INX
352 INC_DEC( x, 1 )
353
354 case 0x10: // BPL
355 BRANCH( !IS_NEG )
356
357 ARITH_ADDR_MODES( 0xC5 ) // CMP
358 nz = a - data;
359 pc++;
360 c = ~nz;
361 nz &= 0xFF;
362 goto loop;
363
364 case 0x30: // BMI
365 BRANCH( IS_NEG )
366
367 case 0xF0: // BEQ
368 BRANCH( !BYTE( nz ) );
369
370 case 0x95: // STA zp,x
371 data = BYTE( data + x );
372 case 0x85: // STA zp
373 pc++;
374 WRITE_LOW( data, a );
375 goto loop;
376
377 case 0xC8: // INY
378 INC_DEC( y, 1 )
379
380 case 0xA8: // TAY
381 y = a;
382 nz = a;
383 goto loop;
384
385 case 0x98: // TYA
386 a = y;
387 nz = y;
388 goto loop;
389
390 case 0xAD:{// LDA abs
391 int addr = GET_ADDR();
392 pc += 2;
393 READ_PPU( addr, a = nz );
394 goto loop;
395 }
396
397 case 0x60: // RTS
398 pc = 1 + READ_STACK( sp );
399 pc += 0x100 * READ_STACK( SP( 1 ) );
400 sp = SP( 2 );
401 goto loop;
402
403 {
404 int addr;
405
406 case 0x8D: // STA abs
407 addr = GET_ADDR();
408 pc += 2;
409 if ( CAN_WRITE_FAST( addr ) )
410 {
411 WRITE_FAST( addr, a );
412 goto loop;
413 }
414 sta_ptr:
415 FLUSH_TIME();
416 WRITE_MEM( addr, a );
417 CACHE_TIME();
418 goto loop;
419
420 case 0x99: // STA abs,Y
421 addr = y + GET_ADDR();
422 pc += 2;
423 if ( CAN_WRITE_FAST( addr ) )
424 {
425 WRITE_FAST( addr, a );
426 goto loop;
427 }
428 goto sta_abs_x;
429
430 case 0x9D: // STA abs,X (slightly more common than STA abs)
431 addr = x + GET_ADDR();
432 pc += 2;
433 if ( CAN_WRITE_FAST( addr ) )
434 {
435 WRITE_FAST( addr, a );
436 goto loop;
437 }
438 DUMMY_READ( addr, x );
439 sta_abs_x:
440 FLUSH_TIME();
441 WRITE_MEM( addr, a );
442 CACHE_TIME();
443 goto loop;
444
445 case 0x91: // STA (ind),Y
446 #define NO_PAGE_PENALTY( lsb )
447 IND_Y( NO_PAGE_PENALTY, addr )
448 pc++;
449 DUMMY_READ( addr, y );
450 goto sta_ptr;
451
452 case 0x81: // STA (ind,X)
453 IND_X( addr )
454 pc++;
455 goto sta_ptr;
456
457 }
458
459 case 0xA9: // LDA #imm
460 pc++;
461 a = data;
462 nz = data;
463 goto loop;
464
465 // common read instructions
466 {
467 int addr;
468
469 case 0xA1: // LDA (ind,X)
470 IND_X( addr )
471 pc++;
472 goto a_nz_read_addr;
473
474 case 0xB1:// LDA (ind),Y
475 addr = READ_LOW( data ) + y;
476 PAGE_PENALTY( addr );
477 addr += 0x100 * READ_LOW( BYTE( data + 1 ) );
478 pc++;
479 READ_FAST( addr, a = nz );
480 if ( CAN_READ_FAST( addr ) )
481 goto loop;
482 DUMMY_READ( addr, y );
483 goto a_nz_read_addr;
484
485 case 0xB9: // LDA abs,Y
486 PAGE_PENALTY( data + y );
487 addr = GET_ADDR() + y;
488 pc += 2;
489 READ_FAST( addr, a = nz );
490 if ( CAN_READ_FAST( addr ) )
491 goto loop;
492 goto a_nz_read_addr;
493
494 case 0xBD: // LDA abs,X
495 PAGE_PENALTY( data + x );
496 addr = GET_ADDR() + x;
497 pc += 2;
498 READ_FAST( addr, a = nz );
499 if ( CAN_READ_FAST( addr ) )
500 goto loop;
501 DUMMY_READ( addr, x );
502 a_nz_read_addr:
503 FLUSH_TIME();
504 a = nz = READ_MEM( addr );
505 CACHE_TIME();
506 goto loop;
507
508 }
509
510// Branch
511
512 case 0x50: // BVC
513 BRANCH( !(flags & v40) )
514
515 case 0x70: // BVS
516 BRANCH( flags & v40 )
517
518 case 0xB0: // BCS
519 BRANCH( c & 0x100 )
520
521 case 0x90: // BCC
522 BRANCH( !(c & 0x100) )
523
524// Load/store
525
526 case 0x94: // STY zp,x
527 data = BYTE( data + x );
528 case 0x84: // STY zp
529 pc++;
530 WRITE_LOW( data, y );
531 goto loop;
532
533 case 0x96: // STX zp,y
534 data = BYTE( data + y );
535 case 0x86: // STX zp
536 pc++;
537 WRITE_LOW( data, x );
538 goto loop;
539
540 case 0xB6: // LDX zp,y
541 data = BYTE( data + y );
542 case 0xA6: // LDX zp
543 data = READ_LOW( data );
544 case 0xA2: // LDX #imm
545 pc++;
546 x = data;
547 nz = data;
548 goto loop;
549
550 case 0xB4: // LDY zp,x
551 data = BYTE( data + x );
552 case 0xA4: // LDY zp
553 data = READ_LOW( data );
554 case 0xA0: // LDY #imm
555 pc++;
556 y = data;
557 nz = data;
558 goto loop;
559
560 case 0xBC: // LDY abs,X
561 data += x;
562 PAGE_PENALTY( data );
563 case 0xAC:{// LDY abs
564 int addr = data + 0x100 * GET_MSB();
565 pc += 2;
566 FLUSH_TIME();
567 y = nz = READ_MEM( addr );
568 CACHE_TIME();
569 goto loop;
570 }
571
572 case 0xBE: // LDX abs,y
573 data += y;
574 PAGE_PENALTY( data );
575 case 0xAE:{// LDX abs
576 int addr = data + 0x100 * GET_MSB();
577 pc += 2;
578 FLUSH_TIME();
579 x = nz = READ_MEM( addr );
580 CACHE_TIME();
581 goto loop;
582 }
583
584 {
585 int temp;
586 case 0x8C: // STY abs
587 temp = y;
588 goto store_abs;
589
590 case 0x8E: // STX abs
591 temp = x;
592 store_abs:
593 {
594 int addr = GET_ADDR();
595 pc += 2;
596 if ( CAN_WRITE_FAST( addr ) )
597 {
598 WRITE_FAST( addr, temp );
599 goto loop;
600 }
601 FLUSH_TIME();
602 WRITE_MEM( addr, temp );
603 CACHE_TIME();
604 goto loop;
605 }
606 }
607
608// Compare
609
610 case 0xEC: {// CPX abs
611 int addr = GET_ADDR();
612 pc++;
613 FLUSH_TIME();
614 data = READ_MEM( addr );
615 CACHE_TIME();
616 goto cpx_data;
617 }
618
619 case 0xE4: // CPX zp
620 data = READ_LOW( data );
621 case 0xE0: // CPX #imm
622 cpx_data:
623 nz = x - data;
624 pc++;
625 c = ~nz;
626 nz &= 0xFF;
627 goto loop;
628
629 case 0xCC:{// CPY abs
630 int addr = GET_ADDR();
631 pc++;
632 FLUSH_TIME();
633 data = READ_MEM( addr );
634 CACHE_TIME();
635 goto cpy_data;
636 }
637
638 case 0xC4: // CPY zp
639 data = READ_LOW( data );
640 case 0xC0: // CPY #imm
641 cpy_data:
642 nz = y - data;
643 pc++;
644 c = ~nz;
645 nz &= 0xFF;
646 goto loop;
647
648// Logical
649
650 ARITH_ADDR_MODES( 0x25 ) // AND
651 nz = (a &= data);
652 pc++;
653 goto loop;
654
655 ARITH_ADDR_MODES( 0x45 ) // EOR
656 nz = (a ^= data);
657 pc++;
658 goto loop;
659
660 ARITH_ADDR_MODES( 0x05 ) // ORA
661 nz = (a |= data);
662 pc++;
663 goto loop;
664
665 case 0x2C:{// BIT abs
666 int addr = GET_ADDR();
667 pc += 2;
668 READ_PPU( addr, nz );
669 flags = (flags & ~v40) + (nz & v40);
670 if ( a & nz )
671 goto loop;
672 nz <<= 8; // result must be zero, even if N bit is set
673 goto loop;
674 }
675
676 case 0x24: // BIT zp
677 nz = READ_LOW( data );
678 pc++;
679 flags = (flags & ~v40) + (nz & v40);
680 if ( a & nz )
681 goto loop; // Z should be clear, and nz must be non-zero if nz & a is
682 nz <<= 8; // set Z flag without affecting N flag
683 goto loop;
684
685// Add/subtract
686
687 ARITH_ADDR_MODES( 0xE5 ) // SBC
688 case 0xEB: // unofficial equivalent
689 data ^= 0xFF;
690 goto adc_imm;
691
692 ARITH_ADDR_MODES( 0x65 ) // ADC
693 adc_imm: {
694 int carry = c >> 8 & 1;
695 int ov = (a ^ 0x80) + carry + SBYTE( data );
696 flags = (flags & ~v40) + (ov >> 2 & v40);
697 c = nz = a + data + carry;
698 pc++;
699 a = BYTE( nz );
700 goto loop;
701 }
702
703// Shift/rotate
704
705 case 0x4A: // LSR A
706 c = 0;
707 case 0x6A: // ROR A
708 nz = c >> 1 & 0x80;
709 c = a << 8;
710 nz += a >> 1;
711 a = nz;
712 goto loop;
713
714 case 0x0A: // ASL A
715 nz = a << 1;
716 c = nz;
717 a = BYTE( nz );
718 goto loop;
719
720 case 0x2A: { // ROL A
721 nz = a << 1;
722 int temp = c >> 8 & 1;
723 c = nz;
724 nz += temp;
725 a = BYTE( nz );
726 goto loop;
727 }
728
729 case 0x5E: // LSR abs,X
730 data += x;
731 case 0x4E: // LSR abs
732 c = 0;
733 case 0x6E: // ROR abs
734 ror_abs: {
735 ADD_PAGE( data );
736 FLUSH_TIME();
737 int temp = READ_MEM( data );
738 nz = (c >> 1 & 0x80) + (temp >> 1);
739 c = temp << 8;
740 goto rotate_common;
741 }
742
743 case 0x3E: // ROL abs,X
744 data += x;
745 goto rol_abs;
746
747 case 0x1E: // ASL abs,X
748 data += x;
749 case 0x0E: // ASL abs
750 c = 0;
751 case 0x2E: // ROL abs
752 rol_abs:
753 ADD_PAGE( data );
754 nz = c >> 8 & 1;
755 FLUSH_TIME();
756 nz += (c = READ_MEM( data ) << 1);
757 rotate_common:
758 pc++;
759 WRITE_MEM( data, BYTE( nz ) );
760 CACHE_TIME();
761 goto loop;
762
763 case 0x7E: // ROR abs,X
764 data += x;
765 goto ror_abs;
766
767 case 0x76: // ROR zp,x
768 data = BYTE( data + x );
769 goto ror_zp;
770
771 case 0x56: // LSR zp,x
772 data = BYTE( data + x );
773 case 0x46: // LSR zp
774 c = 0;
775 case 0x66: // ROR zp
776 ror_zp: {
777 int temp = READ_LOW( data );
778 nz = (c >> 1 & 0x80) + (temp >> 1);
779 c = temp << 8;
780 goto write_nz_zp;
781 }
782
783 case 0x36: // ROL zp,x
784 data = BYTE( data + x );
785 goto rol_zp;
786
787 case 0x16: // ASL zp,x
788 data = BYTE( data + x );
789 case 0x06: // ASL zp
790 c = 0;
791 case 0x26: // ROL zp
792 rol_zp:
793 nz = c >> 8 & 1;
794 nz += (c = READ_LOW( data ) << 1);
795 goto write_nz_zp;
796
797// Increment/decrement
798
799 case 0xCA: // DEX
800 INC_DEC( x, -1 )
801
802 case 0x88: // DEY
803 INC_DEC( y, -1 )
804
805 case 0xF6: // INC zp,x
806 data = BYTE( data + x );
807 case 0xE6: // INC zp
808 nz = 1;
809 goto add_nz_zp;
810
811 case 0xD6: // DEC zp,x
812 data = BYTE( data + x );
813 case 0xC6: // DEC zp
814 nz = -1;
815 add_nz_zp:
816 nz += READ_LOW( data );
817 write_nz_zp:
818 pc++;
819 WRITE_LOW( data, nz );
820 goto loop;
821
822 case 0xFE: // INC abs,x
823 data = x + GET_ADDR();
824 goto inc_ptr;
825
826 case 0xEE: // INC abs
827 data = GET_ADDR();
828 inc_ptr:
829 nz = 1;
830 goto inc_common;
831
832 case 0xDE: // DEC abs,x
833 data = x + GET_ADDR();
834 goto dec_ptr;
835
836 case 0xCE: // DEC abs
837 data = GET_ADDR();
838 dec_ptr:
839 nz = -1;
840 inc_common:
841 FLUSH_TIME();
842 pc += 2;
843 nz += READ_MEM( data );
844 WRITE_MEM( data, BYTE( nz ) );
845 CACHE_TIME();
846 goto loop;
847
848// Transfer
849
850 case 0xAA: // TAX
851 x = nz = a;
852 goto loop;
853
854 case 0x8A: // TXA
855 a = nz = x;
856 goto loop;
857
858 case 0x9A: // TXS
859 SET_SP( x ); // verified (no flag change)
860 goto loop;
861
862 case 0xBA: // TSX
863 x = nz = GET_SP();
864 goto loop;
865
866// Stack
867
868 case 0x48: // PHA
869 sp = SP( -1 );
870 WRITE_STACK( sp, a );
871 goto loop;
872
873 case 0x68: // PLA
874 a = nz = READ_STACK( sp );
875 sp = SP( 1 );
876 goto loop;
877
878 case 0x40:{// RTI
879 pc = READ_STACK( SP( 1 ) );
880 pc += READ_STACK( SP( 2 ) ) * 0x100;
881 int temp = READ_STACK( sp );
882 sp = SP( 3 );
883 data = flags;
884 SET_FLAGS( temp );
885 cpu->r.flags = flags; // update externally-visible I flag
886 int delta = s.base - cpu->irq_time;
887 if ( delta <= 0 ) goto loop; // end_time < irq_time
888 if ( flags & i04 ) goto loop;
889 s_time += delta;
890 s.base = cpu->irq_time;
891 goto loop;
892 }
893
894 case 0x28:{// PLP
895 int temp = READ_STACK( sp );
896 sp = SP( 1 );
897 int changed = flags ^ temp;
898 SET_FLAGS( temp );
899 if ( !(changed & i04) )
900 goto loop; // I flag didn't change
901 if ( flags & i04 )
902 goto handle_sei;
903 goto handle_cli;
904 }
905
906 case 0x08:{// PHP
907 int temp;
908 GET_FLAGS( temp );
909 sp = SP( -1 );
910 WRITE_STACK( sp, temp | (b10 | r20) );
911 goto loop;
912 }
913
914 case 0x6C:{// JMP (ind)
915 data = GET_ADDR();
916 byte const* page = CODE_PAGE( data );
917 pc = page [CODE_OFFSET( data )];
918 data = (data & 0xFF00) + ((data + 1) & 0xFF);
919 pc += page [CODE_OFFSET( data )] * 0x100;
920 goto loop;
921 }
922
923 case 0x00: // BRK
924 goto handle_brk;
925
926// Flags
927
928 case 0x38: // SEC
929 c = 0x100;
930 goto loop;
931
932 case 0x18: // CLC
933 c = 0;
934 goto loop;
935
936 case 0xB8: // CLV
937 flags &= ~v40;
938 goto loop;
939
940 case 0xD8: // CLD
941 flags &= ~d08;
942 goto loop;
943
944 case 0xF8: // SED
945 flags |= d08;
946 goto loop;
947
948 case 0x58: // CLI
949 if ( !(flags & i04) )
950 goto loop;
951 flags &= ~i04;
952 handle_cli: {
953 //dprintf( "CLI at %d\n", TIME );
954 cpu->r.flags = flags; // update externally-visible I flag
955 int delta = s.base - cpu->irq_time;
956 if ( delta <= 0 )
957 {
958 if ( TIME() < cpu->irq_time )
959 goto loop;
960 goto delayed_cli;
961 }
962 s.base = cpu->irq_time;
963 s_time += delta;
964 if ( s_time < 0 )
965 goto loop;
966
967 if ( delta >= s_time + 1 )
968 {
969 // delayed irq until after next instruction
970 s.base += s_time + 1;
971 s_time = -1;
972 goto loop;
973 }
974
975 // TODO: implement
976 delayed_cli:
977 dprintf( "Delayed CLI not emulated\n" );
978 goto loop;
979 }
980
981 case 0x78: // SEI
982 if ( flags & i04 )
983 goto loop;
984 flags |= i04;
985 handle_sei: {
986 cpu->r.flags = flags; // update externally-visible I flag
987 int delta = s.base - cpu->end_time;
988 s.base = cpu->end_time;
989 s_time += delta;
990 if ( s_time < 0 )
991 goto loop;
992
993 dprintf( "Delayed SEI not emulated\n" );
994 goto loop;
995 }
996
997// Unofficial
998
999 // SKW - skip word
1000 case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC:
1001 PAGE_PENALTY( data + x );
1002 case 0x0C:
1003 pc++;
1004 // SKB - skip byte
1005 case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64:
1006 case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4:
1007 pc++;
1008 goto loop;
1009
1010 // NOP
1011 case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA:
1012 goto loop;
1013
1014 case halt_opcode: // HLT - halt processor
1015 if ( pc-- > 0x10000 )
1016 {
1017 // handle wrap-around (assumes caller has put page of HLT at 0x10000)
1018 pc = WORD( pc );
1019 goto loop;
1020 }
1021 case 0x02: case 0x12: case 0x32: case 0x42: case 0x52:
1022 case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2:
1023 goto stop;
1024
1025// Unimplemented
1026
1027 case 0xFF: // force 256-entry jump table for optimization purposes
1028 c |= 1; // compiler doesn't know that this won't affect anything
1029 default:
1030 check( (unsigned) opcode < 0x100 );
1031
1032 #ifdef UNIMPL_INSTR
1033 UNIMPL_INSTR();
1034 #endif
1035
1036 // At least skip over proper number of bytes instruction uses
1037 static unsigned char const illop_lens [8] = {
1038 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0
1039 };
1040 int opcode = instr [-1];
1041 int len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3;
1042 if ( opcode == 0x9C )
1043 len = 2;
1044 pc += len;
1045
1046 // Account for extra clock
1047 if ( (opcode >> 4) == 0x0B )
1048 {
1049 if ( opcode == 0xB3 )
1050 data = READ_LOW( data );
1051 if ( opcode != 0xB7 )
1052 PAGE_PENALTY( data + y );
1053 }
1054 goto loop;
1055 }
1056 assert( false ); // catch missing 'goto loop' or accidental 'break'
1057
1058 int result_;
1059handle_brk:
1060 pc++;
1061 result_ = b10 | 4;
1062
1063#ifdef CPU_DONE
1064interrupt:
1065#endif
1066 {
1067 s_time += 7;
1068
1069 // Save PC and read vector
1070 WRITE_STACK( SP( -1 ), pc >> 8 );
1071 WRITE_STACK( SP( -2 ), pc );
1072 pc = GET_LE16( &READ_CODE( 0xFFFA ) + (result_ & 4) );
1073
1074 // Save flags
1075 int temp;
1076 GET_FLAGS( temp );
1077 temp |= r20 + (result_ & b10); // B flag set for BRK
1078 sp = SP( -3 );
1079 WRITE_STACK( sp, temp );
1080
1081 // Update I flag in externally-visible flags
1082 cpu->r.flags = (flags |= i04);
1083
1084 // Update time
1085 int delta = s.base - cpu->end_time;
1086 if ( delta >= 0 )
1087 goto loop;
1088 s_time += delta;
1089 s.base = cpu->end_time;
1090 goto loop;
1091 }
1092
1093out_of_time:
1094 pc--;
1095
1096 // Optional action that triggers interrupt or changes irq/end time
1097 #ifdef CPU_DONE
1098 {
1099 CPU_DONE( result_ );
1100 if ( result_ >= 0 )
1101 goto interrupt;
1102 if ( s_time < 0 )
1103 goto loop;
1104 }
1105 #endif
1106stop:
1107
1108 // Flush cached state
1109 cpu->r.pc = pc;
1110 cpu->r.sp = GET_SP();
1111 cpu->r.a = a;
1112 cpu->r.x = x;
1113 cpu->r.y = y;
1114
1115 int temp;
1116 GET_FLAGS( temp );
1117 cpu->r.flags = temp;
1118
1119 cpu->cpu_state_.base = s.base;
1120 cpu->cpu_state_.time = s_time;
1121 cpu->cpu_state = &cpu->cpu_state_;
1122}
diff --git a/apps/codecs/libgme/nes_fds_apu.c b/apps/codecs/libgme/nes_fds_apu.c
new file mode 100644
index 0000000000..51421415e6
--- /dev/null
+++ b/apps/codecs/libgme/nes_fds_apu.c
@@ -0,0 +1,291 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "nes_fds_apu.h"
4
5/* Copyright (C) 2006 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18int const fract_range = 65536;
19
20void Fds_init( struct Nes_Fds_Apu* this )
21{
22 Synth_init( &this->synth );
23
24 this->lfo_tempo = lfo_base_tempo;
25 Fds_set_output( this, 0, NULL );
26 Fds_volume( this, 1.0 );
27 Fds_reset( this );
28}
29
30void Fds_reset( struct Nes_Fds_Apu* this )
31{
32 memset( this->regs_, 0, sizeof this->regs_ );
33 memset( this->mod_wave, 0, sizeof this->mod_wave );
34
35 this->last_time = 0;
36 this->env_delay = 0;
37 this->sweep_delay = 0;
38 this->wave_pos = 0;
39 this->last_amp = 0;
40 this->wave_fract = fract_range;
41 this->mod_fract = fract_range;
42 this->mod_pos = 0;
43 this->mod_write_pos = 0;
44
45 static byte const initial_regs [0x0B] ICONST_ATTR = {
46 0x80, // disable envelope
47 0, 0, 0xC0, // disable wave and lfo
48 0x80, // disable sweep
49 0, 0, 0x80, // disable modulation
50 0, 0, 0xFF // LFO period // TODO: use 0xE8 as FDS ROM does?
51 };
52 int i;
53 for ( i = 0; i < (int) sizeof initial_regs; i++ )
54 {
55 // two writes to set both gain and period for envelope registers
56 Fds_write_( this, fds_io_addr + fds_wave_size + i, 0 );
57 Fds_write_( this, fds_io_addr + fds_wave_size + i, initial_regs [i] );
58 }
59}
60
61void Fds_write_( struct Nes_Fds_Apu* this, unsigned addr, int data )
62{
63 unsigned reg = addr - fds_io_addr;
64 if ( reg < fds_io_size )
65 {
66 if ( reg < fds_wave_size )
67 {
68 if ( *regs_nes (this, 0x4089) & 0x80 )
69 this->regs_ [reg] = data & fds_wave_sample_max;
70 }
71 else
72 {
73 this->regs_ [reg] = data;
74 switch ( addr )
75 {
76 case 0x4080:
77 if ( data & 0x80 )
78 this->env_gain = data & 0x3F;
79 else
80 this->env_speed = (data & 0x3F) + 1;
81 break;
82
83 case 0x4084:
84 if ( data & 0x80 )
85 this->sweep_gain = data & 0x3F;
86 else
87 this->sweep_speed = (data & 0x3F) + 1;
88 break;
89
90 case 0x4085:
91 this->mod_pos = this->mod_write_pos;
92 *regs_nes (this, 0x4085) = data & 0x7F;
93 break;
94
95 case 0x4088:
96 if ( *regs_nes (this, 0x4087) & 0x80 )
97 {
98 int pos = this->mod_write_pos;
99 data &= 0x07;
100 this->mod_wave [pos ] = data;
101 this->mod_wave [pos + 1] = data;
102 this->mod_write_pos = (pos + 2) & (fds_wave_size - 1);
103 this->mod_pos = (this->mod_pos + 2) & (fds_wave_size - 1);
104 }
105 break;
106 }
107 }
108 }
109}
110
111void Fds_set_tempo( struct Nes_Fds_Apu* this, double t )
112{
113 this->lfo_tempo = lfo_base_tempo;
114 if ( t != 1.0 )
115 {
116 this->lfo_tempo = (int) ((double) lfo_base_tempo / t + 0.5);
117 if ( this->lfo_tempo <= 0 )
118 this->lfo_tempo = 1;
119 }
120}
121
122void Fds_run_until( struct Nes_Fds_Apu* this, blip_time_t final_end_time )
123{
124 int const wave_freq = (*regs_nes (this, 0x4083) & 0x0F) * 0x100 + *regs_nes (this, 0x4082);
125 struct Blip_Buffer* const output_ = this->output_;
126 if ( wave_freq && output_ && !((*regs_nes (this, 0x4089) | *regs_nes (this, 0x4083)) & 0x80) )
127 {
128 Blip_set_modified( output_ );
129
130 // master_volume
131 #define MVOL_ENTRY( percent ) (fds_master_vol_max * percent + 50) / 100
132 static unsigned char const master_volumes [4] = {
133 MVOL_ENTRY( 100 ), MVOL_ENTRY( 67 ), MVOL_ENTRY( 50 ), MVOL_ENTRY( 40 )
134 };
135 int const master_volume = master_volumes [*regs_nes (this, 0x4089) & 0x03];
136
137 // lfo_period
138 blip_time_t lfo_period = *regs_nes (this, 0x408A) * this->lfo_tempo;
139 if ( *regs_nes (this, 0x4083) & 0x40 )
140 lfo_period = 0;
141
142 // sweep setup
143 blip_time_t sweep_time = this->last_time + this->sweep_delay;
144 blip_time_t const sweep_period = lfo_period * this->sweep_speed;
145 if ( !sweep_period || *regs_nes (this, 0x4084) & 0x80 )
146 sweep_time = final_end_time;
147
148 // envelope setup
149 blip_time_t env_time = this->last_time + this->env_delay;
150 blip_time_t const env_period = lfo_period * this->env_speed;
151 if ( !env_period || *regs_nes (this, 0x4080) & 0x80 )
152 env_time = final_end_time;
153
154 // modulation
155 int mod_freq = 0;
156 if ( !(*regs_nes (this, 0x4087) & 0x80) )
157 mod_freq = (*regs_nes (this, 0x4087) & 0x0F) * 0x100 + *regs_nes (this, 0x4086);
158
159 blip_time_t end_time = this->last_time;
160 do
161 {
162 // sweep
163 if ( sweep_time <= end_time )
164 {
165 sweep_time += sweep_period;
166 int mode = *regs_nes (this, 0x4084) >> 5 & 2;
167 int new_sweep_gain = this->sweep_gain + mode - 1;
168 if ( (unsigned) new_sweep_gain <= (unsigned) 0x80 >> mode )
169 this->sweep_gain = new_sweep_gain;
170 else
171 *regs_nes (this, 0x4084) |= 0x80; // optimization only
172 }
173
174 // envelope
175 if ( env_time <= end_time )
176 {
177 env_time += env_period;
178 int mode = *regs_nes (this, 0x4080) >> 5 & 2;
179 int new_env_gain = this->env_gain + mode - 1;
180 if ( (unsigned) new_env_gain <= (unsigned) 0x80 >> mode )
181 this->env_gain = new_env_gain;
182 else
183 *regs_nes (this, 0x4080) |= 0x80; // optimization only
184 }
185
186 // new end_time
187 blip_time_t const start_time = end_time;
188 end_time = final_end_time;
189 if ( end_time > env_time ) end_time = env_time;
190 if ( end_time > sweep_time ) end_time = sweep_time;
191
192 // frequency modulation
193 int freq = wave_freq;
194 if ( mod_freq )
195 {
196 // time of next modulation clock
197 blip_time_t mod_time = start_time + (this->mod_fract + mod_freq - 1) / mod_freq;
198 if ( end_time > mod_time )
199 end_time = mod_time;
200
201 // run modulator up to next clock and save old sweep_bias
202 int sweep_bias = *regs_nes (this, 0x4085);
203 this->mod_fract -= (end_time - start_time) * mod_freq;
204 if ( this->mod_fract <= 0 )
205 {
206 this->mod_fract += fract_range;
207 check( (unsigned) this->mod_fract <= fract_range );
208
209 static short const mod_table [8] = { 0, +1, +2, +4, 0, -4, -2, -1 };
210 int mod = this->mod_wave [this->mod_pos];
211 this->mod_pos = (this->mod_pos + 1) & (fds_wave_size - 1);
212 int new_sweep_bias = (sweep_bias + mod_table [mod]) & 0x7F;
213 if ( mod == 4 )
214 new_sweep_bias = 0;
215 *regs_nes (this, 0x4085) = new_sweep_bias;
216 }
217
218 // apply frequency modulation
219 sweep_bias = (sweep_bias ^ 0x40) - 0x40;
220 int factor = sweep_bias * this->sweep_gain;
221 int extra = factor & 0x0F;
222 factor >>= 4;
223 if ( extra )
224 {
225 factor--;
226 if ( sweep_bias >= 0 )
227 factor += 3;
228 }
229 if ( factor > 193 ) factor -= 258;
230 if ( factor < -64 ) factor += 256;
231 freq += (freq * factor) >> 6;
232 if ( freq <= 0 )
233 continue;
234 }
235
236 // wave
237 int wave_fract = this->wave_fract;
238 blip_time_t delay = (wave_fract + freq - 1) / freq;
239 blip_time_t time = start_time + delay;
240
241 if ( time <= end_time )
242 {
243 // at least one wave clock within start_time...end_time
244
245 blip_time_t const min_delay = fract_range / freq;
246 int wave_pos = this->wave_pos;
247
248 int volume = this->env_gain;
249 if ( volume > fds_vol_max )
250 volume = fds_vol_max;
251 volume *= master_volume;
252
253 int const min_fract = min_delay * freq;
254
255 do
256 {
257 // clock wave
258 int amp = this->regs_ [wave_pos] * volume;
259 wave_pos = (wave_pos + 1) & (fds_wave_size - 1);
260 int delta = amp - this->last_amp;
261 if ( delta )
262 {
263 this->last_amp = amp;
264 Synth_offset_inline( &this->synth, time, delta, output_ );
265 }
266
267 wave_fract += fract_range - delay * freq;
268 check( unsigned (fract_range - wave_fract) < freq );
269
270 // delay until next clock
271 delay = min_delay;
272 if ( wave_fract > min_fract )
273 delay++;
274 check( delay && delay == (wave_fract + freq - 1) / freq );
275
276 time += delay;
277 }
278 while ( time <= end_time ); // TODO: using < breaks things, but <= is wrong
279
280 this->wave_pos = wave_pos;
281 }
282 this->wave_fract = wave_fract - (end_time - (time - delay)) * freq;
283 check( this->wave_fract > 0 );
284 }
285 while ( end_time < final_end_time );
286
287 this->env_delay = env_time - final_end_time; check( env_delay >= 0 );
288 this->sweep_delay = sweep_time - final_end_time; check( sweep_delay >= 0 );
289 }
290 this->last_time = final_end_time;
291}
diff --git a/apps/codecs/libgme/nes_fds_apu.h b/apps/codecs/libgme/nes_fds_apu.h
new file mode 100644
index 0000000000..1360e443db
--- /dev/null
+++ b/apps/codecs/libgme/nes_fds_apu.h
@@ -0,0 +1,116 @@
1// NES FDS sound chip emulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef NES_FDS_APU_H
5#define NES_FDS_APU_H
6
7#include "blargg_common.h"
8#include "blip_buffer.h"
9
10enum { lfo_base_tempo = 8 };
11enum { fds_osc_count = 1 };
12
13enum { fds_io_addr = 0x4040 };
14enum { fds_io_size = 0x53 };
15
16enum { fds_wave_size = 0x40 };
17enum { fds_master_vol_max = 10 };
18enum { fds_vol_max = 0x20 };
19enum { fds_wave_sample_max = 0x3F };
20
21struct Nes_Fds_Apu {
22 unsigned char regs_ [fds_io_size];// last written value to registers
23 int lfo_tempo; // normally 8; adjusted by set_tempo()
24
25 int env_delay;
26 int env_speed;
27 int env_gain;
28
29 int sweep_delay;
30 int sweep_speed;
31 int sweep_gain;
32
33 int wave_pos;
34 int last_amp;
35 blip_time_t wave_fract;
36
37 int mod_fract;
38 int mod_pos;
39 int mod_write_pos;
40 unsigned char mod_wave [fds_wave_size];
41
42 // synthesis
43 blip_time_t last_time;
44 struct Blip_Buffer* output_;
45 struct Blip_Synth synth;
46};
47
48// init
49void Fds_init( struct Nes_Fds_Apu* this );
50// setup
51void Fds_set_tempo( struct Nes_Fds_Apu* this, double t );
52
53// emulation
54void Fds_reset( struct Nes_Fds_Apu* this );
55
56static inline void Fds_volume( struct Nes_Fds_Apu* this, double v )
57{
58 Synth_volume( &this->synth, 0.14 / fds_master_vol_max / fds_vol_max / fds_wave_sample_max * v );
59}
60
61static inline void Fds_set_output( struct Nes_Fds_Apu* this, int i, struct Blip_Buffer* b )
62{
63#if defined(ROCKBOX)
64 (void) i;
65#endif
66
67 assert( (unsigned) i < fds_osc_count );
68 this->output_ = b;
69}
70
71void Fds_run_until( struct Nes_Fds_Apu* this, blip_time_t ) ICODE_ATTR;
72static inline void Fds_end_frame( struct Nes_Fds_Apu* this, blip_time_t end_time )
73{
74 if ( end_time > this->last_time )
75 Fds_run_until( this, end_time );
76 this->last_time -= end_time;
77 assert( this->last_time >= 0 );
78}
79
80void Fds_write_( struct Nes_Fds_Apu* this, unsigned addr, int data ) ICODE_ATTR;
81static inline void Fds_write( struct Nes_Fds_Apu* this, blip_time_t time, unsigned addr, int data )
82{
83 Fds_run_until( this, time );
84 Fds_write_( this, addr, data );
85}
86
87static inline int Fds_read( struct Nes_Fds_Apu* this, blip_time_t time, unsigned addr )
88{
89 Fds_run_until( this, time );
90
91 int result = 0xFF;
92 switch ( addr )
93 {
94 case 0x4090:
95 result = this->env_gain;
96 break;
97
98 case 0x4092:
99 result = this->sweep_gain;
100 break;
101
102 default:
103 {
104 unsigned i = addr - fds_io_addr;
105 if ( i < fds_wave_size )
106 result = this->regs_ [i];
107 }
108 }
109
110 return result | 0x40;
111}
112
113// allow access to registers by absolute address (i.e. 0x4080)
114static inline unsigned char* regs_nes( struct Nes_Fds_Apu* this, unsigned addr ) { return &this->regs_ [addr - fds_io_addr]; }
115
116#endif
diff --git a/apps/codecs/libgme/nes_fme7_apu.c b/apps/codecs/libgme/nes_fme7_apu.c
new file mode 100644
index 0000000000..cb5ed93be5
--- /dev/null
+++ b/apps/codecs/libgme/nes_fme7_apu.c
@@ -0,0 +1,135 @@
1// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/
2
3#include "nes_fme7_apu.h"
4
5#include <string.h>
6
7/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
8can redistribute it and/or modify it under the terms of the GNU Lesser
9General Public License as published by the Free Software Foundation; either
10version 2.1 of the License, or (at your option) any later version. This
11module is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14details. You should have received a copy of the GNU Lesser General Public
15License along with this module; if not, write to the Free Software Foundation,
16Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17
18#include "blargg_source.h"
19
20void Fme7_init( struct Nes_Fme7_Apu* this )
21{
22 Synth_init( &this->synth );
23
24 Fme7_output( this, NULL );
25 Fme7_volume( this, 1.0 );
26 Fme7_reset( this );
27}
28
29void Fme7_reset( struct Nes_Fme7_Apu* this )
30{
31 this->last_time = 0;
32
33 int i;
34 for ( i = 0; i < fme7_osc_count; i++ )
35 this->oscs [i].last_amp = 0;
36
37 this->latch = 0;
38 memset( this->regs, 0, sizeof this->regs);
39 memset( this->phases, 0, sizeof this->phases );
40 memset( this->delays, 0, sizeof this->delays );
41}
42
43static unsigned char const amp_table [16] ICONST_ATTR =
44{
45 #define ENTRY( n ) (unsigned char) (n * amp_range + 0.5)
46 ENTRY(0.0000), ENTRY(0.0078), ENTRY(0.0110), ENTRY(0.0156),
47 ENTRY(0.0221), ENTRY(0.0312), ENTRY(0.0441), ENTRY(0.0624),
48 ENTRY(0.0883), ENTRY(0.1249), ENTRY(0.1766), ENTRY(0.2498),
49 ENTRY(0.3534), ENTRY(0.4998), ENTRY(0.7070), ENTRY(1.0000)
50 #undef ENTRY
51};
52
53void Fme7_run_until( struct Nes_Fme7_Apu* this, blip_time_t end_time )
54{
55 require( end_time >= this->last_time );
56
57 int index;
58 for ( index = 0; index < fme7_osc_count; index++ )
59 {
60 int mode = this->regs [7] >> index;
61 int vol_mode = this->regs [010 + index];
62 int volume = amp_table [vol_mode & 0x0F];
63
64 struct Blip_Buffer* const osc_output = this->oscs [index].output;
65 if ( !osc_output )
66 continue;
67 /* osc_output->set_modified(); */
68 Blip_set_modified( osc_output );
69
70 // check for unsupported mode
71 #ifndef NDEBUG
72 if ( (mode & 011) <= 001 && vol_mode & 0x1F )
73 debug_printf( "FME7 used unimplemented sound mode: %02X, vol_mode: %02X\n",
74 mode, vol_mode & 0x1F );
75 #endif
76
77 if ( (mode & 001) | (vol_mode & 0x10) )
78 volume = 0; // noise and envelope aren't supported
79
80 // period
81 int const period_factor = 16;
82 unsigned period = (this->regs [index * 2 + 1] & 0x0F) * 0x100 * period_factor +
83 this->regs [index * 2] * period_factor;
84 if ( period < 50 ) // around 22 kHz
85 {
86 volume = 0;
87 if ( !period ) // on my AY-3-8910A, period doesn't have extra one added
88 period = period_factor;
89 }
90
91 // current amplitude
92 int amp = volume;
93 if ( !this->phases [index] )
94 amp = 0;
95 {
96 int delta = amp - this->oscs [index].last_amp;
97 if ( delta )
98 {
99 this->oscs [index].last_amp = amp;
100 Synth_offset( &this->synth, this->last_time, delta, osc_output );
101 }
102 }
103
104 blip_time_t time = this->last_time + this->delays [index];
105 if ( time < end_time )
106 {
107 int delta = amp * 2 - volume;
108 if ( volume )
109 {
110 do
111 {
112 delta = -delta;
113 Synth_offset_inline( &this->synth, time, delta, osc_output );
114 time += period;
115 }
116 while ( time < end_time );
117
118 this->oscs [index].last_amp = (delta + volume) >> 1;
119 this->phases [index] = (delta > 0);
120 }
121 else
122 {
123 // maintain phase when silent
124 int count = (end_time - time + period - 1) / period;
125 this->phases [index] ^= count & 1;
126 time += (blargg_long) count * period;
127 }
128 }
129
130 this->delays [index] = time - end_time;
131 }
132
133 this->last_time = end_time;
134}
135
diff --git a/apps/codecs/libgme/nes_fme7_apu.h b/apps/codecs/libgme/nes_fme7_apu.h
new file mode 100644
index 0000000000..47b93e5cfe
--- /dev/null
+++ b/apps/codecs/libgme/nes_fme7_apu.h
@@ -0,0 +1,90 @@
1// Sunsoft FME-7 sound emulator
2
3// Game_Music_Emu 0.5.5
4#ifndef NES_FME7_APU_H
5#define NES_FME7_APU_H
6
7#include "blargg_common.h"
8#include "blip_buffer.h"
9
10enum { fme7_reg_count = 14 };
11
12// Mask and addresses of registers
13enum { fme7_addr_mask = 0xE000 };
14enum { fme7_data_addr = 0xE000 };
15enum { fme7_latch_addr = 0xC000 };
16enum { fme7_osc_count = 3 };
17
18enum { amp_range = 192 }; // can be any value; this gives best error/quality tradeoff
19
20struct osc_t {
21 struct Blip_Buffer* output;
22 int last_amp;
23};
24
25// static unsigned char const amp_table [16];
26
27struct Nes_Fme7_Apu {
28 // fme7 apu state
29 uint8_t regs [fme7_reg_count];
30 uint8_t phases [3]; // 0 or 1
31 uint8_t latch;
32 uint16_t delays [3]; // a, b, c
33
34 struct osc_t oscs [fme7_osc_count];
35 blip_time_t last_time;
36
37 struct Blip_Synth synth;
38};
39
40// See Nes_Apu.h for reference
41void Fme7_init( struct Nes_Fme7_Apu* this );
42void Fme7_reset( struct Nes_Fme7_Apu* this );
43
44static inline void Fme7_volume( struct Nes_Fme7_Apu* this, double v )
45{
46 Synth_volume( &this->synth, 0.38 / amp_range * v ); // to do: fine-tune
47}
48
49static inline void Fme7_osc_output( struct Nes_Fme7_Apu* this, int i, struct Blip_Buffer* buf )
50{
51 assert( (unsigned) i < fme7_osc_count );
52 this->oscs [i].output = buf;
53}
54
55static inline void Fme7_output( struct Nes_Fme7_Apu* this, struct Blip_Buffer* buf )
56{
57 int i;
58 for ( i = 0; i < fme7_osc_count; i++ )
59 Fme7_osc_output( this, i, buf );
60}
61
62// (addr & addr_mask) == latch_addr
63static inline void Fme7_write_latch( struct Nes_Fme7_Apu* this, int data ) { this->latch = data; }
64
65// (addr & addr_mask) == data_addr
66void Fme7_run_until( struct Nes_Fme7_Apu* this, blip_time_t end_time ) ICODE_ATTR;
67static inline void Fme7_write_data( struct Nes_Fme7_Apu* this, blip_time_t time, int data )
68{
69 if ( (unsigned) this->latch >= fme7_reg_count )
70 {
71 #ifdef debug_printf
72 debug_printf( "FME7 write to %02X (past end of sound registers)\n", (int) latch );
73 #endif
74 return;
75 }
76
77 Fme7_run_until( this, time );
78 this->regs [this->latch] = data;
79}
80
81static inline void Fme7_end_frame( struct Nes_Fme7_Apu* this, blip_time_t time )
82{
83 if ( time > this->last_time )
84 Fme7_run_until( this, time );
85
86 assert( this->last_time >= time );
87 this->last_time -= time;
88}
89
90#endif
diff --git a/apps/codecs/libgme/nes_mmc5_apu.h b/apps/codecs/libgme/nes_mmc5_apu.h
new file mode 100644
index 0000000000..b696b49e97
--- /dev/null
+++ b/apps/codecs/libgme/nes_mmc5_apu.h
@@ -0,0 +1,61 @@
1// NES MMC5 sound chip emulator
2
3// Nes_Snd_Emu 0.2.0-pre
4#ifndef NES_MMC5_APU_H
5#define NES_MMC5_APU_H
6
7#include "blargg_common.h"
8#include "nes_apu.h"
9
10enum { mmc5_regs_addr = 0x5000 };
11enum { mmc5_regs_size = 0x16 };
12enum { mmc5_osc_count = 3 };
13enum { mmc5_exram_size = 1024 };
14
15struct Nes_Mmc5_Apu {
16 struct Nes_Apu apu;
17 unsigned char exram [mmc5_exram_size];
18};
19
20static inline void Mmc5_init( struct Nes_Mmc5_Apu* this )
21{
22 Apu_init( &this->apu );
23}
24
25static inline void Mmc5_set_output( struct Nes_Mmc5_Apu* this, int i, struct Blip_Buffer* b )
26{
27 // in: square 1, square 2, PCM
28 // out: square 1, square 2, skipped, skipped, PCM
29 if ( i > 1 )
30 i += 2;
31 Apu_osc_output( &this->apu, i, b );
32}
33
34static inline void Mmc5_write_register( struct Nes_Mmc5_Apu* this, blip_time_t time, unsigned addr, int data )
35{
36 switch ( addr )
37 {
38 case 0x5015: // channel enables
39 data &= 0x03; // enable the square waves only
40 // fall through
41 case 0x5000: // Square 1
42 case 0x5002:
43 case 0x5003:
44 case 0x5004: // Square 2
45 case 0x5006:
46 case 0x5007:
47 case 0x5011: // DAC
48 Apu_write_register( &this->apu, time, addr - 0x1000, data );
49 break;
50
51 case 0x5010: // some things write to this for some reason
52 break;
53
54#ifdef BLARGG_DEBUG_H
55 default:
56 dprintf( "Unmapped MMC5 APU write: $%04X <- $%02X\n", addr, data );
57#endif
58 }
59}
60
61#endif
diff --git a/apps/codecs/libgme/nes_namco_apu.c b/apps/codecs/libgme/nes_namco_apu.c
new file mode 100644
index 0000000000..0fca501eff
--- /dev/null
+++ b/apps/codecs/libgme/nes_namco_apu.c
@@ -0,0 +1,133 @@
1// Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/
2
3#include "nes_namco_apu.h"
4
5/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18void Namco_init( struct Nes_Namco_Apu* this )
19{
20 Synth_init( &this->synth );
21
22 Namco_output( this, NULL );
23 Namco_volume( this, 1.0 );
24 Namco_reset( this );
25}
26
27void Namco_reset( struct Nes_Namco_Apu* this )
28{
29 this->last_time = 0;
30 this->addr_reg = 0;
31
32 int i;
33 for ( i = 0; i < namco_reg_count; i++ )
34 this->reg [i] = 0;
35
36 for ( i = 0; i < namco_osc_count; i++ )
37 {
38 struct Namco_Osc* osc = &this->oscs [i];
39 osc->delay = 0;
40 osc->last_amp = 0;
41 osc->wave_pos = 0;
42 }
43}
44
45void Namco_output( struct Nes_Namco_Apu* this, struct Blip_Buffer* buf )
46{
47 int i;
48 for ( i = 0; i < namco_osc_count; i++ )
49 Namco_osc_output( this, i, buf );
50}
51
52void Namco_end_frame( struct Nes_Namco_Apu* this, blip_time_t time )
53{
54 if ( time > this->last_time )
55 Namco_run_until( this, time );
56
57 assert( this->last_time >= time );
58 this->last_time -= time;
59}
60
61void Namco_run_until( struct Nes_Namco_Apu* this, blip_time_t nes_end_time )
62{
63 int active_oscs = (this->reg [0x7F] >> 4 & 7) + 1;
64 int i;
65 for ( i = namco_osc_count - active_oscs; i < namco_osc_count; i++ )
66 {
67 struct Namco_Osc* osc = &this->oscs [i];
68 struct Blip_Buffer* output = osc->output;
69 if ( !output )
70 continue;
71 /* output->set_modified(); */
72 Blip_set_modified( output );
73
74 blip_resampled_time_t time =
75 Blip_resampled_time( output, this->last_time ) + osc->delay;
76 blip_resampled_time_t end_time = Blip_resampled_time( output, nes_end_time );
77 osc->delay = 0;
78 if ( time < end_time )
79 {
80 const uint8_t* osc_reg = &this->reg [i * 8 + 0x40];
81 if ( !(osc_reg [4] & 0xE0) )
82 continue;
83
84 int volume = osc_reg [7] & 15;
85 if ( !volume )
86 continue;
87
88 blargg_long freq = (osc_reg [4] & 3) * 0x10000 + osc_reg [2] * 0x100L + osc_reg [0];
89 if ( freq < 64 * active_oscs )
90 continue; // prevent low frequencies from excessively delaying freq changes
91 blip_resampled_time_t period =
92 /* output->resampled_duration( 983040 ) / freq * active_oscs; */
93 Blip_resampled_duration( output, 983040 ) / freq * active_oscs;
94
95 int wave_size = 32 - (osc_reg [4] >> 2 & 7) * 4;
96 if ( !wave_size )
97 continue;
98
99 int last_amp = osc->last_amp;
100 int wave_pos = osc->wave_pos;
101
102 do
103 {
104 // read wave sample
105 int addr = wave_pos + osc_reg [6];
106 int sample = this->reg [addr >> 1] >> (addr << 2 & 4);
107 wave_pos++;
108 sample = (sample & 15) * volume;
109
110 // output impulse if amplitude changed
111 int delta = sample - last_amp;
112 if ( delta )
113 {
114 last_amp = sample;
115 Synth_offset_resampled( &this->synth, time, delta, output );
116 }
117
118 // next sample
119 time += period;
120 if ( wave_pos >= wave_size )
121 wave_pos = 0;
122 }
123 while ( time < end_time );
124
125 osc->wave_pos = wave_pos;
126 osc->last_amp = last_amp;
127 }
128 osc->delay = time - end_time;
129 }
130
131 this->last_time = nes_end_time;
132}
133
diff --git a/apps/codecs/libgme/nes_namco_apu.h b/apps/codecs/libgme/nes_namco_apu.h
new file mode 100644
index 0000000000..b53b69808b
--- /dev/null
+++ b/apps/codecs/libgme/nes_namco_apu.h
@@ -0,0 +1,71 @@
1// Namco 106 sound chip emulator
2
3// Nes_Snd_Emu 0.1.8
4#ifndef NES_NAMCO_APU_H
5#define NES_NAMCO_APU_H
6
7#include "blargg_common.h"
8#include "blip_buffer.h"
9
10struct namco_state_t;
11
12enum { namco_osc_count = 8 };
13enum { namco_addr_reg_addr = 0xF800 };
14enum { namco_data_reg_addr = 0x4800 };
15enum { namco_reg_count = 0x80 };
16
17struct Namco_Osc {
18 blargg_long delay;
19 struct Blip_Buffer* output;
20 short last_amp;
21 short wave_pos;
22};
23
24struct Nes_Namco_Apu {
25 struct Namco_Osc oscs [namco_osc_count];
26
27 blip_time_t last_time;
28 int addr_reg;
29
30 uint8_t reg [namco_reg_count];
31
32 struct Blip_Synth synth;
33};
34
35// See Nes_Apu.h for reference.
36void Namco_init( struct Nes_Namco_Apu* this );
37void Namco_output( struct Nes_Namco_Apu* this, struct Blip_Buffer* );
38
39void Namco_reset( struct Nes_Namco_Apu* this );
40void Namco_end_frame( struct Nes_Namco_Apu* this, blip_time_t ) ICODE_ATTR;
41
42static inline uint8_t* namco_access( struct Nes_Namco_Apu* this )
43{
44 int addr = this->addr_reg & 0x7F;
45 if ( this->addr_reg & 0x80 )
46 this->addr_reg = (addr + 1) | 0x80;
47 return &this->reg [addr];
48}
49
50static inline void Namco_volume( struct Nes_Namco_Apu* this, double v ) { Synth_volume( &this->synth, 0.10 / namco_osc_count * v / 15.0 ); }
51
52// Write-only address register is at 0xF800
53static inline void Namco_write_addr( struct Nes_Namco_Apu* this, int v ) { this->addr_reg = v; }
54
55static inline int Namco_read_data( struct Nes_Namco_Apu* this ) { return *namco_access( this ); }
56
57static inline void Namco_osc_output( struct Nes_Namco_Apu* this, int i, struct Blip_Buffer* buf )
58{
59 assert( (unsigned) i < namco_osc_count );
60 this->oscs [i].output = buf;
61}
62
63// Read/write data register is at 0x4800
64void Namco_run_until( struct Nes_Namco_Apu* this, blip_time_t ) ICODE_ATTR;
65static inline void Namco_write_data( struct Nes_Namco_Apu* this, blip_time_t time, int data )
66{
67 Namco_run_until( this, time );
68 *namco_access( this ) = data;
69}
70
71#endif
diff --git a/apps/codecs/libgme/nes_oscs.c b/apps/codecs/libgme/nes_oscs.c
new file mode 100644
index 0000000000..f04d5fa9ad
--- /dev/null
+++ b/apps/codecs/libgme/nes_oscs.c
@@ -0,0 +1,583 @@
1// Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/
2
3#include "nes_apu.h"
4
5/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18// Nes_Osc
19
20void Osc_clock_length( struct Nes_Osc* this, int halt_mask )
21{
22 if ( this->length_counter && !(this->regs [0] & halt_mask) )
23 this->length_counter--;
24}
25
26// Nes_Square
27
28void Square_clock_envelope( struct Nes_Square* this )
29{
30 struct Nes_Osc* osc = &this->osc;
31 int period = osc->regs [0] & 15;
32 if ( osc->reg_written [3] ) {
33 osc->reg_written [3] = false;
34 this->env_delay = period;
35 this->envelope = 15;
36 }
37 else if ( --this->env_delay < 0 ) {
38 this->env_delay = period;
39 if ( this->envelope | (osc->regs [0] & 0x20) )
40 this->envelope = (this->envelope - 1) & 15;
41 }
42}
43
44int Square_volume( struct Nes_Square* this )
45{
46 struct Nes_Osc* osc = &this->osc;
47 return osc->length_counter == 0 ? 0 : (osc->regs [0] & 0x10) ? (osc->regs [0] & 15) : this->envelope;
48}
49
50void Square_clock_sweep( struct Nes_Square* this, int negative_adjust )
51{
52 struct Nes_Osc* osc = &this->osc;
53 int sweep = osc->regs [1];
54
55 if ( --this->sweep_delay < 0 )
56 {
57 osc->reg_written [1] = true;
58
59 int period = Osc_period( osc );
60 int shift = sweep & shift_mask;
61 if ( shift && (sweep & 0x80) && period >= 8 )
62 {
63 int offset = period >> shift;
64
65 if ( sweep & negate_flag )
66 offset = negative_adjust - offset;
67
68 if ( period + offset < 0x800 )
69 {
70 period += offset;
71 // rewrite period
72 osc->regs [2] = period & 0xFF;
73 osc->regs [3] = (osc->regs [3] & ~7) | ((period >> 8) & 7);
74 }
75 }
76 }
77
78 if ( osc->reg_written [1] ) {
79 osc->reg_written [1] = false;
80 this->sweep_delay = (sweep >> 4) & 7;
81 }
82}
83
84// TODO: clean up
85inline nes_time_t Square_maintain_phase( struct Nes_Square* this, nes_time_t time, nes_time_t end_time,
86 nes_time_t timer_period )
87{
88 nes_time_t remain = end_time - time;
89 if ( remain > 0 )
90 {
91 int count = (remain + timer_period - 1) / timer_period;
92 this->phase = (this->phase + count) & (square_phase_range - 1);
93 time += (blargg_long) count * timer_period;
94 }
95 return time;
96}
97
98void Square_run( struct Nes_Square* this, nes_time_t time, nes_time_t end_time )
99{
100 struct Nes_Osc* osc = &this->osc;
101 const int period = Osc_period( osc );
102 const int timer_period = (period + 1) * 2;
103
104 if ( !osc->output )
105 {
106 osc->delay = Square_maintain_phase( this, time + osc->delay, end_time, timer_period ) - end_time;
107 return;
108 }
109
110 Blip_set_modified( osc->output );
111
112 int offset = period >> (osc->regs [1] & shift_mask);
113 if ( osc->regs [1] & negate_flag )
114 offset = 0;
115
116 const int volume = Square_volume( this );
117 if ( volume == 0 || period < 8 || (period + offset) >= 0x800 )
118 {
119 if ( osc->last_amp ) {
120 Synth_offset( this->synth, time, -osc->last_amp, osc->output );
121 osc->last_amp = 0;
122 }
123
124 time += osc->delay;
125 time = Square_maintain_phase( this, time, end_time, timer_period );
126 }
127 else
128 {
129 // handle duty select
130 int duty_select = (osc->regs [0] >> 6) & 3;
131 int duty = 1 << duty_select; // 1, 2, 4, 2
132 int amp = 0;
133 if ( duty_select == 3 ) {
134 duty = 2; // negated 25%
135 amp = volume;
136 }
137 if ( this->phase < duty )
138 amp ^= volume;
139
140 {
141 int delta = Osc_update_amp( osc, amp );
142 if ( delta )
143 Synth_offset( this->synth, time, delta, osc->output );
144 }
145
146 time += osc->delay;
147 if ( time < end_time )
148 {
149 struct Blip_Buffer* const output = osc->output;
150 Synth* synth = this->synth;
151 int delta = amp * 2 - volume;
152 int phase = this->phase;
153
154 do {
155 phase = (phase + 1) & (square_phase_range - 1);
156 if ( phase == 0 || phase == duty ) {
157 delta = -delta;
158 Synth_offset_inline( synth, time, delta, output );
159 }
160 time += timer_period;
161 }
162 while ( time < end_time );
163
164 osc->last_amp = (delta + volume) >> 1;
165 this->phase = phase;
166 }
167 }
168
169 osc->delay = time - end_time;
170}
171
172// Nes_Triangle
173
174void Triangle_clock_linear_counter( struct Nes_Triangle* this )
175{
176 struct Nes_Osc* osc = &this->osc;
177 if ( osc->reg_written [3] )
178 this->linear_counter = osc->regs [0] & 0x7F;
179 else if ( this->linear_counter )
180 this->linear_counter--;
181
182 if ( !(osc->regs [0] & 0x80) )
183 osc->reg_written [3] = false;
184}
185
186inline int Triangle_calc_amp( struct Nes_Triangle* this )
187{
188 int amp = Triangle_phase_range - this->phase;
189 if ( amp < 0 )
190 amp = this->phase - (Triangle_phase_range + 1);
191 return amp;
192}
193
194// TODO: clean up
195inline nes_time_t Triangle_maintain_phase( struct Nes_Triangle* this, nes_time_t time, nes_time_t end_time,
196 nes_time_t timer_period )
197{
198 nes_time_t remain = end_time - time;
199 if ( remain > 0 )
200 {
201 int count = (remain + timer_period - 1) / timer_period;
202 this->phase = ((unsigned) this->phase + 1 - count) & (Triangle_phase_range * 2 - 1);
203 this->phase++;
204 time += (blargg_long) count * timer_period;
205 }
206 return time;
207}
208
209void Triangle_run( struct Nes_Triangle* this, nes_time_t time, nes_time_t end_time )
210{
211 struct Nes_Osc* osc = &this->osc;
212 const int timer_period = Osc_period( osc ) + 1;
213 if ( !osc->output )
214 {
215 time += osc->delay;
216 osc->delay = 0;
217 if ( osc->length_counter && this->linear_counter && timer_period >= 3 )
218 osc->delay = Triangle_maintain_phase( this, time, end_time, timer_period ) - end_time;
219 return;
220 }
221
222 Blip_set_modified( osc->output );
223
224 // to do: track phase when period < 3
225 // to do: Output 7.5 on dac when period < 2? More accurate, but results in more clicks.
226
227 int delta = Osc_update_amp( osc, Triangle_calc_amp( this ) );
228 if ( delta )
229 Synth_offset( &this->synth, time, delta, osc->output );
230
231 time += osc->delay;
232 if ( osc->length_counter == 0 || this->linear_counter == 0 || timer_period < 3 )
233 {
234 time = end_time;
235 }
236 else if ( time < end_time )
237 {
238 struct Blip_Buffer* const output = osc->output;
239
240 int phase = this->phase;
241 int volume = 1;
242 if ( phase > Triangle_phase_range ) {
243 phase -= Triangle_phase_range;
244 volume = -volume;
245 }
246
247 do {
248 if ( --phase == 0 ) {
249 phase = Triangle_phase_range;
250 volume = -volume;
251 }
252 else {
253 Synth_offset_inline( &this->synth, time, volume, output );
254 }
255
256 time += timer_period;
257 }
258 while ( time < end_time );
259
260 if ( volume < 0 )
261 phase += Triangle_phase_range;
262 this->phase = phase;
263 osc->last_amp = Triangle_calc_amp( this );
264 }
265 osc->delay = time - end_time;
266}
267
268// Nes_Dmc
269
270void Dmc_reset( struct Nes_Dmc* this )
271{
272 this->address = 0;
273 this->dac = 0;
274 this->buf = 0;
275 this->bits_remain = 1;
276 this->bits = 0;
277 this->buf_full = false;
278 this->silence = true;
279 this->next_irq = apu_no_irq;
280 this->irq_flag = false;
281 this->irq_enabled = false;
282
283 Osc_reset( &this->osc );
284 this->period = 0x1AC;
285}
286
287void Dmc_recalc_irq( struct Nes_Dmc* this )
288{
289 struct Nes_Osc* osc = &this->osc;
290 nes_time_t irq = apu_no_irq;
291 if ( this->irq_enabled && osc->length_counter )
292 irq = this->apu->last_dmc_time + osc->delay +
293 ((osc->length_counter - 1) * 8 + this->bits_remain - 1) * (nes_time_t) (this->period) + 1;
294 if ( irq != this->next_irq ) {
295 this->next_irq = irq;
296 Apu_irq_changed( this->apu );
297 }
298}
299
300int Dmc_count_reads( struct Nes_Dmc* this, nes_time_t time, nes_time_t* last_read )
301{
302 struct Nes_Osc* osc = &this->osc;
303 if ( last_read )
304 *last_read = time;
305
306 if ( osc->length_counter == 0 )
307 return 0; // not reading
308
309 nes_time_t first_read = Dmc_next_read_time( this );
310 nes_time_t avail = time - first_read;
311 if ( avail <= 0 )
312 return 0;
313
314 int count = (avail - 1) / (this->period * 8) + 1;
315 if ( !(osc->regs [0] & loop_flag) && count > osc->length_counter )
316 count = osc->length_counter;
317
318 if ( last_read )
319 {
320 *last_read = first_read + (count - 1) * (this->period * 8) + 1;
321 check( *last_read <= time );
322 check( count == count_reads( *last_read, NULL ) );
323 check( count - 1 == count_reads( *last_read - 1, NULL ) );
324 }
325
326 return count;
327}
328
329static short const dmc_period_table [2] [16] ICONST_ATTR = {
330 {428, 380, 340, 320, 286, 254, 226, 214, // NTSC
331 190, 160, 142, 128, 106, 84, 72, 54},
332
333 {398, 354, 316, 298, 276, 236, 210, 198, // PAL
334 176, 148, 132, 118, 98, 78, 66, 50}
335};
336
337inline void Dmc_reload_sample( struct Nes_Dmc* this )
338{
339 this->address = 0x4000 + this->osc.regs [2] * 0x40;
340 this->osc.length_counter = this->osc.regs [3] * 0x10 + 1;
341}
342
343static byte const dac_table [128] ICONST_ATTR =
344{
345 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9,10,11,12,13,14,
346 15,15,16,17,18,19,20,20,21,22,23,24,24,25,26,27,
347 27,28,29,30,31,31,32,33,33,34,35,36,36,37,38,38,
348 39,40,41,41,42,43,43,44,45,45,46,47,47,48,48,49,
349 50,50,51,52,52,53,53,54,55,55,56,56,57,58,58,59,
350 59,60,60,61,61,62,63,63,64,64,65,65,66,66,67,67,
351 68,68,69,70,70,71,71,72,72,73,73,74,74,75,75,75,
352 76,76,77,77,78,78,79,79,80,80,81,81,82,82,82,83,
353};
354
355void Dmc_write_register( struct Nes_Dmc* this, int addr, int data )
356{
357 if ( addr == 0 )
358 {
359 this->period = dmc_period_table [this->pal_mode] [data & 15];
360 this->irq_enabled = (data & 0xC0) == 0x80; // enabled only if loop disabled
361 this->irq_flag &= this->irq_enabled;
362 Dmc_recalc_irq( this );
363 }
364 else if ( addr == 1 )
365 {
366 int old_dac = this->dac;
367 this->dac = data & 0x7F;
368
369 // adjust last_amp so that "pop" amplitude will be properly non-linear
370 // with respect to change in dac
371 int faked_nonlinear = this->dac - (dac_table [this->dac] - dac_table [old_dac]);
372 if ( !this->nonlinear )
373 this->osc.last_amp = faked_nonlinear;
374 }
375}
376
377void Dmc_start( struct Nes_Dmc* this )
378{
379 Dmc_reload_sample( this );
380 Dmc_fill_buffer( this );
381 Dmc_recalc_irq( this );
382}
383
384void Dmc_fill_buffer( struct Nes_Dmc* this )
385{
386 if ( !this->buf_full && this->osc.length_counter )
387 {
388 require( this->prg_reader ); // prg_reader must be set
389 this->buf = this->prg_reader( this->prg_reader_data, 0x8000u + this->address );
390 this->address = (this->address + 1) & 0x7FFF;
391 this->buf_full = true;
392 if ( --this->osc.length_counter == 0 )
393 {
394 if ( this->osc.regs [0] & loop_flag ) {
395 Dmc_reload_sample( this );
396 }
397 else {
398 this->apu->osc_enables &= ~0x10;
399 this->irq_flag = this->irq_enabled;
400 this->next_irq = apu_no_irq;
401 Apu_irq_changed( this->apu );
402 }
403 }
404 }
405}
406
407void Dmc_run( struct Nes_Dmc* this, nes_time_t time, nes_time_t end_time )
408{
409 struct Nes_Osc* osc = &this->osc;
410 int delta = Osc_update_amp( osc, this->dac );
411 if ( !osc->output )
412 {
413 this->silence = true;
414 }
415 else
416 {
417 Blip_set_modified( osc->output );
418 if ( delta )
419 Synth_offset( &this->synth, time, delta, osc->output );
420 }
421
422 time += osc->delay;
423 if ( time < end_time )
424 {
425 int bits_remain = this->bits_remain;
426 if ( this->silence && !this->buf_full )
427 {
428 int count = (end_time - time + this->period - 1) / this->period;
429 bits_remain = (bits_remain - 1 + 8 - (count % 8)) % 8 + 1;
430 time += count * this->period;
431 }
432 else
433 {
434 struct Blip_Buffer* const output = osc->output;
435 const int period = this->period;
436 int bits = this->bits;
437 int dac = this->dac;
438
439 do
440 {
441 if ( !this->silence )
442 {
443 int step = (bits & 1) * 4 - 2;
444 bits >>= 1;
445 if ( (unsigned) (dac + step) <= 0x7F ) {
446 dac += step;
447 Synth_offset_inline( &this->synth, time, step, output );
448 }
449 }
450
451 time += period;
452
453 if ( --bits_remain == 0 )
454 {
455 bits_remain = 8;
456 if ( !this->buf_full ) {
457 this->silence = true;
458 }
459 else {
460 this->silence = false;
461 bits = this->buf;
462 this->buf_full = false;
463 if ( !output )
464 this->silence = true;
465 Dmc_fill_buffer( this );
466 }
467 }
468 }
469 while ( time < end_time );
470
471 this->dac = dac;
472 osc->last_amp = dac;
473 this->bits = bits;
474 }
475 this->bits_remain = bits_remain;
476 }
477 osc->delay = time - end_time;
478}
479
480// Nes_Noise
481
482static short const noise_period_table [16] ICONST_ATTR = {
483 0x004, 0x008, 0x010, 0x020, 0x040, 0x060, 0x080, 0x0A0,
484 0x0CA, 0x0FE, 0x17C, 0x1FC, 0x2FA, 0x3F8, 0x7F2, 0xFE4
485};
486
487void Noise_clock_envelope( struct Nes_Noise* this )
488{
489 struct Nes_Osc* osc = &this->osc;
490 int period = osc->regs [0] & 15;
491 if ( osc->reg_written [3] ) {
492 osc->reg_written [3] = false;
493 this->env_delay = period;
494 this->envelope = 15;
495 }
496 else if ( --this->env_delay < 0 ) {
497 this->env_delay = period;
498 if ( this->envelope | (osc->regs [0] & 0x20) )
499 this->envelope = (this->envelope - 1) & 15;
500 }
501}
502
503int Noise_volume( struct Nes_Noise* this )
504{
505 struct Nes_Osc* osc = &this->osc;
506 return osc->length_counter == 0 ? 0 : (osc->regs [0] & 0x10) ? (osc->regs [0] & 15) : this->envelope;
507}
508
509void Noise_run( struct Nes_Noise* this, nes_time_t time, nes_time_t end_time )
510{
511 struct Nes_Osc* osc = &this->osc;
512 int period = noise_period_table [osc->regs [2] & 15];
513
514 if ( !osc->output )
515 {
516 // TODO: clean up
517 time += osc->delay;
518 osc->delay = time + (end_time - time + period - 1) / period * period - end_time;
519 return;
520 }
521
522 Blip_set_modified( osc->output );
523
524 const int volume = Noise_volume( this );
525 int amp = (this->noise & 1) ? volume : 0;
526 {
527 int delta = Osc_update_amp( osc, amp );
528 if ( delta )
529 Synth_offset( &this->synth, time, delta, osc->output );
530 }
531
532 time += osc->delay;
533 if ( time < end_time )
534 {
535 const int mode_flag = 0x80;
536
537 if ( !volume )
538 {
539 // round to next multiple of period
540 time += (end_time - time + period - 1) / period * period;
541
542 // approximate noise cycling while muted, by shuffling up noise register
543 // to do: precise muted noise cycling?
544 if ( !(osc->regs [2] & mode_flag) ) {
545 int feedback = (this->noise << 13) ^ (this->noise << 14);
546 this->noise = (feedback & 0x4000) | (this->noise >> 1);
547 }
548 }
549 else
550 {
551 struct Blip_Buffer* const output = osc->output;
552
553 // using resampled time avoids conversion in synth.offset()
554 blip_resampled_time_t rperiod = Blip_resampled_duration( output, period );
555 blip_resampled_time_t rtime = Blip_resampled_time( output, time );
556
557 int noise = this->noise;
558 int delta = amp * 2 - volume;
559 const int tap = (osc->regs [2] & mode_flag ? 8 : 13);
560
561 do {
562 int feedback = (noise << tap) ^ (noise << 14);
563 time += period;
564
565 if ( (noise + 1) & 2 ) {
566 // bits 0 and 1 of noise differ
567 delta = -delta;
568 Synth_offset_resampled( &this->synth, rtime, delta, output );
569 }
570
571 rtime += rperiod;
572 noise = (feedback & 0x4000) | (noise >> 1);
573 }
574 while ( time < end_time );
575
576 osc->last_amp = (delta + volume) >> 1;
577 this->noise = noise;
578 }
579 }
580
581 osc->delay = time - end_time;
582}
583
diff --git a/apps/codecs/libgme/nes_oscs.h b/apps/codecs/libgme/nes_oscs.h
new file mode 100644
index 0000000000..a358e01786
--- /dev/null
+++ b/apps/codecs/libgme/nes_oscs.h
@@ -0,0 +1,165 @@
1// Private oscillators used by Nes_Apu
2
3// Nes_Snd_Emu 0.1.8
4#ifndef NES_OSCS_H
5#define NES_OSCS_H
6
7#include "blargg_common.h"
8#include "blip_buffer.h"
9#include "nes_cpu.h"
10
11struct Nes_Apu;
12
13struct Nes_Osc
14{
15 unsigned char regs [4];
16 bool reg_written [4];
17 struct Blip_Buffer* output;
18 int length_counter;// length counter (0 if unused by oscillator)
19 int delay; // delay until next (potential) transition
20 int last_amp; // last amplitude oscillator was outputting
21};
22
23void Osc_clock_length( struct Nes_Osc* this, int halt_mask );
24static inline int Osc_period( struct Nes_Osc* this )
25{
26 return (this->regs [3] & 7) * 0x100 + (this->regs [2] & 0xFF);
27}
28
29static inline void Osc_reset( struct Nes_Osc* this )
30{
31 this->delay = 0;
32 this->last_amp = 0;
33}
34
35static inline int Osc_update_amp( struct Nes_Osc* this, int amp )
36{
37 int delta = amp - this->last_amp;
38 this->last_amp = amp;
39 return delta;
40}
41
42// Nes_Square
43
44enum { negate_flag = 0x08 };
45enum { shift_mask = 0x07 };
46enum { square_phase_range = 8 };
47
48typedef struct Blip_Synth Synth;
49
50struct Nes_Square
51{
52 struct Nes_Osc osc;
53 int envelope;
54 int env_delay;
55 int phase;
56 int sweep_delay;
57
58 Synth* synth; // shared between squares
59};
60
61static inline void Square_set_synth( struct Nes_Square* this, Synth* s ) { this->synth = s; }
62
63void Square_clock_sweep( struct Nes_Square* this, int adjust );
64void Square_run( struct Nes_Square* this, nes_time_t, nes_time_t );
65
66static inline void Square_reset( struct Nes_Square* this )
67{
68 this->sweep_delay = 0;
69 this->envelope = 0;
70 this->env_delay = 0;
71 Osc_reset( &this->osc );
72}
73
74void Square_clock_envelope( struct Nes_Square* this );
75int Square_volume( struct Nes_Square* this );
76
77// Nes_Triangle
78
79enum { Triangle_phase_range = 16 };
80
81struct Nes_Triangle
82{
83 struct Nes_Osc osc;
84
85 int phase;
86 int linear_counter;
87 struct Blip_Synth synth;
88};
89
90void Triangle_run( struct Nes_Triangle* this, nes_time_t, nes_time_t );
91void Triangle_clock_linear_counter( struct Nes_Triangle* this );
92
93static inline void Triangle_reset( struct Nes_Triangle* this )
94{
95 this->linear_counter = 0;
96 this->phase = 1;
97 Osc_reset( &this->osc );
98}
99
100// Nes_Noise
101struct Nes_Noise
102{
103 struct Nes_Osc osc;
104
105 int envelope;
106 int env_delay;
107 int noise;
108 struct Blip_Synth synth;
109};
110
111void Noise_clock_envelope( struct Nes_Noise* this );
112int Noise_volume( struct Nes_Noise* this );
113void Noise_run( struct Nes_Noise* this, nes_time_t, nes_time_t );
114
115static inline void Noise_reset( struct Nes_Noise* this )
116{
117 this->noise = 1 << 14;
118 this->envelope = 0;
119 this->env_delay = 0;
120 Osc_reset( &this->osc );
121}
122
123// Nes_Dmc
124
125enum { loop_flag = 0x40 };
126
127struct Nes_Dmc
128{
129 struct Nes_Osc osc;
130
131 int address; // address of next byte to read
132 int period;
133 int buf;
134 int bits_remain;
135 int bits;
136 bool buf_full;
137 bool silence;
138
139 int dac;
140
141 nes_time_t next_irq;
142 bool irq_enabled;
143 bool irq_flag;
144 bool pal_mode;
145 bool nonlinear;
146
147 int (*prg_reader)( void*, addr_t ); // needs to be initialized to prg read function
148 void* prg_reader_data;
149
150 struct Nes_Apu* apu;
151
152 struct Blip_Synth synth;
153};
154
155void Dmc_start( struct Nes_Dmc* this );
156void Dmc_write_register( struct Nes_Dmc* this, int, int ) ICODE_ATTR;
157void Dmc_run( struct Nes_Dmc* this, nes_time_t, nes_time_t ) ICODE_ATTR;
158void Dmc_recalc_irq( struct Nes_Dmc* this ) ICODE_ATTR;
159void Dmc_fill_buffer( struct Nes_Dmc* this ) ICODE_ATTR;
160void Dmc_reload_sample( struct Nes_Dmc* this ) ICODE_ATTR;
161void Dmc_reset( struct Nes_Dmc* this ) ICODE_ATTR;
162
163int Dmc_count_reads( struct Nes_Dmc* this, nes_time_t, nes_time_t* ) ICODE_ATTR;
164
165#endif
diff --git a/apps/codecs/libgme/nes_vrc6_apu.c b/apps/codecs/libgme/nes_vrc6_apu.c
new file mode 100644
index 0000000000..0aba81e57f
--- /dev/null
+++ b/apps/codecs/libgme/nes_vrc6_apu.c
@@ -0,0 +1,191 @@
1// Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/
2
3#include "nes_vrc6_apu.h"
4
5/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18void Vrc6_init( struct Nes_Vrc6_Apu* this )
19{
20 Synth_init( &this->saw_synth );
21 Synth_init( &this->square_synth );
22
23 Vrc6_output( this, NULL );
24 Vrc6_volume( this, 1.0 );
25 Vrc6_reset( this );
26}
27
28void Vrc6_reset( struct Nes_Vrc6_Apu* this )
29{
30 this->last_time = 0;
31 int i;
32 for ( i = 0; i < vrc6_osc_count; i++ )
33 {
34 struct Vrc6_Osc* osc = &this->oscs [i];
35 int j;
36 for ( j = 0; j < vrc6_reg_count; j++ )
37 osc->regs [j] = 0;
38 osc->delay = 0;
39 osc->last_amp = 0;
40 osc->phase = 1;
41 osc->amp = 0;
42 }
43}
44
45void Vrc6_output( struct Nes_Vrc6_Apu* this, struct Blip_Buffer* buf )
46{
47 int i;
48 for ( i = 0; i < vrc6_osc_count; i++ )
49 Vrc6_osc_output( this, i, buf );
50}
51
52void run_square( struct Nes_Vrc6_Apu* this, struct Vrc6_Osc* osc, blip_time_t end_time );
53void run_saw( struct Nes_Vrc6_Apu* this, blip_time_t end_time );
54void Vrc6_run_until( struct Nes_Vrc6_Apu* this, blip_time_t time )
55{
56 require( time >= this->last_time );
57 run_square( this, &this->oscs [0], time );
58 run_square( this, &this->oscs [1], time );
59 run_saw( this, time );
60 this->last_time = time;
61}
62
63void Vrc6_write_osc( struct Nes_Vrc6_Apu* this, blip_time_t time, int osc_index, int reg, int data )
64{
65 require( (unsigned) osc_index < vrc6_osc_count );
66 require( (unsigned) reg < vrc6_reg_count );
67
68 Vrc6_run_until( this, time );
69 this->oscs [osc_index].regs [reg] = data;
70}
71
72void Vrc6_end_frame( struct Nes_Vrc6_Apu* this, blip_time_t time )
73{
74 if ( time > this->last_time )
75 Vrc6_run_until( this, time );
76
77 assert( this->last_time >= time );
78 this->last_time -= time;
79}
80
81void run_square( struct Nes_Vrc6_Apu* this, struct Vrc6_Osc* osc, blip_time_t end_time )
82{
83 struct Blip_Buffer* output = osc->output;
84 if ( !output )
85 return;
86 Blip_set_modified( output );
87
88 int volume = osc->regs [0] & 15;
89 if ( !(osc->regs [2] & 0x80) )
90 volume = 0;
91
92 int gate = osc->regs [0] & 0x80;
93 int duty = ((osc->regs [0] >> 4) & 7) + 1;
94 int delta = ((gate || osc->phase < duty) ? volume : 0) - osc->last_amp;
95 blip_time_t time = this->last_time;
96 if ( delta )
97 {
98 osc->last_amp += delta;
99 Synth_offset( &this->square_synth, time, delta, output );
100 }
101
102 time += osc->delay;
103 osc->delay = 0;
104 int period = Vrc6_osc_period( osc );
105 if ( volume && !gate && period > 4 )
106 {
107 if ( time < end_time )
108 {
109 int phase = osc->phase;
110
111 do
112 {
113 phase++;
114 if ( phase == 16 )
115 {
116 phase = 0;
117 osc->last_amp = volume;
118 Synth_offset( &this->square_synth, time, volume, output );
119 }
120 if ( phase == duty )
121 {
122 osc->last_amp = 0;
123 Synth_offset( &this->square_synth, time, -volume, output );
124 }
125 time += period;
126 }
127 while ( time < end_time );
128
129 osc->phase = phase;
130 }
131 osc->delay = time - end_time;
132 }
133}
134
135void run_saw( struct Nes_Vrc6_Apu* this, blip_time_t end_time )
136{
137 struct Vrc6_Osc* osc = &this->oscs [2];
138 struct Blip_Buffer* output = osc->output;
139 if ( !output )
140 return;
141 Blip_set_modified( output );
142
143 int amp = osc->amp;
144 int amp_step = osc->regs [0] & 0x3F;
145 blip_time_t time = this->last_time;
146 int last_amp = osc->last_amp;
147 if ( !(osc->regs [2] & 0x80) || !(amp_step | amp) )
148 {
149 osc->delay = 0;
150 int delta = (amp >> 3) - last_amp;
151 last_amp = amp >> 3;
152 Synth_offset( &this->saw_synth, time, delta, output );
153 }
154 else
155 {
156 time += osc->delay;
157 if ( time < end_time )
158 {
159 int period = Vrc6_osc_period( osc ) * 2;
160 int phase = osc->phase;
161
162 do
163 {
164 if ( --phase == 0 )
165 {
166 phase = 7;
167 amp = 0;
168 }
169
170 int delta = (amp >> 3) - last_amp;
171 if ( delta )
172 {
173 last_amp = amp >> 3;
174 Synth_offset( &this->saw_synth, time, delta, output );
175 }
176
177 time += period;
178 amp = (amp + amp_step) & 0xFF;
179 }
180 while ( time < end_time );
181
182 osc->phase = phase;
183 osc->amp = amp;
184 }
185
186 osc->delay = time - end_time;
187 }
188
189 osc->last_amp = last_amp;
190}
191
diff --git a/apps/codecs/libgme/nes_vrc6_apu.h b/apps/codecs/libgme/nes_vrc6_apu.h
new file mode 100644
index 0000000000..540438f4a2
--- /dev/null
+++ b/apps/codecs/libgme/nes_vrc6_apu.h
@@ -0,0 +1,62 @@
1// Konami VRC6 sound chip emulator
2
3// Nes_Snd_Emu 0.1.8
4#ifndef NES_VRC6_APU_H
5#define NES_VRC6_APU_H
6
7#include "blargg_common.h"
8#include "blip_buffer.h"
9
10enum { vrc6_osc_count = 3 };
11enum { vrc6_reg_count = 3 };
12enum { vrc6_base_addr = 0x9000 };
13enum { vrc6_addr_step = 0x1000 };
14
15struct Vrc6_Osc
16{
17 uint8_t regs [vrc6_reg_count];
18 struct Blip_Buffer* output;
19 int delay;
20 int last_amp;
21 int phase;
22 int amp; // only used by saw
23};
24
25static inline int Vrc6_osc_period( struct Vrc6_Osc* this )
26{
27 return (this->regs [2] & 0x0F) * 0x100 + this->regs [1] + 1;
28}
29
30struct Nes_Vrc6_Apu {
31 struct Vrc6_Osc oscs [vrc6_osc_count];
32 blip_time_t last_time;
33
34 struct Blip_Synth saw_synth;
35 struct Blip_Synth square_synth;
36};
37
38// See Nes_Apu.h for reference
39void Vrc6_init( struct Nes_Vrc6_Apu* this );
40void Vrc6_reset( struct Nes_Vrc6_Apu* this );
41void Vrc6_output( struct Nes_Vrc6_Apu* this, struct Blip_Buffer* );
42void Vrc6_end_frame( struct Nes_Vrc6_Apu* this, blip_time_t ) ICODE_ATTR;
43
44// Oscillator 0 write-only registers are at $9000-$9002
45// Oscillator 1 write-only registers are at $A000-$A002
46// Oscillator 2 write-only registers are at $B000-$B002
47void Vrc6_write_osc( struct Nes_Vrc6_Apu* this, blip_time_t, int osc, int reg, int data ) ICODE_ATTR;
48
49static inline void Vrc6_osc_output( struct Nes_Vrc6_Apu* this, int i, struct Blip_Buffer* buf )
50{
51 assert( (unsigned) i < vrc6_osc_count );
52 this->oscs [i].output = buf;
53}
54
55static inline void Vrc6_volume( struct Nes_Vrc6_Apu* this, double v )
56{
57 double const factor = 0.0967 * 2;
58 Synth_volume( &this->saw_synth, factor / 31 * v );
59 Synth_volume( &this->square_synth, factor * 0.5 / 15 * v );
60}
61
62#endif
diff --git a/apps/codecs/libgme/nes_vrc7_apu.c b/apps/codecs/libgme/nes_vrc7_apu.c
new file mode 100644
index 0000000000..d8768bfc7e
--- /dev/null
+++ b/apps/codecs/libgme/nes_vrc7_apu.c
@@ -0,0 +1,89 @@
1
2#include "nes_vrc7_apu.h"
3#include "blargg_source.h"
4
5int const period = 36; // NES CPU clocks per FM clock
6
7void Vrc7_init( struct Nes_Vrc7_Apu* this )
8{
9 Synth_init( &this->synth );
10
11 OPLL_new ( &this->opll, 3579545, 3579545 / 72 );
12 OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE );
13
14 this->osc.output = 0;
15 this->osc.last_amp = 0;
16 this->mask = 0;
17
18 Vrc7_volume( this, 1.0 );
19 Vrc7_reset( this );
20}
21
22void Vrc7_reset( struct Nes_Vrc7_Apu* this )
23{
24 this->addr = 0;
25 this->next_time = 0;
26 this->osc.last_amp = 0;
27
28 OPLL_reset (&this->opll);
29 OPLL_setMask(&this->opll, this->mask);
30}
31
32void Vrc7_set_rate( struct Nes_Vrc7_Apu* this, double r )
33{
34 OPLL_set_quality( &this->opll, r < 44100 ? 0 : 1 );
35 OPLL_set_rate( &this->opll, (e_uint32)r );
36}
37
38void Vrc7_write_reg( struct Nes_Vrc7_Apu* this, int data )
39{
40 this->addr = data;
41}
42
43void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time );
44void Vrc7_write_data( struct Nes_Vrc7_Apu* this, blip_time_t time, int data )
45{
46 if ( time > this->next_time )
47 Vrc7_run_until( this, time );
48
49 OPLL_writeIO( &this->opll, 0, this->addr );
50 OPLL_writeIO( &this->opll, 1, data );
51}
52
53void Vrc7_end_frame( struct Nes_Vrc7_Apu* this, blip_time_t time )
54{
55 if ( time > this->next_time )
56 Vrc7_run_until( this, time );
57
58 this->next_time -= time;
59 assert( this->next_time >= 0 );
60
61 if ( this->osc.output )
62 Blip_set_modified( this->osc.output );
63}
64
65void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time )
66{
67 require( end_time > this->next_time );
68
69 blip_time_t time = this->next_time;
70 OPLL* opll = &this->opll; // cache
71 struct Blip_Buffer* const output = this-> osc.output;
72 if ( output )
73 {
74 do
75 {
76 int amp = OPLL_calc( opll ) << 1;
77 int delta = amp - this->osc.last_amp;
78 if ( delta )
79 {
80 this->osc.last_amp = amp;
81 Synth_offset_inline( &this->synth, time, delta, output );
82 }
83 time += period;
84 }
85 while ( time < end_time );
86 }
87
88 this->next_time = time;
89}
diff --git a/apps/codecs/libgme/nes_vrc7_apu.h b/apps/codecs/libgme/nes_vrc7_apu.h
new file mode 100644
index 0000000000..5453e6b403
--- /dev/null
+++ b/apps/codecs/libgme/nes_vrc7_apu.h
@@ -0,0 +1,52 @@
1// Konami VRC7 sound chip emulator
2
3#ifndef NES_VRC7_APU_H
4#define NES_VRC7_APU_H
5
6#include "blargg_common.h"
7#include "blip_buffer.h"
8
9#include "emu2413.h"
10
11enum { vrc7_osc_count = 6 };
12
13struct vrc7_osc_t {
14 struct Blip_Buffer* output;
15 int last_amp;
16};
17
18struct Nes_Vrc7_Apu {
19 OPLL opll;
20 int addr;
21 blip_time_t next_time;
22 struct vrc7_osc_t osc;
23 struct Blip_Synth synth;
24 e_uint32 mask;
25};
26
27// See Nes_Apu.h for reference
28void Vrc7_init( struct Nes_Vrc7_Apu* this );
29void Vrc7_reset( struct Nes_Vrc7_Apu* this );
30void Vrc7_set_rate( struct Nes_Vrc7_Apu* this, double r );
31void Vrc7_end_frame( struct Nes_Vrc7_Apu* this, blip_time_t ) ICODE_ATTR;
32
33void Vrc7_write_reg( struct Nes_Vrc7_Apu* this, int reg ) ICODE_ATTR;
34void Vrc7_write_data( struct Nes_Vrc7_Apu* this, blip_time_t, int data ) ICODE_ATTR;
35
36void output_changed( struct Nes_Vrc7_Apu* this );
37static inline void Vrc7_set_output( struct Nes_Vrc7_Apu* this, int i, struct Blip_Buffer* buf )
38{
39 assert( (unsigned) i < vrc7_osc_count );
40 this->mask |= 1 << i;
41
42 // Will use OPLL_setMask to mute voices
43 if ( buf ) {
44 this->mask ^= 1 << i;
45 this->osc.output = buf;
46 }
47}
48
49// DB2LIN_AMP_BITS == 11, * 2
50static inline void Vrc7_volume( struct Nes_Vrc7_Apu* this, double v ) { Synth_volume( &this->synth, 1.0 / 3 / 4096 * v ); }
51
52#endif
diff --git a/apps/codecs/libgme/nsf_cpu.c b/apps/codecs/libgme/nsf_cpu.c
new file mode 100644
index 0000000000..1f44bd3c3c
--- /dev/null
+++ b/apps/codecs/libgme/nsf_cpu.c
@@ -0,0 +1,115 @@
1// Normal cpu for NSF emulator
2
3// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
4
5#include "nsf_emu.h"
6
7#include "blargg_endian.h"
8
9#ifdef BLARGG_DEBUG_H
10 //#define CPU_LOG_START 1000000
11 //#include "nes_cpu_log.h"
12 #undef LOG_MEM
13#endif
14
15/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
16can redistribute it and/or modify it under the terms of the GNU Lesser
17General Public License as published by the Free Software Foundation; either
18version 2.1 of the License, or (at your option) any later version. This
19module is distributed in the hope that it will be useful, but WITHOUT ANY
20WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
22details. You should have received a copy of the GNU Lesser General Public
23License along with this module; if not, write to the Free Software Foundation,
24Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
25
26#include "blargg_source.h"
27
28#ifndef LOG_MEM
29 #define LOG_MEM( addr, str, data ) data
30#endif
31
32int read_mem( struct Nsf_Emu* this, addr_t addr )
33{
34 int result = this->low_ram [addr & (low_ram_size-1)]; // also handles wrap-around
35 if ( addr & 0xE000 )
36 {
37 result = *Cpu_get_code( &this->cpu, addr );
38 if ( addr < sram_addr )
39 {
40 if ( addr == apu_status_addr )
41 result = Apu_read_status( &this->apu, Cpu_time( &this->cpu ) );
42 else
43 result = cpu_read( this, addr );
44 }
45 }
46 return LOG_MEM( addr, ">", result );
47}
48
49void write_mem( struct Nsf_Emu* this, addr_t addr, int data )
50{
51 (void) LOG_MEM( addr, "<", data );
52
53 int offset = addr - sram_addr;
54 if ( (unsigned) offset < sram_size )
55 {
56 sram( this ) [offset] = data;
57 }
58 else
59 {
60 // after sram because cpu handles most low_ram accesses internally already
61 int temp = addr & (low_ram_size-1); // also handles wrap-around
62 if ( !(addr & 0xE000) )
63 {
64 this->low_ram [temp] = data;
65 }
66 else
67 {
68 int bank = addr - banks_addr;
69 if ( (unsigned) bank < bank_count )
70 {
71 write_bank( this, bank, data );
72 }
73 else if ( (unsigned) (addr - apu_io_addr) < apu_io_size )
74 {
75 Apu_write_register( &this->apu, Cpu_time( &this->cpu ), addr, data );
76 }
77 else
78 {
79 #ifndef NSF_EMU_APU_ONLY
80 // 0x8000-0xDFFF is writable
81 int i = addr - 0x8000;
82 if ( fds_enabled( this ) && (unsigned) i < fdsram_size )
83 fdsram( this ) [i] = data;
84 else
85 #endif
86 cpu_write( this, addr, data );
87 }
88 }
89 }
90}
91
92#define READ_LOW( addr ) (LOG_MEM( addr, ">", this->low_ram [addr] ))
93#define WRITE_LOW( addr, data ) (LOG_MEM( addr, "<", this->low_ram [addr] = data ))
94
95#define CAN_WRITE_FAST( addr ) (addr < low_ram_size)
96#define WRITE_FAST WRITE_LOW
97
98// addr < 0x2000 || addr >= 0x8000
99#define CAN_READ_FAST( addr ) ((addr ^ 0x8000) < 0xA000)
100#define READ_FAST( addr, out ) (LOG_MEM( addr, ">", out = READ_CODE( addr ) ))
101
102#define READ_MEM( addr ) read_mem( this, addr )
103#define WRITE_MEM( addr, data ) write_mem( this, addr, data )
104
105#define CPU_BEGIN \
106bool run_cpu_until( struct Nsf_Emu* this, nes_time_t end ) \
107{ \
108 struct Nes_Cpu* cpu = &this->cpu; \
109 Cpu_set_end_time( cpu, end ); \
110 if ( *Cpu_get_code( cpu, cpu->r.pc ) != halt_opcode ) \
111 {
112 #include "nes_cpu_run.h"
113 }
114 return Cpu_time_past_end( cpu ) < 0;
115}
diff --git a/apps/codecs/libgme/nsf_emu.c b/apps/codecs/libgme/nsf_emu.c
new file mode 100644
index 0000000000..c805780cb1
--- /dev/null
+++ b/apps/codecs/libgme/nsf_emu.c
@@ -0,0 +1,1105 @@
1// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/
2
3#include "nsf_emu.h"
4#include "multi_buffer.h"
5
6#include "blargg_endian.h"
7
8/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
9can redistribute it and/or modify it under the terms of the GNU Lesser
10General Public License as published by the Free Software Foundation; either
11version 2.1 of the License, or (at your option) any later version. This
12module is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15details. You should have received a copy of the GNU Lesser General Public
16License along with this module; if not, write to the Free Software Foundation,
17Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19#include "blargg_source.h"
20
21const char gme_wrong_file_type [] ICONST_ATTR = "Wrong file type for this emulator";
22long const clock_divisor = 12;
23
24int const stereo = 2; // number of channels for stereo
25int const silence_max = 6; // seconds
26int const silence_threshold = 0x10;
27long const fade_block_size = 512;
28int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
29
30// number of frames until play interrupts init
31int const initial_play_delay = 7; // KikiKaikai needed this to work
32int const rom_addr = 0x8000;
33
34void clear_track_vars( struct Nsf_Emu* this )
35{
36 this->current_track = -1;
37 this->out_time = 0;
38 this->emu_time = 0;
39 this->emu_track_ended_ = true;
40 this->track_ended = true;
41 this->fade_start = INT_MAX / 2 + 1;
42 this->fade_step = 1;
43 this->silence_time = 0;
44 this->silence_count = 0;
45 this->buf_remain = 0;
46}
47
48static int pcm_read( void* emu, addr_t addr )
49{
50 return *Cpu_get_code( &((struct Nsf_Emu*) emu)->cpu, addr );
51}
52
53void Nsf_init( struct Nsf_Emu* this )
54{
55 this->sample_rate = 0;
56 this->mute_mask_ = 0;
57 this->tempo = 1.0;
58 this->gain = 1.0;
59
60 // defaults
61 this->max_initial_silence = 2;
62 this->ignore_silence = false;
63 this->voice_count = 0;
64
65 // Set sound gain
66 Sound_set_gain( this, 1.2 );
67
68 // Unload
69 clear_track_vars( this );
70
71 // Init rom
72 Rom_init( &this->rom, 0x1000 );
73
74 // Init & clear nsfe info
75 Info_init( &this->info );
76 Info_unload( &this->info ); // TODO: extremely hacky!
77
78 Cpu_init( &this->cpu );
79 Apu_init( &this->apu );
80 Apu_dmc_reader( &this->apu, pcm_read, this );
81}
82
83// Setup
84
85blargg_err_t init_sound( struct Nsf_Emu* this )
86{
87 /* if ( header_.chip_flags & ~(fds_flag | namco_flag | vrc6_flag | fme7_flag) )
88 warning( "Uses unsupported audio expansion hardware" ); **/
89
90 this->voice_count = apu_osc_count;
91
92 double adjusted_gain = 1.0 / 0.75 * this->gain;
93
94 #ifdef NSF_EMU_APU_ONLY
95 {
96 if ( this->header_.chip_flags )
97 set_warning( "Uses unsupported audio expansion hardware" );
98 }
99 #else
100 {
101 if ( vrc6_enabled( this ) )
102 {
103 Vrc6_init( &this->vrc6 );
104 adjusted_gain *= 0.75;
105
106 this->voice_count += vrc6_osc_count;
107 }
108
109 if ( fme7_enabled( this ) )
110 {
111 Fme7_init( &this->fme7 );
112 adjusted_gain *= 0.75;
113
114 this->voice_count += fme7_osc_count;
115 }
116
117 if ( mmc5_enabled( this ) )
118 {
119 Mmc5_init( &this->mmc5 );
120 adjusted_gain *= 0.75;
121
122 this->voice_count += mmc5_osc_count;
123 }
124
125 if ( fds_enabled( this ) )
126 {
127 Fds_init( &this->fds );
128 adjusted_gain *= 0.75;
129
130 this->voice_count += fds_osc_count ;
131 }
132
133 if ( namco_enabled( this ) )
134 {
135 Namco_init( &this->namco );
136 adjusted_gain *= 0.75;
137
138 this->voice_count += namco_osc_count;
139 }
140
141 if ( vrc7_enabled( this ) )
142 {
143 #ifndef NSF_EMU_NO_VRC7
144 Vrc7_init( &this->vrc7 );
145 Vrc7_set_rate( &this->vrc7, this->sample_rate );
146 #endif
147
148 adjusted_gain *= 0.75;
149
150 this->voice_count += vrc7_osc_count;
151 }
152
153 if ( vrc7_enabled( this ) ) Vrc7_volume( &this->vrc7, adjusted_gain );
154 if ( namco_enabled( this ) ) Namco_volume( &this->namco, adjusted_gain );
155 if ( vrc6_enabled( this ) ) Vrc6_volume( &this->vrc6, adjusted_gain );
156 if ( fme7_enabled( this ) ) Fme7_volume( &this->fme7, adjusted_gain );
157 if ( mmc5_enabled( this ) ) Apu_volume( &this->mmc5.apu, adjusted_gain );
158 if ( fds_enabled( this ) ) Fds_volume( &this->fds, adjusted_gain );
159 }
160 #endif
161
162 if ( adjusted_gain > this->gain )
163 adjusted_gain = this->gain;
164
165 Apu_volume( &this->apu, adjusted_gain );
166
167 return 0;
168}
169
170// Header stuff
171bool valid_tag( struct header_t* this )
172{
173 return 0 == memcmp( this->tag, "NESM\x1A", 5 );
174}
175
176// True if file supports only PAL speed
177static bool pal_only( struct header_t* this )
178{
179 return (this->speed_flags & 3) == 1;
180}
181
182static double clock_rate( struct header_t* this )
183{
184 return pal_only( this ) ? 1662607.125 : 1789772.727272727;
185}
186
187int play_period( struct header_t* this )
188{
189 // NTSC
190 int clocks = 29780;
191 int value = 0x411A;
192 byte const* rate_ptr = this->ntsc_speed;
193
194 // PAL
195 if ( pal_only( this ) )
196 {
197 clocks = 33247;
198 value = 0x4E20;
199 rate_ptr = this->pal_speed;
200 }
201
202 // Default rate
203 int rate = get_le16( rate_ptr );
204 if ( rate == 0 )
205 rate = value;
206
207 // Custom rate
208 if ( rate != value )
209 clocks = (int) (rate * clock_rate( this ) * (1.0/1000000.0));
210
211 return clocks;
212}
213
214// Gets address, given pointer to it in file header. If zero, returns rom_addr.
215addr_t get_addr( byte const in [] )
216{
217 addr_t addr = get_le16( in );
218 if ( addr == 0 )
219 addr = rom_addr;
220 return addr;
221}
222
223static blargg_err_t check_nsf_header( struct header_t* h )
224{
225 if ( !valid_tag( h ) )
226 return gme_wrong_file_type;
227 return 0;
228}
229
230blargg_err_t Nsf_load( struct Nsf_Emu* this, void* data, long size )
231{
232 // Unload
233 Info_unload( &this->info ); // TODO: extremely hacky!
234 this->m3u.size = 0;
235
236 this->voice_count = 0;
237 clear_track_vars( this );
238
239 assert( offsetof (struct header_t,unused [4]) == header_size );
240
241 if ( !memcmp( data, "NESM\x1A", 5 ) ) {
242 Nsf_disable_playlist( this, true );
243
244 RETURN_ERR( Rom_load( &this->rom, data, size, header_size, &this->header, 0 ) );
245 return Nsf_post_load( this );
246 }
247
248 blargg_err_t err = Info_load( &this->info, data, size, this );
249 Nsf_disable_playlist( this, false );
250 return err;
251}
252
253blargg_err_t Nsf_post_load( struct Nsf_Emu* this )
254{
255 RETURN_ERR( check_nsf_header( &this->header ) );
256
257 /* if ( header_.vers != 1 )
258 warning( "Unknown file version" ); */
259
260 // set up data
261 addr_t load_addr = get_le16( this->header.load_addr );
262
263 /* if ( load_addr < (fds_enabled() ? sram_addr : rom_addr) )
264 warning( "Load address is too low" ); */
265
266 Rom_set_addr( &this->rom, load_addr % this->rom.bank_size );
267
268 /* if ( header_.vers != 1 )
269 warning( "Unknown file version" ); */
270
271 set_play_period( this, play_period( &this->header ) );
272
273 // sound and memory
274 blargg_err_t err = init_sound( this );
275 if ( err )
276 return err;
277
278 // Post load
279 Sound_set_tempo( this, this->tempo );
280
281 // Remute voices
282 Sound_mute_voices( this, this->mute_mask_ );
283
284 // Set track_count
285 this->track_count = this->header.track_count;
286
287 // Change clock rate & setup buffer
288 this->clock_rate__ = (long) (clock_rate( &this->header ) + 0.5);
289 Buffer_clock_rate( &this->stereo_buf, this->clock_rate__ );
290 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
291 return 0;
292}
293
294void Nsf_disable_playlist( struct Nsf_Emu* this, bool b )
295{
296 Info_disable_playlist( &this->info, b );
297 this->track_count = this->info.track_count;
298}
299
300void Nsf_clear_playlist( struct Nsf_Emu* this )
301{
302 Nsf_disable_playlist( this, true );
303}
304
305void write_bank( struct Nsf_Emu* this, int bank, int data )
306{
307 // Find bank in ROM
308 int offset = mask_addr( data * this->rom.bank_size, this->rom.mask );
309 /* if ( offset >= rom.size() )
310 warning( "invalid bank" ); */
311 void const* rom_data = Rom_at_addr( &this->rom, offset );
312
313 #ifndef NSF_EMU_APU_ONLY
314 if ( bank < bank_count - fds_banks && fds_enabled( this ) )
315 {
316 // TODO: FDS bank switching is kind of hacky, might need to
317 // treat ROM as RAM so changes won't get lost when switching.
318 byte* out = sram( this );
319 if ( bank >= fds_banks )
320 {
321 out = fdsram( this );
322 bank -= fds_banks;
323 }
324 memcpy( &out [bank * this->rom.bank_size], rom_data, this->rom.bank_size );
325 return;
326 }
327 #endif
328
329 if ( bank >= fds_banks )
330 Cpu_map_code( &this->cpu, (bank + 6) * this->rom.bank_size, this->rom.bank_size, rom_data, false );
331}
332
333void map_memory( struct Nsf_Emu* this )
334{
335 // Map standard things
336 Cpu_reset( &this->cpu, unmapped_code( this ) );
337 Cpu_map_code( &this->cpu, 0, 0x2000, this->low_ram, low_ram_size ); // mirrored four times
338 Cpu_map_code( &this->cpu, sram_addr, sram_size, sram( this ), 0 );
339
340 // Determine initial banks
341 byte banks [bank_count];
342 static byte const zero_banks [sizeof this->header.banks] = { 0 };
343 if ( memcmp( this->header.banks, zero_banks, sizeof zero_banks ) )
344 {
345 banks [0] = this->header.banks [6];
346 banks [1] = this->header.banks [7];
347 memcpy( banks + fds_banks, this->header.banks, sizeof this->header.banks );
348 }
349 else
350 {
351 // No initial banks, so assign them based on load_addr
352 int i, first_bank = (get_addr( this->header.load_addr ) - sram_addr) / this->rom.bank_size;
353 unsigned total_banks = this->rom.size / this->rom.bank_size;
354 for ( i = bank_count; --i >= 0; )
355 {
356 int bank = i - first_bank;
357 if ( (unsigned) bank >= total_banks )
358 bank = 0;
359 banks [i] = bank;
360 }
361 }
362
363 // Map banks
364 int i;
365 for ( i = (fds_enabled( this ) ? 0 : fds_banks); i < bank_count; ++i )
366 write_bank( this, i, banks [i] );
367
368 // Map FDS RAM
369 if ( fds_enabled( this ) )
370 Cpu_map_code( &this->cpu, rom_addr, fdsram_size, fdsram( this ), 0 );
371}
372
373void set_voice( struct Nsf_Emu* this, int i, struct Blip_Buffer* buf, struct Blip_Buffer* left, struct Blip_Buffer* right)
374{
375#if defined(ROCKBOX)
376 (void) left;
377 (void) right;
378#endif
379
380 if ( i < apu_osc_count )
381 {
382 Apu_osc_output( &this->apu, i, buf );
383 return;
384 }
385 i -= apu_osc_count;
386
387 #ifndef NSF_EMU_APU_ONLY
388 {
389 if ( vrc6_enabled( this ) && (i -= vrc6_osc_count) < 0 )
390 {
391 Vrc6_osc_output( &this->vrc6, i + vrc6_osc_count, buf );
392 return;
393 }
394
395 if ( fme7_enabled( this ) && (i -= fme7_osc_count) < 0 )
396 {
397 Fme7_osc_output( &this->fme7, i + fme7_osc_count, buf );
398 return;
399 }
400
401 if ( mmc5_enabled( this ) && (i -= mmc5_osc_count) < 0 )
402 {
403 Mmc5_set_output( &this->mmc5, i + mmc5_osc_count, buf );
404 return;
405 }
406
407 if ( fds_enabled( this ) && (i -= fds_osc_count) < 0 )
408 {
409 Fds_set_output( &this->fds, i + fds_osc_count, buf );
410 return;
411 }
412
413 if ( namco_enabled( this ) && (i -= namco_osc_count) < 0 )
414 {
415 Namco_osc_output( &this->namco, i + namco_osc_count, buf );
416 return;
417 }
418
419 if ( vrc7_enabled( this ) && (i -= vrc7_osc_count) < 0 )
420 {
421 Vrc7_set_output( &this->vrc7, i + vrc7_osc_count, buf );
422 return;
423 }
424 }
425 #endif
426}
427
428// Emulation
429
430// Music Emu
431
432blargg_err_t Nsf_set_sample_rate( struct Nsf_Emu* this, long rate )
433{
434 require( !this->sample_rate ); // sample rate can't be changed once set
435 Buffer_init( &this->stereo_buf );
436 RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) );
437
438 // Set bass frequency
439 Buffer_bass_freq( &this->stereo_buf, 80 );
440
441 this->sample_rate = rate;
442 return 0;
443}
444
445void Sound_mute_voice( struct Nsf_Emu* this, int index, bool mute )
446{
447 require( (unsigned) index < (unsigned) this->voice_count );
448 int bit = 1 << index;
449 int mask = this->mute_mask_ | bit;
450 if ( !mute )
451 mask ^= bit;
452 Sound_mute_voices( this, mask );
453}
454
455void Sound_mute_voices( struct Nsf_Emu* this, int mask )
456{
457 require( this->sample_rate ); // sample rate must be set first
458 this->mute_mask_ = mask;
459
460 int i;
461 for ( i = this->voice_count; i--; )
462 {
463 if ( mask & (1 << i) )
464 {
465 set_voice( this, i, 0, 0, 0 );
466 }
467 else
468 {
469 struct channel_t ch = Buffer_channel( &this->stereo_buf );
470 assert( (ch.center && ch.left && ch.right) ||
471 (!ch.center && !ch.left && !ch.right) ); // all or nothing
472 set_voice( this, i, ch.center, ch.left, ch.right );
473 }
474 }
475}
476
477void Sound_set_tempo( struct Nsf_Emu* this, double t )
478{
479 require( this->sample_rate ); // sample rate must be set first
480 double const min = 0.02;
481 double const max = 4.00;
482 if ( t < min ) t = min;
483 if ( t > max ) t = max;
484 this->tempo = t;
485
486 set_play_period( this, (int) (play_period( &this->header ) / t) );
487
488 Apu_set_tempo( &this->apu, t );
489
490#ifndef NSF_EMU_APU_ONLY
491 if ( fds_enabled( this ) )
492 Fds_set_tempo( &this->fds, t );
493#endif
494}
495
496inline void push_byte( struct Nsf_Emu* this, int b )
497{
498 this->low_ram [0x100 + this->cpu.r.sp--] = b;
499}
500
501// Jumps to routine, given pointer to address in file header. Pushes idle_addr
502// as return address, NOT old PC.
503void jsr_then_stop( struct Nsf_Emu* this, byte const addr [] )
504{
505 this->cpu.r.pc = get_addr( addr );
506 push_byte( this, (idle_addr - 1) >> 8 );
507 push_byte( this, (idle_addr - 1) );
508}
509
510int cpu_read( struct Nsf_Emu* this, addr_t addr )
511{
512 #ifndef NSF_EMU_APU_ONLY
513 {
514 if ( namco_enabled( this ) && addr == namco_data_reg_addr )
515 return Namco_read_data( &this->namco );
516
517 if ( fds_enabled( this ) && (unsigned) (addr - fds_io_addr) < fds_io_size )
518 return Fds_read( &this->fds, Cpu_time( &this->cpu ), addr );
519
520 if ( mmc5_enabled( this ) ) {
521 int i = addr - 0x5C00;
522 if ( (unsigned) i < mmc5_exram_size )
523 return this->mmc5.exram [i];
524
525 int m = addr - 0x5205;
526 if ( (unsigned) m < 2 )
527 return (this->mmc5_mul [0] * this->mmc5_mul [1]) >> (m * 8) & 0xFF;
528 }
529 }
530 #endif
531
532 /* Unmapped read */
533 return addr >> 8;
534}
535
536int unmapped_read( struct Nsf_Emu* this, addr_t addr )
537{
538 (void) this;
539
540 switch ( addr )
541 {
542 case 0x2002:
543 case 0x4016:
544 case 0x4017:
545 return addr >> 8;
546 }
547
548 // Unmapped read
549 return addr >> 8;
550}
551
552void cpu_write( struct Nsf_Emu* this, addr_t addr, int data )
553{
554 #ifndef NSF_EMU_APU_ONLY
555 {
556 nes_time_t time = Cpu_time( &this->cpu );
557 if ( fds_enabled( this) && (unsigned) (addr - fds_io_addr) < fds_io_size )
558 {
559 Fds_write( &this->fds, time, addr, data );
560 return;
561 }
562
563 if ( namco_enabled( this) )
564 {
565 if ( addr == namco_addr_reg_addr )
566 {
567 Namco_write_addr( &this->namco, data );
568 return;
569 }
570
571 if ( addr == namco_data_reg_addr )
572 {
573 Namco_write_data( &this->namco, time, data );
574 return;
575 }
576 }
577
578 if ( vrc6_enabled( this) )
579 {
580 int reg = addr & (vrc6_addr_step - 1);
581 int osc = (unsigned) (addr - vrc6_base_addr) / vrc6_addr_step;
582 if ( (unsigned) osc < vrc6_osc_count && (unsigned) reg < vrc6_reg_count )
583 {
584 Vrc6_write_osc( &this->vrc6, time, osc, reg, data );
585 return;
586 }
587 }
588
589 if ( fme7_enabled( this) && addr >= fme7_latch_addr )
590 {
591 switch ( addr & fme7_addr_mask )
592 {
593 case fme7_latch_addr:
594 Fme7_write_latch( &this->fme7, data );
595 return;
596
597 case fme7_data_addr:
598 Fme7_write_data( &this->fme7, time, data );
599 return;
600 }
601 }
602
603 if ( mmc5_enabled( this) )
604 {
605 if ( (unsigned) (addr - mmc5_regs_addr) < mmc5_regs_size )
606 {
607 Mmc5_write_register( &this->mmc5, time, addr, data );
608 return;
609 }
610
611 int m = addr - 0x5205;
612 if ( (unsigned) m < 2 )
613 {
614 this->mmc5_mul [m] = data;
615 return;
616 }
617
618 int i = addr - 0x5C00;
619 if ( (unsigned) i < mmc5_exram_size )
620 {
621 this->mmc5.exram [i] = data;
622 return;
623 }
624 }
625
626 if ( vrc7_enabled( this) )
627 {
628 if ( addr == 0x9010 )
629 {
630 Vrc7_write_reg( &this->vrc7, data );
631 return;
632 }
633
634 if ( (unsigned) (addr - 0x9028) <= 0x08 )
635 {
636 Vrc7_write_data( &this->vrc7, time, data );
637 return;
638 }
639 }
640 }
641 #endif
642
643 // Unmapped_write
644}
645
646void unmapped_write( struct Nsf_Emu* this, addr_t addr, int data )
647{
648 (void) data;
649
650 switch ( addr )
651 {
652 case 0x8000: // some write to $8000 and $8001 repeatedly
653 case 0x8001:
654 case 0x4800: // probably namco sound mistakenly turned on in MCK
655 case 0xF800:
656 case 0xFFF8: // memory mapper?
657 return;
658 }
659
660 if ( mmc5_enabled( this ) && addr == 0x5115 ) return;
661
662 // FDS memory
663 if ( fds_enabled( this ) && (unsigned) (addr - 0x8000) < 0x6000 ) return;
664}
665
666void fill_buf( struct Nsf_Emu* this );
667blargg_err_t Nsf_start_track( struct Nsf_Emu* this, int track )
668{
669 clear_track_vars( this );
670
671 // Remap track if playlist available
672 if ( this->m3u.size > 0 ) {
673 struct entry_t* e = &this->m3u.entries[track];
674 track = e->track;
675 }
676 else track = Info_remap_track( &this->info, track );
677
678 this->current_track = track;
679 Buffer_clear( &this->stereo_buf );
680
681 #ifndef NSF_EMU_APU_ONLY
682 if ( mmc5_enabled( this ) )
683 {
684 this->mmc5_mul [0] = 0;
685 this->mmc5_mul [1] = 0;
686 memset( this->mmc5.exram, 0, mmc5_exram_size );
687 }
688
689 if ( fds_enabled( this ) ) Fds_reset( &this->fds );
690 if ( namco_enabled( this ) ) Namco_reset( &this->namco );
691 if ( vrc6_enabled( this ) ) Vrc6_reset( &this->vrc6 );
692 if ( fme7_enabled( this ) ) Fme7_reset( &this->fme7 );
693 if ( mmc5_enabled( this ) ) Apu_reset( &this->mmc5.apu, false, 0 );
694 if ( vrc7_enabled( this ) ) Vrc7_reset( &this->vrc7 );
695 #endif
696
697 int speed_flags = 0;
698 #ifdef NSF_EMU_EXTRA_FLAGS
699 speed_flags = this->header.speed_flags;
700 #endif
701
702 Apu_reset( &this->apu, pal_only( &this->header ), (speed_flags & 0x20) ? 0x3F : 0 );
703 Apu_write_register( &this->apu, 0, 0x4015, 0x0F );
704 Apu_write_register( &this->apu, 0, 0x4017, (speed_flags & 0x10) ? 0x80 : 0 );
705
706 memset( unmapped_code( this ), halt_opcode, unmapped_size );
707 memset( this->low_ram, 0, low_ram_size );
708 memset( sram( this ), 0, sram_size );
709
710 map_memory( this );
711
712 // Arrange time of first call to play routine
713 this->play_extra = 0;
714 this->next_play = this->play_period;
715
716 this->play_delay = initial_play_delay;
717 this->saved_state.pc = idle_addr;
718
719 // Setup for call to init routine
720 this->cpu.r.a = track;
721 this->cpu.r.x = pal_only( &this->header );
722 this->cpu.r.sp = 0xFF;
723 jsr_then_stop( this, this->header.init_addr );
724 /* if ( this->cpu.r.pc < get_addr( header.load_addr ) )
725 warning( "Init address < load address" ); */
726
727 this->emu_track_ended_ = false;
728 this->track_ended = false;
729
730 if ( !this->ignore_silence )
731 {
732 // play until non-silence or end of track
733 long end;
734 for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; )
735 {
736 fill_buf( this );
737 if ( this->buf_remain | (int) this->emu_track_ended_ )
738 break;
739 }
740
741 this->emu_time = this->buf_remain;
742 this->out_time = 0;
743 this->silence_time = 0;
744 this->silence_count = 0;
745 }
746 /* return track_ended() ? warning() : 0; */
747 return 0;
748}
749
750void run_once( struct Nsf_Emu* this, nes_time_t end )
751{
752 // Emulate until next play call if possible
753 if ( run_cpu_until( this, min( this->next_play, end ) ) )
754 {
755 // Halt instruction encountered
756
757 if ( this->cpu.r.pc != idle_addr )
758 {
759 // special_event( "illegal instruction" );
760 Cpu_set_time( &this->cpu, this->cpu.end_time );
761 return;
762 }
763
764 // Init/play routine returned
765 this->play_delay = 1; // play can now be called regularly
766
767 if ( this->saved_state.pc == idle_addr )
768 {
769 // nothing to run
770 nes_time_t t = this->cpu.end_time;
771 if ( Cpu_time( &this->cpu ) < t )
772 Cpu_set_time( &this->cpu, t );
773 }
774 else
775 {
776 // continue init routine that was interrupted by play routine
777 this->cpu.r = this->saved_state;
778 this->saved_state.pc = idle_addr;
779 }
780 }
781
782 if ( Cpu_time( &this->cpu ) >= this->next_play )
783 {
784 // Calculate time of next call to play routine
785 this->play_extra ^= 1; // extra clock every other call
786 this->next_play += this->play_period + this->play_extra;
787
788 // Call routine if ready
789 if ( this->play_delay && !--this->play_delay )
790 {
791 // Save state if init routine is still running
792 if ( this->cpu.r.pc != idle_addr )
793 {
794 check( this->saved_state.pc == idle_addr );
795 this->saved_state = this->cpu.r;
796 // special_event( "play called during init" );
797 }
798
799 jsr_then_stop( this, this->header.play_addr );
800 }
801 }
802}
803
804void run_until( struct Nsf_Emu* this, nes_time_t end )
805{
806 while ( Cpu_time( &this->cpu ) < end )
807 run_once( this, end );
808}
809
810void end_frame( struct Nsf_Emu* this, nes_time_t end )
811{
812 if ( Cpu_time( &this->cpu ) < end )
813 run_until( this, end );
814 Cpu_adjust_time( &this->cpu, -end );
815
816 // Localize to new time frame
817 this->next_play -= end;
818 check( this->next_play >= 0 );
819 if ( this->next_play < 0 )
820 this->next_play = 0;
821
822 Apu_end_frame( &this->apu, end );
823
824 #ifndef NSF_EMU_APU_ONLY
825 if ( fds_enabled( this ) ) Fds_end_frame( &this->fds, end );
826 if ( fme7_enabled( this ) ) Fme7_end_frame( &this->fme7, end );
827 if ( mmc5_enabled( this ) ) Apu_end_frame( &this->mmc5.apu, end );
828 if ( namco_enabled( this ) ) Namco_end_frame( &this->namco, end );
829 if ( vrc6_enabled( this ) ) Vrc6_end_frame( &this->vrc6, end );
830 if ( vrc7_enabled( this ) ) Vrc7_end_frame( &this->vrc7, end );
831 #endif
832}
833
834// Tell/Seek
835
836blargg_long msec_to_samples( long sample_rate, blargg_long msec )
837{
838 blargg_long sec = msec / 1000;
839 msec -= sec * 1000;
840 return (sec * sample_rate + msec * sample_rate / 1000) * stereo;
841}
842
843long Track_tell( struct Nsf_Emu* this )
844{
845 blargg_long rate = this->sample_rate * stereo;
846 blargg_long sec = this->out_time / rate;
847 return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate;
848}
849
850blargg_err_t Track_seek( struct Nsf_Emu* this, long msec )
851{
852 blargg_long time = msec_to_samples( this->sample_rate, msec );
853 if ( time < this->out_time )
854 RETURN_ERR( Nsf_start_track( this, this->current_track ) );
855 return Track_skip( this, time - this->out_time );
856}
857
858blargg_err_t skip_( struct Nsf_Emu* this, long count ) ICODE_ATTR;
859blargg_err_t Track_skip( struct Nsf_Emu* this, long count )
860{
861 require( this->current_track >= 0 ); // start_track() must have been called already
862 this->out_time += count;
863
864 // remove from silence and buf first
865 {
866 long n = min( count, this->silence_count );
867 this->silence_count -= n;
868 count -= n;
869
870 n = min( count, this->buf_remain );
871 this->buf_remain -= n;
872 count -= n;
873 }
874
875 if ( count && !this->emu_track_ended_ )
876 {
877 this->emu_time += count;
878 // End track if error
879 if ( skip_( this, count ) )
880 this->emu_track_ended_ = true;
881 }
882
883 if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended
884 this->track_ended |= this->emu_track_ended_;
885
886 return 0;
887}
888
889blargg_err_t play_( struct Nsf_Emu* this, long count, sample_t* out ) ICODE_ATTR;
890blargg_err_t skip_( struct Nsf_Emu* this, long count )
891{
892 // for long skip, mute sound
893 const long threshold = 30000;
894 if ( count > threshold )
895 {
896 int saved_mute = this->mute_mask_;
897 Sound_mute_voices( this, ~0 );
898
899 while ( count > threshold / 2 && !this->emu_track_ended_ )
900 {
901 RETURN_ERR( play_( this, buf_size, this->buf ) );
902 count -= buf_size;
903 }
904
905 Sound_mute_voices( this, saved_mute );
906 }
907
908 while ( count && !this->emu_track_ended_ )
909 {
910 long n = buf_size;
911 if ( n > count )
912 n = count;
913 count -= n;
914 RETURN_ERR( play_( this, n, this->buf ) );
915 }
916 return 0;
917}
918
919// Fading
920
921void Track_set_fade( struct Nsf_Emu* this, long start_msec, long length_msec )
922{
923 this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo);
924 this->fade_start = msec_to_samples( this->sample_rate, start_msec );
925}
926
927// unit / pow( 2.0, (double) x / step )
928static int int_log( blargg_long x, int step, int unit )
929{
930 int shift = x / step;
931 int fraction = (x - shift * step) * unit / step;
932 return ((unit - fraction) + (fraction >> 1)) >> shift;
933}
934
935void handle_fade( struct Nsf_Emu* this, long out_count, sample_t* out )
936{
937 int i;
938 for ( i = 0; i < out_count; i += fade_block_size )
939 {
940 int const shift = 14;
941 int const unit = 1 << shift;
942 int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size,
943 this->fade_step, unit );
944 if ( gain < (unit >> fade_shift) )
945 this->track_ended = this->emu_track_ended_ = true;
946
947 sample_t* io = &out [i];
948 int count;
949 for ( count = min( fade_block_size, out_count - i ); count; --count )
950 {
951 *io = (sample_t) ((*io * gain) >> shift);
952 ++io;
953 }
954 }
955}
956
957// Silence detection
958
959void emu_play( struct Nsf_Emu* this, long count, sample_t* out ) ICODE_ATTR;
960void emu_play( struct Nsf_Emu* this, long count, sample_t* out )
961{
962 check( current_track_ >= 0 );
963 this->emu_time += count;
964 if ( this->current_track >= 0 && !this->emu_track_ended_ ) {
965
966 // End track if error
967 if ( play_( this, count, out ) )
968 this->emu_track_ended_ = true;
969 }
970 else
971 memset( out, 0, count * sizeof *out );
972}
973
974// number of consecutive silent samples at end
975static long count_silence( sample_t* begin, long size )
976{
977 sample_t first = *begin;
978 *begin = silence_threshold; // sentinel
979 sample_t* p = begin + size;
980 while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { }
981 *begin = first;
982 return size - (p - begin);
983}
984
985// fill internal buffer and check it for silence
986void fill_buf( struct Nsf_Emu* this )
987{
988 assert( !this->buf_remain );
989 if ( !this->emu_track_ended_ )
990 {
991 emu_play( this, buf_size, this->buf );
992 long silence = count_silence( this->buf, buf_size );
993 if ( silence < buf_size )
994 {
995 this->silence_time = this->emu_time - silence;
996 this->buf_remain = buf_size;
997 return;
998 }
999 }
1000 this->silence_count += buf_size;
1001}
1002
1003blargg_err_t Nsf_play( struct Nsf_Emu* this, long out_count, sample_t* out )
1004{
1005 if ( this->track_ended )
1006 {
1007 memset( out, 0, out_count * sizeof *out );
1008 }
1009 else
1010 {
1011 require( this->current_track >= 0 );
1012 require( out_count % stereo == 0 );
1013
1014 assert( this->emu_time >= this->out_time );
1015
1016 long pos = 0;
1017 if ( this->silence_count )
1018 {
1019 // during a run of silence, run emulator at >=2x speed so it gets ahead
1020 long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time;
1021 while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) )
1022 fill_buf( this );
1023
1024 // fill with silence
1025 pos = min( this->silence_count, out_count );
1026 memset( out, 0, pos * sizeof *out );
1027 this->silence_count -= pos;
1028
1029 if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate )
1030 {
1031 this->track_ended = this->emu_track_ended_ = true;
1032 this->silence_count = 0;
1033 this->buf_remain = 0;
1034 }
1035 }
1036
1037 if ( this->buf_remain )
1038 {
1039 // empty silence buf
1040 long n = min( this->buf_remain, out_count - pos );
1041 memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out );
1042 this->buf_remain -= n;
1043 pos += n;
1044 }
1045
1046 // generate remaining samples normally
1047 long remain = out_count - pos;
1048 if ( remain )
1049 {
1050 emu_play( this, remain, out + pos );
1051 this->track_ended |= this->emu_track_ended_;
1052
1053 if ( !this->ignore_silence || this->out_time > this->fade_start )
1054 {
1055 // check end for a new run of silence
1056 long silence = count_silence( out + pos, remain );
1057 if ( silence < remain )
1058 this->silence_time = this->emu_time - silence;
1059
1060 if ( this->emu_time - this->silence_time >= buf_size )
1061 fill_buf( this ); // cause silence detection on next play()
1062 }
1063 }
1064
1065 if ( this->out_time > this->fade_start )
1066 handle_fade( this, out_count, out );
1067 }
1068 this->out_time += out_count;
1069 return 0;
1070}
1071
1072blargg_err_t play_( struct Nsf_Emu* this, long count, sample_t* out )
1073{
1074 long remain = count;
1075 while ( remain )
1076 {
1077 remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain );
1078 if ( remain )
1079 {
1080 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) )
1081 {
1082 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
1083
1084 // Remute voices
1085 Sound_mute_voices( this, this->mute_mask_ );
1086 }
1087 int msec = Buffer_length( &this->stereo_buf );
1088 blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate__ / 1000 - 100;
1089 RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) );
1090 assert( clocks_emulated );
1091 Buffer_end_frame( &this->stereo_buf, clocks_emulated );
1092 }
1093 }
1094 return 0;
1095}
1096
1097blargg_err_t run_clocks( struct Nsf_Emu* this, blip_time_t* duration, int msec )
1098{
1099#if defined(ROCKBOX)
1100 (void) msec;
1101#endif
1102
1103 end_frame( this, *duration );
1104 return 0;
1105}
diff --git a/apps/codecs/libgme/nsf_emu.h b/apps/codecs/libgme/nsf_emu.h
new file mode 100644
index 0000000000..421425e339
--- /dev/null
+++ b/apps/codecs/libgme/nsf_emu.h
@@ -0,0 +1,262 @@
1// Nintendo NES/Famicom NSF music file emulator
2
3// Game_Music_Emu 0.5.5
4#ifndef NSF_EMU_H
5#define NSF_EMU_H
6
7#include "rom_data.h"
8#include "multi_buffer.h"
9#include "nes_apu.h"
10#include "nes_cpu.h"
11#include "nsfe_info.h"
12#include "m3u_playlist.h"
13
14#ifndef NSF_EMU_APU_ONLY
15 #include "nes_namco_apu.h"
16 #include "nes_vrc6_apu.h"
17 #include "nes_fme7_apu.h"
18 #include "nes_fds_apu.h"
19 #include "nes_mmc5_apu.h"
20 #include "nes_vrc7_apu.h"
21#endif
22
23typedef short sample_t;
24
25// Sound chip flags
26enum {
27 vrc6_flag = 1 << 0,
28 vrc7_flag = 1 << 1,
29 fds_flag = 1 << 2,
30 mmc5_flag = 1 << 3,
31 namco_flag = 1 << 4,
32 fme7_flag = 1 << 5
33};
34
35enum { fds_banks = 2 };
36enum { bank_count = fds_banks + 8 };
37
38enum { rom_begin = 0x8000 };
39enum { bank_select_addr = 0x5FF8 };
40enum { mem_size = 0x10000 };
41
42// cpu sits here when waiting for next call to play routine
43enum { idle_addr = 0x5FF6 };
44enum { banks_addr = idle_addr };
45enum { badop_addr = bank_select_addr };
46
47enum { low_ram_size = 0x800 };
48enum { sram_size = 0x2000 };
49enum { fdsram_size = 0x6000 };
50enum { fdsram_offset = 0x2000 + page_size + 8 };
51enum { sram_addr = 0x6000 };
52enum { unmapped_size= page_size + 8 };
53
54enum { buf_size = 2048 };
55
56// NSF file header
57enum { header_size = 0x80 };
58struct header_t
59{
60 char tag [5];
61 byte vers;
62 byte track_count;
63 byte first_track;
64 byte load_addr [2];
65 byte init_addr [2];
66 byte play_addr [2];
67 char game [32];
68 char author [32];
69 char copyright [32];
70 byte ntsc_speed [2];
71 byte banks [8];
72 byte pal_speed [2];
73 byte speed_flags;
74 byte chip_flags;
75 byte unused [4];
76};
77
78struct Nsf_Emu {
79 // Play routine timing
80 nes_time_t next_play;
81 nes_time_t play_period;
82 int play_extra;
83 int play_delay;
84 struct registers_t saved_state; // of interrupted init routine
85
86 int track_count;
87
88 // general
89 int max_initial_silence;
90 int voice_count;
91 int mute_mask_;
92 double tempo;
93 double gain;
94
95 long sample_rate;
96
97 // track-specific
98 int current_track;
99 blargg_long out_time; // number of samples played since start of track
100 blargg_long emu_time; // number of samples emulator has generated since start of track
101 bool emu_track_ended_; // emulator has reached end of track
102 volatile bool track_ended;
103
104 // fading
105 blargg_long fade_start;
106 int fade_step;
107
108 // silence detection
109 int silence_lookahead; // speed to run emulator when looking ahead for silence
110 bool ignore_silence;
111 long silence_time; // number of samples where most recent silence began
112 long silence_count; // number of samples of silence to play before using buf
113 long buf_remain; // number of samples left in silence buffer
114
115 double clock_rate_;
116 long clock_rate__;
117 unsigned buf_changed_count;
118
119 // M3u Playlist
120 struct M3u_Playlist m3u;
121
122 // Larger items at the end
123 #ifndef NSF_EMU_APU_ONLY
124 byte mmc5_mul [2];
125
126 struct Nes_Fds_Apu fds;
127 struct Nes_Mmc5_Apu mmc5;
128 struct Nes_Namco_Apu namco;
129 struct Nes_Vrc6_Apu vrc6;
130 struct Nes_Fme7_Apu fme7;
131 struct Nes_Vrc7_Apu vrc7;
132 #endif
133
134 struct Nes_Cpu cpu;
135 struct Nes_Apu apu;
136
137 // Header for currently loaded file
138 struct header_t header;
139
140 struct Stereo_Buffer stereo_buf;
141 struct Rom_Data rom;
142
143 // Extended nsf info
144 struct Nsfe_Info info;
145
146 sample_t buf [buf_size];
147 byte high_ram[fdsram_size + fdsram_offset];
148 byte low_ram [low_ram_size];
149};
150
151// Basic functionality (see Gme_File.h for file loading/track info functions)
152
153void Nsf_init( struct Nsf_Emu* this );
154blargg_err_t Nsf_load( struct Nsf_Emu* this, void* data, long size );
155blargg_err_t Nsf_post_load( struct Nsf_Emu* this );
156
157// Set output sample rate. Must be called only once before loading file.
158blargg_err_t Nsf_set_sample_rate( struct Nsf_Emu* this, long sample_rate );
159
160// Start a track, where 0 is the first track. Also clears warning string.
161blargg_err_t Nsf_start_track( struct Nsf_Emu* this , int );
162
163// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation
164// errors set warning string, and major errors also end track.
165blargg_err_t Nsf_play( struct Nsf_Emu* this, long count, sample_t* buf );
166
167void Nsf_clear_playlist( struct Nsf_Emu* this );
168void Nsf_disable_playlist( struct Nsf_Emu* this, bool b ); // use clear_playlist()
169
170// Track status/control
171
172// Number of milliseconds (1000 msec = 1 second) played since beginning of track
173long Track_tell( struct Nsf_Emu* this );
174
175// Seek to new time in track. Seeking backwards or far forward can take a while.
176blargg_err_t Track_seek( struct Nsf_Emu* this, long msec );
177
178// Skip n samples
179blargg_err_t Track_skip( struct Nsf_Emu* this, long n );
180
181// Set start time and length of track fade out. Once fade ends track_ended() returns
182// true. Fade time can be changed while track is playing.
183void Track_set_fade( struct Nsf_Emu* this, long start_msec, long length_msec );
184
185// Get track length in milliseconds
186long Track_length( struct Nsf_Emu* this, int n );
187
188// Sound customization
189
190// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed.
191// Track length as returned by track_info() assumes a tempo of 1.0.
192void Sound_set_tempo( struct Nsf_Emu* this, double t );
193
194// Mute/unmute voice i, where voice 0 is first voice
195void Sound_mute_voice( struct Nsf_Emu* this, int index, bool mute );
196
197// Set muting state of all voices at once using a bit mask, where -1 mutes them all,
198// 0 unmutes them all, 0x01 mutes just the first voice, etc.
199void Sound_mute_voices( struct Nsf_Emu* this, int mask );
200
201// Change overall output amplitude, where 1.0 results in minimal clamping.
202// Must be called before set_sample_rate().
203static inline void Sound_set_gain( struct Nsf_Emu* this, double g )
204{
205 assert( !this->sample_rate ); // you must set gain before setting sample rate
206 this->gain = g;
207}
208
209// Emulation (You shouldn't touch these)
210
211blargg_err_t run_clocks( struct Nsf_Emu* this, blip_time_t* duration, int );
212
213void map_memory( struct Nsf_Emu* this ) ICODE_ATTR;
214void write_bank( struct Nsf_Emu* this, int index, int data ) ICODE_ATTR;
215int cpu_read( struct Nsf_Emu* this, addr_t ) ICODE_ATTR;
216void cpu_write( struct Nsf_Emu* this, addr_t, int ) ICODE_ATTR;
217void push_byte( struct Nsf_Emu* this, int ) ICODE_ATTR;
218addr_t get_addr( byte const [] ) ICODE_ATTR;
219bool run_cpu_until( struct Nsf_Emu* this, nes_time_t end ) ICODE_ATTR;
220
221// Sets clocks between calls to play routine to p + 1/2 clock
222static inline void set_play_period( struct Nsf_Emu* this, int p ) { this->play_period = p; }
223
224// Time play routine will next be called
225static inline nes_time_t play_time( struct Nsf_Emu* this ) { return this->next_play; }
226
227// Emulates to at least time t. Might emulate a few clocks extra.
228void run_until( struct Nsf_Emu* this, nes_time_t t ) ICODE_ATTR;
229
230// Runs cpu to at least time t and returns false, or returns true
231// if it encounters illegal instruction (halt).
232bool run_cpu_until( struct Nsf_Emu* this, nes_time_t t ) ICODE_ATTR;
233
234// cpu calls through to these to access memory (except instructions)
235int read_mem( struct Nsf_Emu* this, addr_t ) ICODE_ATTR;
236void write_mem( struct Nsf_Emu* this, addr_t, int ) ICODE_ATTR;
237
238// Address of play routine
239static inline addr_t play_addr( struct Nsf_Emu* this ) { return get_addr( this->header.play_addr ); }
240
241// Same as run_until, except emulation stops for any event (routine returned,
242// play routine called, illegal instruction).
243void run_once( struct Nsf_Emu* this, nes_time_t ) ICODE_ATTR;
244
245// Reads byte as cpu would when executing code. Only works for RAM/ROM,
246// NOT I/O like sound chips.
247int read_code( struct Nsf_Emu* this, addr_t addr ) ICODE_ATTR;
248
249static inline byte* fdsram( struct Nsf_Emu* this ) { return &this->high_ram [fdsram_offset]; }
250static inline byte* sram( struct Nsf_Emu* this ) { return this->high_ram; }
251static inline byte* unmapped_code( struct Nsf_Emu* this ) { return &this->high_ram [sram_size]; }
252
253#ifndef NSF_EMU_APU_ONLY
254static inline int fds_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & fds_flag; }
255static inline int vrc6_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & vrc6_flag; }
256static inline int vrc7_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & vrc7_flag; }
257static inline int mmc5_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & mmc5_flag; }
258static inline int namco_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & namco_flag; }
259static inline int fme7_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & fme7_flag; }
260#endif
261
262#endif
diff --git a/apps/codecs/libgme/nsfe_info.c b/apps/codecs/libgme/nsfe_info.c
new file mode 100644
index 0000000000..d22b763173
--- /dev/null
+++ b/apps/codecs/libgme/nsfe_info.c
@@ -0,0 +1,272 @@
1// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/
2
3#include "nsf_emu.h"
4
5#include "blargg_endian.h"
6#include <string.h>
7
8/* Copyright (C) 2005-2006 Shay Green. This module is free software; you
9can redistribute it and/or modify it under the terms of the GNU Lesser
10General Public License as published by the Free Software Foundation; either
11version 2.1 of the License, or (at your option) any later version. This
12module is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15details. You should have received a copy of the GNU Lesser General Public
16License along with this module; if not, write to the Free Software Foundation,
17Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19#include "blargg_source.h"
20
21void Info_init( struct Nsfe_Info* this )
22{
23 this->playlist_disabled = false;
24}
25
26void Info_unload( struct Nsfe_Info* this )
27{
28 memset(this->playlist, 0, 256);
29 memset(this->track_times, 0, 256 * sizeof(int32_t));
30
31 this->playlist_size = 0;
32 this->track_times_size = 0;
33}
34
35// TODO: if no playlist, treat as if there is a playlist that is just 1,2,3,4,5... ?
36void Info_disable_playlist( struct Nsfe_Info* this, bool b )
37{
38 this->playlist_disabled = b;
39 this->track_count = this->playlist_size;
40 if ( !this->track_count || this->playlist_disabled )
41 this->track_count = this->actual_track_count_;
42}
43
44int Info_remap_track( struct Nsfe_Info* this, int track )
45{
46 if ( !this->playlist_disabled && (unsigned) track < (unsigned) this->playlist_size )
47 track = this->playlist [track];
48 return track;
49}
50
51const char eof_error [] = "Unexpected end of file";
52
53// Read n bytes from memory buffer
54static blargg_err_t in_read( void* dst, long bytes, void* data, long* offset, long size )
55{
56 if ((*offset + bytes) > size) return eof_error;
57
58 memcpy(dst, (char*) data + *offset, bytes);
59 *offset += bytes;
60 return 0;
61}
62
63static blargg_err_t in_skip( long bytes, long *offset, long size )
64{
65 if ((*offset + bytes) > size) return eof_error;
66
67 *offset += bytes;
68 return 0;
69}
70
71// Skip n bytes from memory buffer
72
73// Read multiple strings and separate into individual strings
74static int read_strs( void* data, long bytes, long* offset, long size,
75 const char* strs [4] )
76{
77 char* chars = (char*) data + *offset;
78 chars [bytes - 1] = 0; // in case last string doesn't have terminator
79
80 if ( in_skip( bytes, offset, size) )
81 return -1;
82
83 int count = 0, i;
84 for ( i = 0; i < bytes; i++ )
85 {
86 strs [count] = &chars [i];
87 while ( i < bytes && chars [i] )
88 i++;
89
90 count++;
91 if (count >= 4)
92 break;
93 }
94
95 return count;
96}
97
98struct nsfe_info_t
99{
100 byte load_addr [2];
101 byte init_addr [2];
102 byte play_addr [2];
103 byte speed_flags;
104 byte chip_flags;
105 byte track_count;
106 byte first_track;
107 byte unused [6];
108};
109
110blargg_err_t Info_load( struct Nsfe_Info* this, void* data, long size, struct Nsf_Emu* nsf_emu )
111{
112 long offset = 0;
113 int const nsfe_info_size = 16;
114 assert( offsetof (struct nsfe_info_t,unused [6]) == nsfe_info_size );
115
116 // check header
117 byte signature [4];
118 blargg_err_t err = in_read( signature, sizeof signature, data, &offset, size );
119 if ( err )
120 return (err == eof_error ? gme_wrong_file_type : err);
121 if ( memcmp( signature, "NSFE", 4 ) ) {
122 }
123
124 // free previous info
125 /* TODO: clear track_names */
126 memset(this->playlist, 0, 256);
127 memset(this->track_times, 0, 256 * sizeof(int32_t));
128
129 this->playlist_size = 0;
130 this->track_times_size = 0;
131
132 // default nsf header
133 static const struct header_t base_header =
134 {
135 {'N','E','S','M','\x1A'},// tag
136 1, // version
137 1, 1, // track count, first track
138 {0,0},{0,0},{0,0}, // addresses
139 "","","", // strings
140 {0x1A, 0x41}, // NTSC rate
141 {0,0,0,0,0,0,0,0}, // banks
142 {0x20, 0x4E}, // PAL rate
143 0, 0, // flags
144 {0,0,0,0} // unused
145 };
146
147 memcpy( &nsf_emu->header, &base_header, sizeof base_header );
148
149 // parse tags
150 int phase = 0;
151 while ( phase != 3 )
152 {
153 // read size and tag
154 byte block_header [2] [4];
155 RETURN_ERR( in_read( block_header, sizeof block_header, data, &offset, size ) );
156
157 blargg_long chunk_size = get_le32( block_header [0] );
158 blargg_long tag = get_le32( block_header [1] );
159
160 switch ( tag )
161 {
162 case BLARGG_4CHAR('O','F','N','I'): {
163 check( phase == 0 );
164 if ( chunk_size < 8 )
165 return "Corrupt file";
166
167 struct nsfe_info_t finfo;
168 finfo.track_count = 1;
169 finfo.first_track = 0;
170
171 RETURN_ERR( in_read( &finfo, min( chunk_size, (blargg_long) nsfe_info_size ),
172 (char*) data, &offset, size ) );
173
174 if ( chunk_size > nsfe_info_size )
175 RETURN_ERR( in_skip( chunk_size - nsfe_info_size, &offset, size ) );
176
177 phase = 1;
178 nsf_emu->header.speed_flags = finfo.speed_flags;
179 nsf_emu->header.chip_flags = finfo.chip_flags;
180 nsf_emu->header.track_count = finfo.track_count;
181 this->actual_track_count_ = finfo.track_count;
182 nsf_emu->header.first_track = finfo.first_track;
183 memcpy( nsf_emu->header.load_addr, finfo.load_addr, 2 * 3 );
184 break;
185 }
186
187 case BLARGG_4CHAR('K','N','A','B'):
188 if ( chunk_size > (int) sizeof nsf_emu->header.banks )
189 return "Corrupt file";
190 RETURN_ERR( in_read( nsf_emu->header.banks, chunk_size, data, &offset, size ) );
191 break;
192
193 case BLARGG_4CHAR('h','t','u','a'): {
194 const char* strs [4];
195 int n = read_strs( data, chunk_size, &offset, size, strs );
196 if ( n < 0 )
197 return eof_error;
198 break;
199 }
200
201 case BLARGG_4CHAR('e','m','i','t'):
202 this->track_times_size = chunk_size / 4;
203 RETURN_ERR( in_read( this->track_times, this->track_times_size * 4, data, &offset, size ) );
204 break;
205
206 case BLARGG_4CHAR('l','b','l','t'):
207 RETURN_ERR( in_skip( chunk_size, &offset, size ) );
208 break;
209
210 case BLARGG_4CHAR('t','s','l','p'):
211 this->playlist_size = chunk_size;
212 RETURN_ERR( in_read( &this->playlist [0], chunk_size, data, &offset, size ) );
213 break;
214
215 case BLARGG_4CHAR('A','T','A','D'): {
216 check( phase == 1 );
217 phase = 2;
218 if ( !nsf_emu )
219 {
220 RETURN_ERR( in_skip( chunk_size, &offset, size ) );
221 }
222 else
223 {
224 // Avoid unexpected end of file
225 if ( (offset + chunk_size) > size )
226 return eof_error;
227
228 RETURN_ERR( Rom_load( &nsf_emu->rom, (char*) data + offset, chunk_size, 0, 0, 0 ) );
229 RETURN_ERR( Nsf_post_load( nsf_emu ) );
230 offset += chunk_size;
231 }
232 break;
233 }
234
235 case BLARGG_4CHAR('D','N','E','N'):
236 check( phase == 2 );
237 phase = 3;
238 break;
239
240 default:
241 // tags that can be skipped start with a lowercase character
242 check( islower( (tag >> 24) & 0xFF ) );
243 RETURN_ERR( in_skip( chunk_size, &offset, size ) );
244 break;
245 }
246 }
247
248 return 0;
249}
250
251long Track_length( struct Nsf_Emu* this, int n )
252{
253 long length = 0;
254 if ( (this->m3u.size > 0) && (n < this->m3u.size) ) {
255 struct entry_t* entry = &this->m3u.entries [n];
256 length = entry->length;
257 }
258 else if ( (this->info.playlist_size > 0) && (n < this->info.playlist_size) ) {
259 int remapped = Info_remap_track( &this->info, n );
260 if ( (unsigned) remapped < (unsigned) this->info.track_times_size )
261 length = (int32_t) get_le32( &this->info.track_times [remapped] );
262 }
263 else if( (unsigned) n < (unsigned) this->info.track_times_size )
264 length = (int32_t) get_le32( &this->info.track_times [n] );
265
266 /* Length will be 2,30 minutes for one track songs,
267 and 1,45 minutes for multitrack songs */
268 if ( length <= 0 )
269 length = (this->track_count > 1 ? 105 : 150) * 1000;
270
271 return length;
272}
diff --git a/apps/codecs/libgme/nsfe_info.h b/apps/codecs/libgme/nsfe_info.h
new file mode 100644
index 0000000000..9dcde7b68a
--- /dev/null
+++ b/apps/codecs/libgme/nsfe_info.h
@@ -0,0 +1,30 @@
1// Nintendo NES/Famicom NSFE file info parser
2
3// Game_Music_Emu 0.5.5
4#ifndef NSFE_INFO_H
5#define NSFE_INFO_H
6
7#include "blargg_common.h"
8
9struct Nsf_Emu;
10
11// Allows reading info from NSFE file without creating emulator
12struct Nsfe_Info {
13 int playlist_size;
14 int track_times_size;
15 int track_count;
16 int actual_track_count_;
17 bool playlist_disabled;
18
19 unsigned char playlist [256];
20 int32_t track_times [256];
21};
22
23void Info_init( struct Nsfe_Info* this );
24blargg_err_t Info_load( struct Nsfe_Info* this, void *data, long size, struct Nsf_Emu* );
25void Info_disable_playlist( struct Nsfe_Info* this, bool b );
26int Info_remap_track( struct Nsfe_Info* this, int i );
27void Info_unload( struct Nsfe_Info* this );
28
29
30#endif
diff --git a/apps/codecs/libgme/opl_apu.c b/apps/codecs/libgme/opl_apu.c
new file mode 100644
index 0000000000..bde5e9e26e
--- /dev/null
+++ b/apps/codecs/libgme/opl_apu.c
@@ -0,0 +1,198 @@
1#include "opl_apu.h"
2
3#include "blargg_source.h"
4
5/* NOTE: Removed unused chips ~ gama */
6
7blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type )
8{
9 Synth_init( &this->synth );
10
11 this->type_ = type;
12 this->clock_ = clock;
13 this->rate_ = rate;
14 this->period_ = period;
15 Opl_set_output( this, 0 );
16 Opl_volume( this, 1.0 );
17
18 switch (type)
19 {
20 case type_opll:
21 case type_msxmusic:
22 case type_smsfmunit:
23 OPLL_new ( &this->opll, clock, rate );
24 OPLL_reset_patch( &this->opll, OPLL_2413_TONE );
25 break;
26 case type_vrc7:
27 OPLL_new ( &this->opll, clock, rate );
28 OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE );
29 break;
30 case type_msxaudio:
31 OPL_init( &this->opl, this->opl_memory, sizeof this->opl_memory );
32 OPL_setSampleRate( &this->opl, rate, clock );
33 OPL_setInternalVolume(&this->opl, 1 << 13);
34 break;
35 }
36
37 Opl_reset( this );
38 return 0;
39}
40
41void Opl_shutdown( struct Opl_Apu* this )
42{
43 switch (this->type_)
44 {
45 case type_opll:
46 case type_msxmusic:
47 case type_smsfmunit:
48 case type_vrc7:
49 OPLL_delete( &this->opll );
50 break;
51 case type_msxaudio: break;
52 }
53}
54
55void Opl_reset( struct Opl_Apu* this )
56{
57 this->addr = 0;
58 this->next_time = 0;
59 this->last_amp = 0;
60
61 switch (this->type_)
62 {
63 case type_opll:
64 case type_msxmusic:
65 case type_smsfmunit:
66 case type_vrc7:
67 OPLL_reset( &this->opll );
68 OPLL_setMask( &this->opll, 0 );
69 break;
70 case type_msxaudio:
71 OPL_reset( &this->opl );
72 break;
73 }
74}
75
76static void run_until( struct Opl_Apu* this, blip_time_t end_time );
77void Opl_write_data( struct Opl_Apu* this, blip_time_t time, int data )
78{
79 run_until( this, time );
80 switch (this->type_)
81 {
82 case type_opll:
83 case type_msxmusic:
84 case type_smsfmunit:
85 case type_vrc7:
86 OPLL_writeIO( &this->opll, 0, this->addr );
87 OPLL_writeIO( &this->opll, 1, data );
88 break;
89 case type_msxaudio:
90 OPL_writeReg( &this->opl, this->addr, data );
91 break;
92 }
93}
94
95int Opl_read( struct Opl_Apu* this, blip_time_t time, int port )
96{
97 run_until( this, time );
98 switch (this->type_)
99 {
100 case type_opll:
101 case type_msxmusic:
102 case type_smsfmunit:
103 case type_vrc7:
104 return OPLL_read( &this->opll, port );
105 case type_msxaudio:
106 return OPL_readStatus( &this->opl );
107 }
108
109 return 0;
110}
111
112void Opl_end_frame( struct Opl_Apu* this, blip_time_t time )
113{
114 run_until( this, time );
115 this->next_time -= time;
116
117 if ( this->output_ )
118 Blip_set_modified( this->output_ );
119}
120
121static void run_until( struct Opl_Apu* this, blip_time_t end_time )
122{
123 if ( end_time > this->next_time )
124 {
125 blip_time_t time_delta = end_time - this->next_time;
126 blip_time_t time = this->next_time;
127 unsigned count = time_delta / this->period_ + 1;
128 switch (this->type_)
129 {
130 case type_opll:
131 case type_msxmusic:
132 case type_smsfmunit:
133 case type_vrc7:
134 {
135 OPLL* opll = &this->opll; // cache
136 struct Blip_Buffer* const output = this->output_;
137 while ( count > 0 )
138 {
139 unsigned todo = count;
140 if ( todo > 1024 ) todo = 1024;
141 short *buffer = OPLL_update_buffer(opll, todo);
142
143 if ( output && buffer )
144 {
145 int last_amp = this->last_amp;
146 unsigned i;
147 for ( i = 0; i < todo; i++ )
148 {
149 int amp = buffer [i];
150 int delta = amp - last_amp;
151 if ( delta )
152 {
153 last_amp = amp;
154 Synth_offset_inline( &this->synth, time, delta, output );
155 }
156 time += this->period_;
157 }
158 this->last_amp = last_amp;
159 }
160 count -= todo;
161 }
162 }
163 break;
164 case type_msxaudio:
165 {
166 struct Y8950* opl = &this->opl;
167 struct Blip_Buffer* const output = this->output_;
168 while ( count > 0 )
169 {
170 unsigned todo = count;
171 if ( todo > 1024 ) todo = 1024;
172 int *buffer = OPL_updateBuffer(opl, todo);
173
174 if ( output && buffer )
175 {
176 int last_amp = this->last_amp;
177 unsigned i;
178 for ( i = 0; i < todo; i++ )
179 {
180 int amp = buffer [i];
181 int delta = amp - last_amp;
182 if ( delta )
183 {
184 last_amp = amp;
185 Synth_offset_inline( &this->synth, time, delta, output );
186 }
187 time += this->period_;
188 }
189 this->last_amp = last_amp;
190 }
191 count -= todo;
192 }
193 }
194 break;
195 }
196 this->next_time = time;
197 }
198}
diff --git a/apps/codecs/libgme/opl_apu.h b/apps/codecs/libgme/opl_apu.h
new file mode 100644
index 0000000000..3f5a751976
--- /dev/null
+++ b/apps/codecs/libgme/opl_apu.h
@@ -0,0 +1,62 @@
1#ifndef OPL_APU_H
2#define OPL_APU_H
3
4#include "blargg_common.h"
5#include "blargg_source.h"
6#include "blip_buffer.h"
7
8#include "emu8950.h"
9#include "emu2413.h"
10
11enum opl_type_t { type_opll = 0x10, type_msxmusic = 0x11, type_smsfmunit = 0x12,
12 type_vrc7 = 0x13, type_msxaudio = 0x21 };
13
14enum { opl_osc_count = 1 };
15
16struct Opl_Apu {
17 struct Blip_Buffer* output_;
18 enum opl_type_t type_;
19
20 blip_time_t next_time;
21 int last_amp;
22 int addr;
23
24 long clock_;
25 long rate_;
26 blip_time_t period_;
27
28 struct Blip_Synth synth;
29
30 // OPL chips
31 struct Y8950 opl;
32 OPLL opll;
33
34 unsigned char regs[ 0x100 ];
35 unsigned char opl_memory[ 32768 ];
36};
37
38blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type );
39
40void Opl_reset( struct Opl_Apu* this );
41static inline void Opl_volume( struct Opl_Apu* this, double v ) { Synth_volume( &this->synth, 1.0 / (4096 * 6) * v ); }
42
43static inline void Opl_osc_output( struct Opl_Apu* this, int i, struct Blip_Buffer* buf )
44{
45#if defined(ROCKBOX)
46 (void) i;
47#endif
48 assert( (unsigned) i < opl_osc_count );
49 this->output_ = buf;
50}
51
52static inline void Opl_set_output( struct Opl_Apu* this, struct Blip_Buffer* buf ) { Opl_osc_output( this, 0, buf ); }
53void Opl_end_frame( struct Opl_Apu* this, blip_time_t ) ICODE_ATTR;
54
55static inline void Opl_write_addr( struct Opl_Apu* this, int data ) { this->addr = data; }
56void Opl_write_data( struct Opl_Apu* this, blip_time_t, int data ) ICODE_ATTR;
57
58int Opl_read( struct Opl_Apu* this, blip_time_t, int port ) ICODE_ATTR;
59
60static inline bool Opl_supported( void ) { return true; }
61
62#endif
diff --git a/apps/codecs/libgme/opltables.h b/apps/codecs/libgme/opltables.h
new file mode 100644
index 0000000000..1414f2264b
--- /dev/null
+++ b/apps/codecs/libgme/opltables.h
@@ -0,0 +1,242 @@
1#ifndef _OPLTABLES_H_
2#define _OPLTABLES_H_
3
4/* Precalculated emu8950 tables for use in Rockbox,
5 Calculated for 44Khz sampling rate */
6
7static const short ar_adjust_coeff[] ICONST_ATTR = {
8 255, 227, 210, 198, 189, 181, 175, 170, 165, 161, 157,
9 153, 150, 147, 144, 141, 139, 136, 134, 132, 130, 128,
10 126, 125, 123, 121, 120, 118, 117, 115, 114, 113, 112,
11 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100,
12 99, 98, 97, 96, 95, 94, 94, 93, 92, 91, 91,
13 90, 89, 88, 88, 87, 86, 86, 85, 84, 84, 83,
14 82, 82, 81, 81, 80, 79, 79, 78, 78, 77, 77,
15 76, 76, 75, 75, 74, 74, 73, 73, 72, 72, 71,
16 71, 70, 70, 69, 69, 69, 68, 68, 67, 67, 66,
17 66, 66, 65, 65, 64, 64, 64, 63, 63, 62, 62,
18 62, 61, 61, 61, 60, 60, 60, 59, 59, 59, 58,
19 58, 58, 57, 57, 57, 56, 56, 56, 55, 55, 55,
20 54, 54, 54, 53, 53, 53, 53, 52, 52, 52, 51,
21 51, 51, 50, 50, 50, 50, 49, 49, 49, 49, 48,
22 48, 48, 48, 47, 47, 47, 46, 46, 46, 46, 45,
23 45, 45, 45, 44, 44, 44, 44, 44, 43, 43, 43,
24 43, 42, 42, 42, 42, 41, 41, 41, 41, 41, 40,
25 40, 40, 40, 39, 39, 39, 39, 39, 38, 38, 38,
26 38, 38, 37, 37, 37, 37, 37, 36, 36, 36, 36,
27 36, 35, 35, 35, 35, 35, 34, 34, 34, 34, 34,
28 33, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32,
29 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30,
30 30, 29, 29, 29, 29, 29, 29, 28, 28, 28, 28,
31 28, 28, 27, 27, 27, 27, 27, 27, 26, 26, 26,
32 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25,
33 24, 24, 24, 24, 24, 24, 23, 23, 23, 23, 23,
34 23, 23, 22, 22, 22, 22, 22, 22, 22, 21, 21,
35 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20,
36 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 18,
37 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17,
38 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16,
39 16, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14,
40 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13,
41 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12,
42 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
43 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
44 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8,
45 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7,
46 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
47 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5,
48 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,
49 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3,
50 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2,
51 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
52 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54 0, 0, 0, 0, 0
55};
56
57static const short db2lin_coeff[] ICONST_ATTR = {
58 2047, 2003, 1960, 1918, 1877, 1837, 1798, 1759, 1722, 1685, 1649,
59 1614, 1579, 1546, 1513, 1480, 1449, 1418, 1387, 1358, 1329, 1300,
60 1273, 1245, 1219, 1193, 1167, 1142, 1118, 1094, 1071, 1048, 1025,
61 1004, 982, 961, 941, 920, 901, 882, 863, 844, 826, 809,
62 791, 774, 758, 742, 726, 710, 695, 680, 666, 651, 638,
63 624, 611, 598, 585, 572, 560, 548, 536, 525, 514, 503,
64 492, 481, 471, 461, 451, 442, 432, 423, 414, 405, 396,
65 388, 380, 371, 364, 356, 348, 341, 333, 326, 319, 312,
66 306, 299, 293, 287, 280, 274, 269, 263, 257, 252, 246,
67 241, 236, 231, 226, 221, 216, 212, 207, 203, 198, 194,
68 190, 186, 182, 178, 174, 170, 167, 163, 160, 156, 153,
69 150, 147, 143, 140, 137, 134, 131, 129, 126, 123, 121,
70 118, 115, 113, 111, 108, 106, 104, 101, 99, 97, 95,
71 93, 91, 89, 87, 85, 83, 82, 80, 78, 76, 75,
72 73, 72, 70, 69, 67, 66, 64, 63, 61, 60, 59,
73 58, 56, 55, 54, 53, 52, 51, 49, 48, 47, 46,
74 45, 44, 43, 42, 42, 41, 40, 39, 38, 37, 36,
75 36, 35, 34, 33, 33, 32, 31, 31, 30, 29, 29,
76 28, 27, 27, 26, 26, 25, 25, 24, 23, 23, 22,
77 22, 21, 21, 21, 20, 20, 19, 19, 18, 18, 18,
78 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 14,
79 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11,
80 11, 10, 10, 10, 10, 9, 9, 9, 9, 9, 8,
81 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7,
82 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5,
83 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4,
84 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3,
85 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
86 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
87 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
88 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
89 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
90 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
92 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
98 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104 0, 0, 0, 0, 0, 0
105};
106
107static const short sin_coeff[] ICONST_ATTR = {
108 511, 235, 203, 185, 171, 161, 152, 145, 139, 134, 129,
109 124, 120, 117, 113, 110, 107, 104, 102, 99, 97, 95,
110 92, 90, 88, 87, 85, 83, 81, 80, 78, 77, 75,
111 74, 72, 71, 70, 69, 67, 66, 65, 64, 63, 62,
112 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 52,
113 51, 50, 49, 48, 48, 47, 46, 45, 45, 44, 43,
114 43, 42, 41, 41, 40, 39, 39, 38, 38, 37, 37,
115 36, 35, 35, 34, 34, 33, 33, 32, 32, 31, 31,
116 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26,
117 25, 25, 25, 24, 24, 23, 23, 23, 22, 22, 22,
118 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18,
119 18, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15,
120 14, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12,
121 12, 11, 11, 11, 11, 11, 10, 10, 10, 10, 9,
122 9, 9, 9, 9, 8, 8, 8, 8, 8, 7, 7,
123 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5,
124 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4,
125 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3,
126 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
127 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
128 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
129 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131 0, 0, 0,
132};
133
134static const short pm0_coeff[] ICONST_ATTR = {
135 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
136 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
137 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
138 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
139 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
140 256, 256, 257, 257, 257, 257, 257, 257, 257, 257, 257,
141 257, 257, 257, 257, 257, 257, 256, 256, 256, 256, 256,
142 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
143 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
144 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
145 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
146 256, 256, 256, 256, 256, 256, 256, 256, 255, 255, 255,
147 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
148 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
149 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
150 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
151 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254,
152 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
153 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
154 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
155 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
156 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
157 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
158 255, 255, 255,
159};
160
161static const short pm1_coeff[] ICONST_ATTR = {
162 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
163 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 257,
164 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
165 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
166 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
167 257, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258,
168 258, 258, 258, 258, 258, 258, 258, 257, 257, 257, 257,
169 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
170 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
171 257, 257, 257, 257, 257, 257, 257, 257, 257, 256, 256,
172 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
173 256, 256, 256, 256, 256, 256, 256, 256, 255, 255, 255,
174 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
175 255, 255, 255, 255, 255, 255, 254, 254, 254, 254, 254,
176 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
177 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
178 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 253,
179 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
180 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
181 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
182 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
183 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255,
184 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
185 255, 255, 255,
186};
187
188static const short am0_coeff[] ICONST_ATTR = {
189 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
190 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
191 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
192 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
193 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
194 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
195 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
196 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4,
197 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
198 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3,
199 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
200 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2,
201 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1,
202 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
203 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
204 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
205 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
206 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
207 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
209 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
210 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
211 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
212 2, 2, 2,
213};
214
215static const short am1_coeff[] ICONST_ATTR = {
216 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15,
217 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 19,
218 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
219 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23,
220 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25,
221 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
222 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
223 24, 24, 24, 24, 24, 24, 24, 24, 23, 23, 23,
224 23, 23, 23, 22, 22, 22, 22, 22, 21, 21, 21,
225 21, 20, 20, 20, 20, 19, 19, 19, 19, 18, 18,
226 18, 17, 17, 17, 17, 16, 16, 16, 15, 15, 15,
227 14, 14, 14, 14, 13, 13, 13, 12, 12, 12, 11,
228 11, 11, 10, 10, 10, 9, 9, 9, 9, 8, 8,
229 8, 7, 7, 7, 7, 6, 6, 6, 5, 5, 5,
230 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2,
231 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
234 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
235 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
236 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5,
237 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8,
238 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11,
239 11, 12, 12,
240};
241
242#endif
diff --git a/apps/codecs/libgme/resampler.c b/apps/codecs/libgme/resampler.c
new file mode 100644
index 0000000000..bcd98f68d2
--- /dev/null
+++ b/apps/codecs/libgme/resampler.c
@@ -0,0 +1,320 @@
1// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/
2
3#include "resampler.h"
4
5#include <stdlib.h>
6#include <string.h>
7
8/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
9can redistribute it and/or modify it under the terms of the GNU Lesser
10General Public License as published by the Free Software Foundation; either
11version 2.1 of the License, or (at your option) any later version. This
12module is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15details. You should have received a copy of the GNU Lesser General Public
16License along with this module; if not, write to the Free Software Foundation,
17Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19#include "blargg_source.h"
20
21// TODO: fix this. hack since resampler holds back some output.
22unsigned const resampler_extra = 34;
23
24enum { shift = 14 };
25int const unit = 1 << shift;
26
27blargg_err_t Resampler_setup( struct Resampler* this, double oversample, double rolloff, double gain )
28{
29 (void) rolloff;
30
31 this->gain_ = (int)((1 << gain_bits) * gain);
32 this->step = (int) ( oversample * unit + 0.5);
33 this->rate_ = 1.0 / unit * this->step;
34 return 0;
35}
36
37blargg_err_t Resampler_reset( struct Resampler* this, int pairs )
38{
39 // expand allocations a bit
40 Resampler_resize( this, pairs );
41 this->resampler_size = this->oversamples_per_frame + (this->oversamples_per_frame >> 2);
42
43 this->buffer_size = this->resampler_size;
44 this->pos = 0;
45 this->write_pos = 0;
46 return 0;
47}
48
49void Resampler_resize( struct Resampler* this, int pairs )
50{
51 int new_sample_buf_size = pairs * 2;
52 if ( this->sample_buf_size != new_sample_buf_size )
53 {
54 this->sample_buf_size = new_sample_buf_size;
55 this->oversamples_per_frame = (int) (pairs * this->rate_) * 2 + 2;
56 Resampler_clear( this );
57 }
58}
59
60void mix_mono( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out_ )
61{
62 int const bass = BLIP_READER_BASS( stereo_buf->bufs [0] );
63 BLIP_READER_BEGIN( sn, stereo_buf->bufs [0] );
64
65 int count = this->sample_buf_size >> 1;
66 BLIP_READER_ADJ_( sn, count );
67
68 typedef dsample_t stereo_dsample_t [2];
69 stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count;
70 stereo_dsample_t const* BLARGG_RESTRICT in =
71 (stereo_dsample_t const*) this->sample_buf + count;
72 int offset = -count;
73 int const gain = this->gain_;
74 do
75 {
76 int s = BLIP_READER_READ_RAW( sn ) >> (blip_sample_bits - 16);
77 BLIP_READER_NEXT_IDX_( sn, bass, offset );
78
79 int l = (in [offset] [0] * gain >> gain_bits) + s;
80 int r = (in [offset] [1] * gain >> gain_bits) + s;
81
82 BLIP_CLAMP( l, l );
83 out [offset] [0] = (blip_sample_t) l;
84
85 BLIP_CLAMP( r, r );
86 out [offset] [1] = (blip_sample_t) r;
87 }
88 while ( ++offset );
89
90 BLIP_READER_END( sn, stereo_buf->bufs [0] );
91}
92
93void mix_stereo( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out_ )
94{
95 int const bass = BLIP_READER_BASS( stereo_buf->bufs [0] );
96 BLIP_READER_BEGIN( snc, stereo_buf->bufs [0] );
97 BLIP_READER_BEGIN( snl, stereo_buf->bufs [1] );
98 BLIP_READER_BEGIN( snr, stereo_buf->bufs [2] );
99
100 int count = this->sample_buf_size >> 1;
101 BLIP_READER_ADJ_( snc, count );
102 BLIP_READER_ADJ_( snl, count );
103 BLIP_READER_ADJ_( snr, count );
104
105 typedef dsample_t stereo_dsample_t [2];
106 stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count;
107 stereo_dsample_t const* BLARGG_RESTRICT in =
108 (stereo_dsample_t const*) this->sample_buf + count;
109 int offset = -count;
110 int const gain = this->gain_;
111 do
112 {
113 int sc = BLIP_READER_READ_RAW( snc ) >> (blip_sample_bits - 16);
114 int sl = BLIP_READER_READ_RAW( snl ) >> (blip_sample_bits - 16);
115 int sr = BLIP_READER_READ_RAW( snr ) >> (blip_sample_bits - 16);
116 BLIP_READER_NEXT_IDX_( snc, bass, offset );
117 BLIP_READER_NEXT_IDX_( snl, bass, offset );
118 BLIP_READER_NEXT_IDX_( snr, bass, offset );
119
120 int l = (in [offset] [0] * gain >> gain_bits) + sl + sc;
121 int r = (in [offset] [1] * gain >> gain_bits) + sr + sc;
122
123 BLIP_CLAMP( l, l );
124 out [offset] [0] = (blip_sample_t) l;
125
126 BLIP_CLAMP( r, r );
127 out [offset] [1] = (blip_sample_t) r;
128 }
129 while ( ++offset );
130
131 BLIP_READER_END( snc, stereo_buf->bufs [0] );
132 BLIP_READER_END( snl, stereo_buf->bufs [1] );
133 BLIP_READER_END( snr, stereo_buf->bufs [2] );
134}
135
136void mix_stereo_no_center( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out_ )
137{
138 int const bass = BLIP_READER_BASS( stereo_buf->bufs [0] );
139 BLIP_READER_BEGIN( snl, stereo_buf->bufs [1] );
140 BLIP_READER_BEGIN( snr, stereo_buf->bufs [2] );
141
142 int count = this->sample_buf_size >> 1;
143 BLIP_READER_ADJ_( snl, count );
144 BLIP_READER_ADJ_( snr, count );
145
146 typedef dsample_t stereo_dsample_t [2];
147 stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count;
148 stereo_dsample_t const* BLARGG_RESTRICT in =
149 (stereo_dsample_t const*) this->sample_buf + count;
150 int offset = -count;
151 int const gain = this->gain_;
152 do
153 {
154 int sl = BLIP_READER_READ_RAW( snl ) >> (blip_sample_bits - 16);
155 int sr = BLIP_READER_READ_RAW( snr ) >> (blip_sample_bits - 16);
156 BLIP_READER_NEXT_IDX_( snl, bass, offset );
157 BLIP_READER_NEXT_IDX_( snr, bass, offset );
158
159 int l = (in [offset] [0] * gain >> gain_bits) + sl;
160 int r = (in [offset] [1] * gain >> gain_bits) + sr;
161
162 BLIP_CLAMP( l, l );
163 out [offset] [0] = (blip_sample_t) l;
164
165 BLIP_CLAMP( r, r );
166 out [offset] [1] = (blip_sample_t) r;
167 }
168 while ( ++offset );
169
170 BLIP_READER_END( snl, stereo_buf->bufs [1] );
171 BLIP_READER_END( snr, stereo_buf->bufs [2] );
172}
173
174dsample_t const* resample_( struct Resampler* this, dsample_t** out_,
175 dsample_t const* out_end, dsample_t const in [], int in_size )
176{
177 in_size -= write_offset;
178 if ( in_size > 0 )
179 {
180 dsample_t* BLIP_RESTRICT out = *out_;
181 dsample_t const* const in_end = in + in_size;
182
183 int const step = this->step;
184 int pos = this->pos;
185
186 // TODO: IIR filter, then linear resample
187 // TODO: detect skipped sample, allowing merging of IIR and resample?
188
189 do
190 {
191 #define INTERP( i, out )\
192 out = (in [0 + i] * (unit - pos) + ((in [2 + i] + in [4 + i] + in [6 + i]) << shift) +\
193 in [8 + i] * pos) >> (shift + 2);
194
195 int out_0;
196 INTERP( 0, out_0 )
197 INTERP( 1, out [0] = out_0; out [1] )
198 out += stereo;
199
200 pos += step;
201 in += ((unsigned) pos >> shift) * stereo;
202 pos &= unit - 1;
203 }
204 while ( in < in_end && out < out_end );
205
206 this->pos = pos;
207 *out_ = out;
208 }
209 return in;
210}
211
212inline int resample_wrapper( struct Resampler* this, dsample_t out [], int* out_size,
213 dsample_t const in [], int in_size )
214{
215 assert( Resampler_rate( this ) );
216
217 dsample_t* out_ = out;
218 int result = resample_( this, &out_, out + *out_size, in, in_size ) - in;
219 assert( out_ <= out + *out_size );
220 assert( result <= in_size );
221
222 *out_size = out_ - out;
223 return result;
224}
225
226int skip_input( struct Resampler* this, int count )
227{
228 this->write_pos -= count;
229 if ( this->write_pos < 0 ) // occurs when downsampling
230 {
231 count += this->write_pos;
232 this->write_pos = 0;
233 }
234 memmove( this->buf, &this->buf [count], this->write_pos * sizeof this->buf [0] );
235 return count;
236}
237
238void play_frame_( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out )
239{
240 long pair_count = this->sample_buf_size >> 1;
241 blip_time_t blip_time = Blip_count_clocks( &stereo_buf->bufs [0], pair_count );
242 int sample_count = this->oversamples_per_frame - this->write_pos + resampler_extra;
243
244 int new_count = this->callback( this->callback_data, blip_time, sample_count, &this->buf [this->write_pos] );
245 assert( new_count < resampler_size );
246
247 Buffer_end_frame( stereo_buf, blip_time );
248 /* Blip_end_frame( &stereo_buf->bufs [0], blip_time ); */
249 assert( Blip_samples_avail( &stereo_buf->bufs [0] ) == pair_count * 2 );
250
251 this->write_pos += new_count;
252 assert( (unsigned) this->write_pos <= this->buffer_size );
253
254 new_count = this->sample_buf_size;
255 if ( new_count )
256 skip_input( this, resample_wrapper( this, this->sample_buf, &new_count, this->buf, this->write_pos ) );
257 assert( new_count == (long) this->sample_buf_size );
258
259 int bufs_used = stereo_buf->stereo_added | stereo_buf->was_stereo;
260 if ( bufs_used <= 1 ) {
261 mix_mono( this, stereo_buf, out );
262 Blip_remove_samples( &stereo_buf->bufs [0], pair_count );
263 Blip_remove_silence( &stereo_buf->bufs [1], pair_count );
264 Blip_remove_silence( &stereo_buf->bufs [2], pair_count );
265 }
266 else if ( bufs_used & 1 ) {
267 mix_stereo( this, stereo_buf, out );
268 Blip_remove_samples( &stereo_buf->bufs [0], pair_count );
269 Blip_remove_samples( &stereo_buf->bufs [1], pair_count );
270 Blip_remove_samples( &stereo_buf->bufs [2], pair_count );
271 }
272 else {
273 mix_stereo_no_center( this, stereo_buf, out );
274 Blip_remove_silence( &stereo_buf->bufs [0], pair_count );
275 Blip_remove_samples( &stereo_buf->bufs [1], pair_count );
276 Blip_remove_samples( &stereo_buf->bufs [2], pair_count );
277 }
278
279 // to do: this might miss opportunities for optimization
280 if ( !Blip_samples_avail( &stereo_buf->bufs [0] ) )
281 {
282 stereo_buf->was_stereo = stereo_buf->stereo_added;
283 stereo_buf->stereo_added = 0;
284 }
285
286 /* mix_mono( this, stereo_buf, out );
287 Blip_remove_samples( &stereo_buf->bufs [0], pair_count ); */
288}
289
290void Resampler_play( struct Resampler* this, long count, dsample_t* out, struct Stereo_Buffer* stereo_buf )
291{
292 // empty extra buffer
293 long remain = this->sample_buf_size - this->buf_pos;
294 if ( remain )
295 {
296 if ( remain > count )
297 remain = count;
298 count -= remain;
299 memcpy( out, &this->sample_buf [this->buf_pos], remain * sizeof *out );
300 out += remain;
301 this->buf_pos += remain;
302 }
303
304 // entire frames
305 while ( count >= (long) this->sample_buf_size )
306 {
307 play_frame_( this, stereo_buf, out );
308 out += this->sample_buf_size;
309 count -= this->sample_buf_size;
310 }
311
312 // extra
313 if ( count )
314 {
315 play_frame_( this, stereo_buf, this->sample_buf );
316 this->buf_pos = count;
317 memcpy( out, this->sample_buf, count * sizeof *out );
318 out += count;
319 }
320}
diff --git a/apps/codecs/libgme/resampler.h b/apps/codecs/libgme/resampler.h
new file mode 100644
index 0000000000..f5e8c55119
--- /dev/null
+++ b/apps/codecs/libgme/resampler.h
@@ -0,0 +1,68 @@
1// Combination of Downsampler and Blip_Buffer mixing. Used by Sega FM emulators.
2
3// Game_Music_Emu 0.5.5
4#ifndef RESAMPLER_H
5#define RESAMPLER_H
6
7#include "blargg_config.h"
8#include "multi_buffer.h"
9
10typedef short dsample_t;
11
12enum { stereo = 2 };
13enum { max_buf_size = 3960 };
14enum { max_resampler_size = 5942 };
15enum { write_offset = 8 * stereo };
16enum { gain_bits = 14 };
17
18struct Resampler {
19 int (*callback)( void*, blip_time_t, int, dsample_t* );
20 void* callback_data;
21
22 dsample_t sample_buf [max_buf_size];
23 int sample_buf_size;
24 int oversamples_per_frame;
25 int buf_pos;
26 int resampler_size;
27 int gain_;
28
29 // Internal resampler
30 dsample_t buf [max_resampler_size];
31 int buffer_size;
32
33 int write_pos;
34 double rate_;
35
36 int pos;
37 int step;
38};
39
40static inline void Resampler_init( struct Resampler* this )
41{
42 this->pos = 0;
43 this->write_pos = 0;
44 this->rate_ = 0;
45}
46
47blargg_err_t Resampler_reset( struct Resampler* this, int max_pairs );
48void Resampler_resize( struct Resampler* this, int pairs_per_frame );
49
50void Resampler_play( struct Resampler* this, long count, dsample_t* out, struct Stereo_Buffer* ) ICODE_ATTR;
51
52static inline void Resampler_set_callback(struct Resampler* this, int (*func)( void*, blip_time_t, int, dsample_t* ), void* user_data )
53{
54 this->callback = func;
55 this->callback_data = user_data;
56}
57
58blargg_err_t Resampler_setup( struct Resampler* this, double oversample, double rolloff, double gain );
59
60static inline void Resampler_clear( struct Resampler* this )
61{
62 this->buf_pos = this->sample_buf_size;
63
64 this->pos = 0;
65 this->write_pos = 0;
66}
67
68#endif
diff --git a/apps/codecs/libgme/rom_data.c b/apps/codecs/libgme/rom_data.c
new file mode 100644
index 0000000000..5fe3115130
--- /dev/null
+++ b/apps/codecs/libgme/rom_data.c
@@ -0,0 +1,68 @@
1// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/
2
3#include "rom_data.h"
4
5/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include <string.h>
17#include "blargg_source.h"
18
19// Rom_Data
20
21blargg_err_t Rom_load( struct Rom_Data* this, const void* data, long size,
22 int header_size, void* header_out, int fill )
23{
24 long file_offset = this->pad_size;
25
26 this->rom_addr = 0;
27 this->mask = 0;
28 this->size = 0;
29
30 if ( size <= header_size ) // <= because there must be data after header
31 return gme_wrong_file_type;
32
33 // Read header
34 memcpy( header_out, data, header_size );
35
36 this->file_size = size - header_size;
37 this->file_data = (byte*) data + header_size;
38
39 memset( this->unmapped, fill, this->rom_size );
40 memcpy( &this->unmapped [file_offset], this->file_data,
41 this->file_size < this->pad_size ? this->file_size : this->pad_size );
42
43 return 0;
44}
45
46void Rom_set_addr( struct Rom_Data* this, long addr )
47{
48 this->rom_addr = addr - this->bank_size - pad_extra;
49
50 long rounded = (addr + this->file_size + this->bank_size - 1) / this->bank_size * this->bank_size;
51 if ( rounded <= 0 )
52 {
53 rounded = 0;
54 }
55 else
56 {
57 int shift = 0;
58 unsigned long max_addr = (unsigned long) (rounded - 1);
59 while ( max_addr >> shift )
60 shift++;
61 this->mask = (1L << shift) - 1;
62 }
63
64 if ( addr < 0 )
65 addr = 0;
66 this->size = rounded;
67 this->rsize_ = rounded - this->rom_addr + pad_extra;
68}
diff --git a/apps/codecs/libgme/rom_data.h b/apps/codecs/libgme/rom_data.h
new file mode 100644
index 0000000000..28b34f2a70
--- /dev/null
+++ b/apps/codecs/libgme/rom_data.h
@@ -0,0 +1,83 @@
1// Common aspects of emulators which use rom data
2
3// Game_Music_Emu 0.5.2
4#ifndef ROM_DATA_H
5#define ROM_DATA_H
6
7#include "blargg_common.h"
8#include "blargg_source.h"
9
10// ROM data handler, used by several Classic_Emu derivitives. Loads file data
11// with padding on both sides, allowing direct use in bank mapping. The main purpose
12// is to allow all file data to be loaded with only one read() call (for efficiency).
13
14extern const char gme_wrong_file_type []; // declared in gme.h
15
16enum { pad_extra = 8 };
17enum { max_bank_size = 0x4000 };
18enum { max_pad_size = max_bank_size + pad_extra };
19enum { max_rom_size = 2 * max_pad_size };
20
21struct Rom_Data {
22 byte* file_data;
23 blargg_ulong file_size;
24
25 blargg_long rom_addr;
26 blargg_long bank_size;
27 blargg_long rom_size;
28 blargg_ulong pad_size;
29 blargg_long mask;
30 blargg_long size; // TODO: eliminate
31 blargg_long rsize_;
32
33 // Unmapped space
34 byte unmapped [max_rom_size];
35};
36
37// Initialize rom
38static inline void Rom_init( struct Rom_Data* this, blargg_long bank_size )
39{
40 this->bank_size = bank_size;
41 this->pad_size = this->bank_size + pad_extra;
42 this->rom_size = 2 * this->pad_size;
43}
44
45// Load file data, using already-loaded header 'h' if not NULL. Copy header
46// from loaded file data into *out and fill unmapped bytes with 'fill'.
47blargg_err_t Rom_load( struct Rom_Data* this, const void* data, long size, int header_size, void* header_out, int fill );
48
49// Set address that file data should start at
50void Rom_set_addr( struct Rom_Data* this, long addr );
51
52// Mask address to nearest power of two greater than size()
53static inline blargg_long mask_addr( blargg_long addr, blargg_long mask )
54{
55 #ifdef check
56 check( addr <= mask );
57 #endif
58 return addr & mask;
59}
60
61// Pointer to page starting at addr. Returns unmapped() if outside data.
62static inline byte* Rom_at_addr( struct Rom_Data* this, blargg_long addr )
63{
64 blargg_ulong offset = mask_addr( addr, this->mask ) - this->rom_addr;
65 if ( offset > (blargg_ulong) (this->rsize_ - this->pad_size) )
66 offset = 0; // unmapped
67
68 if ( offset < this->pad_size ) return &this->unmapped [offset];
69 else return &this->file_data [offset - this->pad_size];
70}
71
72
73#ifndef GME_APU_HOOK
74 #define GME_APU_HOOK( emu, addr, data ) ((void) 0)
75#endif
76
77#ifndef GME_FRAME_HOOK
78 #define GME_FRAME_HOOK( emu ) ((void) 0)
79#else
80 #define GME_FRAME_HOOK_DEFINED 1
81#endif
82
83#endif
diff --git a/apps/codecs/libgme/sgc_cpu.c b/apps/codecs/libgme/sgc_cpu.c
new file mode 100644
index 0000000000..3bd2d15df9
--- /dev/null
+++ b/apps/codecs/libgme/sgc_cpu.c
@@ -0,0 +1,36 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "sgc_emu.h"
4
5#include "blargg_endian.h"
6//#include "z80_cpu_log.h"
7
8/* Copyright (C) 2009 Shay Green. This module is free software; you
9can redistribute it and/or modify it under the terms of the GNU Lesser
10General Public License as published by the Free Software Foundation; either
11version 2.1 of the License, or (at your option) any later version. This
12module is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15details. You should have received a copy of the GNU Lesser General Public
16License along with this module; if not, write to the Free Software Foundation,
17Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19#include "blargg_source.h"
20
21#define OUT_PORT( addr, data ) cpu_out( this, TIME(), addr, data )
22#define IN_PORT( addr ) 0 // cpu in
23#define WRITE_MEM( addr, data ) cpu_write( this, addr, data )
24#define IDLE_ADDR this->idle_addr
25#define RST_BASE this->vectors_addr
26
27#define CPU_BEGIN \
28bool run_cpu( struct Sgc_Emu* this, cpu_time_t end_time )\
29{\
30 Sgc_Cpu* cpu = &this->cpu; \
31 Z80_set_end_time( cpu, end_time );
32
33 #include "z80_cpu_run.h"
34
35 return warning;
36}
diff --git a/apps/codecs/libgme/sgc_emu.c b/apps/codecs/libgme/sgc_emu.c
new file mode 100644
index 0000000000..9abfc00d2c
--- /dev/null
+++ b/apps/codecs/libgme/sgc_emu.c
@@ -0,0 +1,673 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "sgc_emu.h"
4
5/* Copyright (C) 2009 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18int const osc_count = sms_osc_count + fm_apu_osc_count;
19
20int const stereo = 2; // number of channels for stereo
21int const silence_max = 6; // seconds
22int const silence_threshold = 0x10;
23long const fade_block_size = 512;
24int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
25
26const char gme_wrong_file_type [] = "Wrong file type for this emulator";
27
28void clear_track_vars( struct Sgc_Emu* this )
29{
30 this->current_track = -1;
31 this->out_time = 0;
32 this->emu_time = 0;
33 this->emu_track_ended_ = true;
34 this->track_ended = true;
35 this->fade_start = INT_MAX / 2 + 1;
36 this->fade_step = 1;
37 this->silence_time = 0;
38 this->silence_count = 0;
39 this->buf_remain = 0;
40 /* warning(); // clear warning */
41}
42
43void Sgc_init( struct Sgc_Emu* this )
44{
45 assert( offsetof (struct header_t,copyright [32]) == header_size );
46
47 this->sample_rate = 0;
48 this->mute_mask_ = 0;
49 this->tempo = 1.0;
50 this->gain = 1.0;
51 this->voice_count = 0;
52
53 // defaults
54 this->max_initial_silence = 2;
55 this->silence_lookahead = 6;
56 this->ignore_silence = false;
57
58 Sms_apu_init( &this->apu );
59 Fm_apu_create( &this->fm_apu );
60
61 Rom_init( &this->rom, 0x4000 );
62 Z80_init( &this->cpu );
63
64 Sound_set_gain( this, 1.2 );
65
66 // Unload
67 clear_track_vars( this );
68}
69
70// Setup
71
72blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size )
73{
74 RETURN_ERR( Rom_load( &this->rom, data, size, header_size, &this->header, 0 ) );
75
76 if ( !valid_tag( &this->header ) )
77 return gme_wrong_file_type;
78
79 /* if ( header.vers != 1 )
80 warning( "Unknown file version" ); */
81
82 /* if ( header.system > 2 )
83 warning( "Unknown system" ); */
84
85 addr_t load_addr = get_le16( this->header.load_addr );
86 /* if ( load_addr < 0x400 )
87 set_warning( "Invalid load address" ); */
88
89 Rom_set_addr( &this->rom, load_addr );
90 this->play_period = clock_rate( this ) / 60;
91
92 if ( sega_mapping( this ) && Fm_apu_supported() )
93 RETURN_ERR( Fm_apu_init( &this->fm_apu, clock_rate( this ), clock_rate( this ) / 72 ) );
94
95 this->m3u.size = 0;
96 this->track_count = this->header.song_count;
97 this->voice_count = sega_mapping( this ) ? osc_count : sms_osc_count;
98
99 Sms_apu_volume( &this->apu, this->gain );
100 Fm_apu_volume( &this->fm_apu, this->gain );
101
102 // Setup buffer
103 this->clock_rate_ = clock_rate( this );
104 Buffer_clock_rate( &this->stereo_buf, clock_rate( this ) );
105 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
106 Sound_set_tempo( this, this->tempo );
107
108 // Remute voices
109 Sound_mute_voices( this, this->mute_mask_ );
110 return 0;
111}
112
113void Sound_set_voice( struct Sgc_Emu* this, int i, struct Blip_Buffer* c, struct Blip_Buffer* l, struct Blip_Buffer* r )
114{
115 if ( i < sms_osc_count )
116 Sms_apu_set_output( &this->apu, i, c, l, r );
117 else
118 Fm_apu_set_output( &this->fm_apu, c );
119}
120
121blargg_err_t run_clocks( struct Sgc_Emu* this, blip_time_t* duration, int msec )
122{
123#if defined(ROCKBOX)
124 (void) msec;
125#endif
126
127 cpu_time_t t = *duration;
128 while ( Z80_time( &this->cpu ) < t )
129 {
130 cpu_time_t next = min( t, this->next_play );
131 if ( run_cpu( this, next ) )
132 {
133 /* warning( "Unsupported CPU instruction" ); */
134 Z80_set_time( &this->cpu, next );
135 }
136
137 if ( this->cpu.r.pc == this->idle_addr )
138 Z80_set_time( &this->cpu, next );
139
140 if ( Z80_time( &this->cpu ) >= this->next_play )
141 {
142 this->next_play += this->play_period;
143 if ( this->cpu.r.pc == this->idle_addr )
144 jsr( this, this->header.play_addr );
145 }
146 }
147
148 this->next_play -= t;
149 check( this->next_play >= 0 );
150 Z80_adjust_time( &this->cpu, -t );
151
152 Sms_apu_end_frame( &this->apu, t );
153 if ( sega_mapping( this ) && this->fm_accessed )
154 {
155 if ( Fm_apu_supported() )
156 Fm_apu_end_frame( &this->fm_apu, t );
157 /* else
158 warning( "FM sound not supported" ); */
159 }
160
161 return 0;
162}
163
164// Emulation
165
166void cpu_out( struct Sgc_Emu* this, cpu_time_t time, addr_t addr, int data )
167{
168 int port = addr & 0xFF;
169
170 if ( sega_mapping( this ) )
171 {
172 switch ( port )
173 {
174 case 0x06:
175 Sms_apu_write_ggstereo( &this->apu, time, data );
176 return;
177
178 case 0x7E:
179 case 0x7F:
180 Sms_apu_write_data( &this->apu, time, data ); /* dprintf( "$7E<-%02X\n", data ); */
181 return;
182
183 case 0xF0:
184 this->fm_accessed = true;
185 if ( Fm_apu_supported() )
186 Fm_apu_write_addr( &this->fm_apu, data );//, dprintf( "$F0<-%02X\n", data );
187 return;
188
189 case 0xF1:
190 this->fm_accessed = true;
191 if ( Fm_apu_supported() )
192 Fm_apu_write_data( &this->fm_apu, time, data );//, dprintf( "$F1<-%02X\n", data );
193 return;
194 }
195 }
196 else if ( port >= 0xE0 )
197 {
198 Sms_apu_write_data( &this->apu, time, data );
199 return;
200 }
201}
202
203void jsr( struct Sgc_Emu* this, byte addr [2] )
204{
205 *Z80_write( &this->cpu, --this->cpu.r.sp ) = this->idle_addr >> 8;
206 *Z80_write( &this->cpu, --this->cpu.r.sp ) = this->idle_addr & 0xFF;
207 this->cpu.r.pc = get_le16( addr );
208}
209
210void set_bank( struct Sgc_Emu* this, int bank, void const* data )
211{
212 //dprintf( "map bank %d to %p\n", bank, (byte*) data - rom.at_addr( 0 ) );
213 Z80_map_mem( &this->cpu, bank * this->rom.bank_size, this->rom.bank_size, this->unmapped_write, data );
214}
215
216void cpu_write( struct Sgc_Emu* this, addr_t addr, int data )
217{
218 if ( (addr ^ 0xFFFC) > 3 || !sega_mapping( this ) )
219 {
220 *Z80_write( &this->cpu, addr ) = data;
221 return;
222 }
223
224 switch ( addr )
225 {
226 case 0xFFFC:
227 Z80_map_mem_rw( &this->cpu, 2 * this->rom.bank_size, this->rom.bank_size, this->ram2 );
228 if ( data & 0x08 )
229 break;
230
231 this->bank2 = this->ram2;
232 // FALL THROUGH
233
234 case 0xFFFF: {
235 bool rom_mapped = (Z80_read( &this->cpu, 2 * this->rom.bank_size ) == this->bank2);
236 this->bank2 = Rom_at_addr( &this->rom, data * this->rom.bank_size );
237 if ( rom_mapped )
238 set_bank( this, 2, this->bank2 );
239 break;
240 }
241
242 case 0xFFFD:
243 set_bank( this, 0, Rom_at_addr( &this->rom, data * this->rom.bank_size ) );
244 break;
245
246 case 0xFFFE:
247 set_bank( this, 1, Rom_at_addr( &this->rom, data * this->rom.bank_size ) );
248 break;
249 }
250}
251
252blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, long rate )
253{
254 require( !this->sample_rate ); // sample rate can't be changed once set
255 Buffer_init( &this->stereo_buf );
256 Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 );
257
258 // Set buffer bass
259 Buffer_bass_freq( &this->stereo_buf, 80 );
260
261 this->sample_rate = rate;
262 return 0;
263}
264
265void Sound_mute_voice( struct Sgc_Emu* this, int index, bool mute )
266{
267 require( (unsigned) index < (unsigned) this->voice_count );
268 int bit = 1 << index;
269 int mask = this->mute_mask_ | bit;
270 if ( !mute )
271 mask ^= bit;
272 Sound_mute_voices( this, mask );
273}
274
275void Sound_mute_voices( struct Sgc_Emu* this, int mask )
276{
277 require( this->sample_rate ); // sample rate must be set first
278 this->mute_mask_ = mask;
279
280 int i;
281 for ( i = this->voice_count; i--; )
282 {
283 if ( mask & (1 << i) )
284 {
285 Sound_set_voice( this, i, 0, 0, 0 );
286 }
287 else
288 {
289 struct channel_t ch = Buffer_channel( &this->stereo_buf );
290 assert( (ch.center && ch.left && ch.right) ||
291 (!ch.center && !ch.left && !ch.right) ); // all or nothing
292 Sound_set_voice( this, i, ch.center, ch.left, ch.right );
293 }
294 }
295}
296
297void Sound_set_tempo( struct Sgc_Emu* this, double t )
298{
299 require( this->sample_rate ); // sample rate must be set first
300 double const min = 0.02;
301 double const max = 4.00;
302 if ( t < min ) t = min;
303 if ( t > max ) t = max;
304 this->tempo = t;
305
306 this->play_period = (int) (clock_rate( this ) / (this->header.rate ? 50 : 60) / t);
307}
308
309void fill_buf( struct Sgc_Emu* this ) ICODE_ATTR;
310blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track )
311{
312 clear_track_vars( this );
313
314 // Remap track if playlist available
315 if ( this->m3u.size > 0 ) {
316 struct entry_t* e = &this->m3u.entries[track];
317 track = e->track;
318 }
319
320 this->current_track = track;
321
322 if ( sega_mapping( this ) )
323 {
324 Sms_apu_reset( &this->apu, 0, 0 );
325 Fm_apu_reset( &this->fm_apu );
326 this->fm_accessed = false;
327 }
328 else
329 {
330 Sms_apu_reset( &this->apu, 0x0003, 15 );
331 }
332
333 memset( this->ram , 0, sizeof this->ram );
334 memset( this->ram2, 0, sizeof this->ram2 );
335 memset( this->vectors, 0xFF, sizeof this->vectors );
336 Z80_reset( &this->cpu, this->unmapped_write, this->rom.unmapped );
337
338 if ( sega_mapping( this ) )
339 {
340 this->vectors_addr = 0x10000 - page_size;
341 this->idle_addr = this->vectors_addr;
342 int i;
343 for ( i = 1; i < 8; ++i )
344 {
345 this->vectors [i*8 + 0] = 0xC3; // JP addr
346 this->vectors [i*8 + 1] = this->header.rst_addrs [i - 1] & 0xff;
347 this->vectors [i*8 + 2] = this->header.rst_addrs [i - 1] >> 8;
348 }
349
350 Z80_map_mem_rw( &this->cpu, 0xC000, 0x2000, this->ram );
351 Z80_map_mem( &this->cpu, this->vectors_addr, page_size, this->unmapped_write, this->vectors );
352
353 this->bank2 = NULL;
354 for ( i = 0; i < 4; ++i )
355 cpu_write( this, 0xFFFC + i, this->header.mapping [i] );
356 }
357 else
358 {
359 if ( !this->coleco_bios )
360 return "Coleco BIOS not set"; /* BLARGG_ERR( BLARGG_ERR_CALLER, "Coleco BIOS not set" ); */
361
362 this->vectors_addr = 0;
363 Z80_map_mem( &this->cpu, 0, 0x2000, this->unmapped_write, this->coleco_bios );
364 int i;
365 for ( i = 0; i < 8; ++i )
366 Z80_map_mem_rw( &this->cpu, 0x6000 + i*0x400, 0x400, this->ram );
367
368 this->idle_addr = 0x2000;
369 Z80_map_mem( &this->cpu, 0x2000, page_size, this->unmapped_write, this->vectors );
370
371 for ( i = 0; i < 0x8000 / this->rom.bank_size; ++i )
372 {
373 int addr = 0x8000 + i*this->rom.bank_size;
374 Z80_map_mem( &this->cpu, addr, this->rom.bank_size, this->unmapped_write, Rom_at_addr( &this->rom, addr ) );
375 }
376 }
377
378 this->cpu.r.sp = get_le16( this->header.stack_ptr );
379 this->cpu.r.b.a = track;
380 this->next_play = this->play_period;
381
382 jsr( this, this->header.init_addr );
383
384 Buffer_clear( &this->stereo_buf );
385
386 this->emu_track_ended_ = false;
387 this->track_ended = false;
388
389 if ( !this->ignore_silence )
390 {
391 // play until non-silence or end of track
392 long end;
393 for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; )
394 {
395 fill_buf( this );
396 if ( this->buf_remain | (int) this->emu_track_ended_ )
397 break;
398 }
399
400 this->emu_time = this->buf_remain;
401 this->out_time = 0;
402 this->silence_time = 0;
403 this->silence_count = 0;
404 }
405 /* return track_ended() ? warning() : 0; */
406 return 0;
407}
408
409// Tell/Seek
410
411blargg_long msec_to_samples( blargg_long msec, long sample_rate )
412{
413 blargg_long sec = msec / 1000;
414 msec -= sec * 1000;
415 return (sec * sample_rate + msec * sample_rate / 1000) * stereo;
416}
417
418long Track_tell( struct Sgc_Emu* this )
419{
420 blargg_long rate = this->sample_rate * stereo;
421 blargg_long sec = this->out_time / rate;
422 return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate;
423}
424
425blargg_err_t Track_seek( struct Sgc_Emu* this, long msec )
426{
427 blargg_long time = msec_to_samples( msec, this->sample_rate );
428 if ( time < this->out_time )
429 RETURN_ERR( Sgc_start_track( this, this->current_track ) );
430 return Track_skip( this, time - this->out_time );
431}
432
433blargg_err_t skip_( struct Sgc_Emu* this, long count ) ICODE_ATTR;
434blargg_err_t Track_skip( struct Sgc_Emu* this, long count )
435{
436 require( this->current_track >= 0 ); // start_track() must have been called already
437 this->out_time += count;
438
439 // remove from silence and buf first
440 {
441 long n = min( count, this->silence_count );
442 this->silence_count -= n;
443 count -= n;
444
445 n = min( count, this->buf_remain );
446 this->buf_remain -= n;
447 count -= n;
448 }
449
450 if ( count && !this->emu_track_ended_ )
451 {
452 this->emu_time += count;
453
454 // End track if error
455 if ( skip_( this, count ) ) {
456 this->emu_track_ended_ = true;
457 }
458 }
459
460 if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended
461 this->track_ended |= this->emu_track_ended_;
462
463 return 0;
464}
465
466blargg_err_t play_( struct Sgc_Emu* this, long count, sample_t* out ) ICODE_ATTR;
467blargg_err_t skip_( struct Sgc_Emu* this, long count )
468{
469 // for long skip, mute sound
470 const long threshold = 30000;
471 if ( count > threshold )
472 {
473 int saved_mute = this->mute_mask_;
474 Sound_mute_voices( this, ~0 );
475
476 while ( count > threshold / 2 && !this->emu_track_ended_ )
477 {
478 RETURN_ERR( play_( this, buf_size, this->buf ) );
479 count -= buf_size;
480 }
481
482 Sound_mute_voices( this, saved_mute );
483 }
484
485 while ( count && !this->emu_track_ended_ )
486 {
487 long n = buf_size;
488 if ( n > count )
489 n = count;
490 count -= n;
491 RETURN_ERR( play_( this, n, this->buf ) );
492 }
493 return 0;
494}
495
496// Fading
497
498void Track_set_fade( struct Sgc_Emu* this, long start_msec, long length_msec )
499{
500 this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo);
501 this->fade_start = msec_to_samples( start_msec, this->sample_rate );
502}
503
504// unit / pow( 2.0, (double) x / step )
505static int int_log( blargg_long x, int step, int unit )
506{
507 int shift = x / step;
508 int fraction = (x - shift * step) * unit / step;
509 return ((unit - fraction) + (fraction >> 1)) >> shift;
510}
511
512void handle_fade( struct Sgc_Emu* this, long out_count, sample_t* out )
513{
514 int i;
515 for ( i = 0; i < out_count; i += fade_block_size )
516 {
517 int const shift = 14;
518 int const unit = 1 << shift;
519 int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size,
520 this->fade_step, unit );
521 if ( gain < (unit >> fade_shift) )
522 this->track_ended = this->emu_track_ended_ = true;
523
524 sample_t* io = &out [i];
525 int count;
526 for ( count = min( fade_block_size, out_count - i ); count; --count )
527 {
528 *io = (sample_t) ((*io * gain) >> shift);
529 ++io;
530 }
531 }
532}
533
534// Silence detection
535
536void emu_play( struct Sgc_Emu* this, long count, sample_t* out )
537{
538 check( this->current_track_ >= 0 );
539 this->emu_time += count;
540 if ( this->current_track >= 0 && !this->emu_track_ended_ ) {
541 // End track if error
542 if ( play_( this, count, out ) )
543 this->emu_track_ended_ = true;
544 }
545 else
546 memset( out, 0, count * sizeof *out );
547}
548
549// number of consecutive silent samples at end
550static long count_silence( sample_t* begin, long size )
551{
552 sample_t first = *begin;
553 *begin = silence_threshold; // sentinel
554 sample_t* p = begin + size;
555 while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { }
556 *begin = first;
557 return size - (p - begin);
558}
559
560// fill internal buffer and check it for silence
561void fill_buf( struct Sgc_Emu* this )
562{
563 assert( !this->buf_remain );
564 if ( !this->emu_track_ended_ )
565 {
566 emu_play( this, buf_size, this->buf );
567 long silence = count_silence( this->buf, buf_size );
568 if ( silence < buf_size )
569 {
570 this->silence_time = this->emu_time - silence;
571 this->buf_remain = buf_size;
572 return;
573 }
574 }
575 this->silence_count += buf_size;
576}
577
578blargg_err_t Sgc_play( struct Sgc_Emu* this, long out_count, sample_t* out )
579{
580 if ( this->track_ended )
581 {
582 memset( out, 0, out_count * sizeof *out );
583 }
584 else
585 {
586 require( this->current_track >= 0 );
587 require( out_count % stereo == 0 );
588
589 assert( this->emu_time >= this->out_time );
590
591 // prints nifty graph of how far ahead we are when searching for silence
592 //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" );
593
594 long pos = 0;
595 if ( this->silence_count )
596 {
597 // during a run of silence, run emulator at >=2x speed so it gets ahead
598 long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time;
599 while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) )
600 fill_buf( this );
601
602 // fill with silence
603 pos = min( this->silence_count, out_count );
604 memset( out, 0, pos * sizeof *out );
605 this->silence_count -= pos;
606
607 if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate )
608 {
609 this->track_ended = this->emu_track_ended_ = true;
610 this->silence_count = 0;
611 this->buf_remain = 0;
612 }
613 }
614
615 if ( this->buf_remain )
616 {
617 // empty silence buf
618 long n = min( this->buf_remain, out_count - pos );
619 memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out );
620 this->buf_remain -= n;
621 pos += n;
622 }
623
624 // generate remaining samples normally
625 long remain = out_count - pos;
626 if ( remain )
627 {
628 emu_play( this, remain, out + pos );
629 this->track_ended |= this->emu_track_ended_;
630
631 if ( !this->ignore_silence || this->out_time > this->fade_start )
632 {
633 // check end for a new run of silence
634 long silence = count_silence( out + pos, remain );
635 if ( silence < remain )
636 this->silence_time = this->emu_time - silence;
637
638 if ( this->emu_time - this->silence_time >= buf_size )
639 fill_buf( this ); // cause silence detection on next play()
640 }
641 }
642
643 if ( this->out_time > this->fade_start )
644 handle_fade( this, out_count, out );
645 }
646 this->out_time += out_count;
647 return 0;
648}
649
650blargg_err_t play_( struct Sgc_Emu* this, long count, sample_t* out )
651{
652 long remain = count;
653 while ( remain )
654 {
655 remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain );
656 if ( remain )
657 {
658 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) )
659 {
660 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
661
662 // Remute voices
663 Sound_mute_voices( this, this->mute_mask_ );
664 }
665 int msec = Buffer_length( &this->stereo_buf );
666 blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100;
667 RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) );
668 assert( clocks_emulated );
669 Buffer_end_frame( &this->stereo_buf, clocks_emulated );
670 }
671 }
672 return 0;
673}
diff --git a/apps/codecs/libgme/sgc_emu.h b/apps/codecs/libgme/sgc_emu.h
new file mode 100644
index 0000000000..957e7438ef
--- /dev/null
+++ b/apps/codecs/libgme/sgc_emu.h
@@ -0,0 +1,199 @@
1// Sega/Game Gear/Coleco SGC music file emulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef SGC_EMU_H
5#define SGC_EMU_H
6
7#include "blargg_common.h"
8#include "multi_buffer.h"
9
10#include "rom_data.h"
11#include "z80_cpu.h"
12#include "sms_fm_apu.h"
13#include "sms_apu.h"
14#include "m3u_playlist.h"
15
16typedef short sample_t;
17typedef struct Z80_Cpu Sgc_Cpu;
18
19enum { buf_size = 2048 };
20
21// SGC file header
22enum { header_size = 0xA0 };
23struct header_t
24{
25 char tag [4]; // "SGC\x1A"
26 byte vers; // 0x01
27 byte rate; // 0=NTSC 1=PAL
28 byte reserved1 [2];
29 byte load_addr [2];
30 byte init_addr [2];
31 byte play_addr [2];
32 byte stack_ptr [2];
33 byte reserved2 [2];
34 byte rst_addrs [7*2];
35 byte mapping [4]; // Used by Sega only
36 byte first_song; // Song to start playing first
37 byte song_count;
38 byte first_effect;
39 byte last_effect;
40 byte system; // 0=Master System 1=Game Gear 2=Colecovision
41 byte reserved3 [23];
42 char game [32]; // strings can be 32 chars, NOT terminated
43 char author [32];
44 char copyright [32];
45};
46
47// True if header has valid file signature
48static inline bool valid_tag( struct header_t* h )
49{
50 return 0 == memcmp( h->tag, "SGC\x1A", 4 );
51}
52
53static inline int effect_count( struct header_t* h ) { return h->last_effect ? h->last_effect - h->first_effect + 1 : 0; }
54
55
56struct Sgc_Emu {
57 bool fm_accessed;
58
59 cpu_time_t play_period;
60 cpu_time_t next_play;
61 void const* bank2; // ROM selected for bank 2, in case RAM is currently hiding it
62 addr_t vectors_addr; // RST vectors start here
63 addr_t idle_addr; // return address for init/play routines
64 void* coleco_bios;
65
66 // general
67 int voice_count;
68 int mute_mask_;
69 double tempo;
70 double gain;
71
72 long sample_rate;
73
74 // track-specific
75 volatile bool track_ended;
76 int current_track;
77 int track_count;
78 blargg_long out_time; // number of samples played since start of track
79 blargg_long emu_time; // number of samples emulator has generated since start of track
80 bool emu_track_ended_; // emulator has reached end of track
81
82 // fading
83 blargg_long fade_start;
84 int fade_step;
85
86 // silence detection
87 bool ignore_silence;
88 int max_initial_silence;
89 int silence_lookahead; // speed to run emulator when looking ahead for silence
90 long silence_time; // number of samples where most recent silence began
91 long silence_count; // number of samples of silence to play before using buf
92 long buf_remain; // number of samples left in silence buffer
93
94 long clock_rate_;
95 unsigned buf_changed_count;
96
97 // M3u Playlist
98 struct M3u_Playlist m3u;
99
100 sample_t buf [buf_size];
101 struct Stereo_Buffer stereo_buf;
102
103 struct Sms_Apu apu;
104 struct Sms_Fm_Apu fm_apu;
105
106 Sgc_Cpu cpu;
107
108 // large items
109 struct header_t header;
110 struct Rom_Data rom;
111 byte vectors [page_size + page_padding];
112 byte ram [0x2000 + page_padding];
113 byte ram2 [0x4000 + page_padding];
114 byte unmapped_write [0x4000];
115};
116
117// Basic functionality (see Gme_File.h for file loading/track info functions)
118
119void Sgc_init( struct Sgc_Emu* this );
120
121blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size );
122
123static inline int clock_rate( struct Sgc_Emu* this ) { return this->header.rate ? 3546893 : 3579545; }
124
125// 0x2000 bytes
126static inline void set_coleco_bios( struct Sgc_Emu* this, void* p ) { this->coleco_bios = p; }
127
128// Set output sample rate. Must be called only once before loading file.
129blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, long sample_rate );
130
131// Start a track, where 0 is the first track. Also clears warning string.
132blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track );
133
134// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation
135// errors set warning string, and major errors also end track.
136blargg_err_t Sgc_play( struct Sgc_Emu* this, long count, sample_t* buf );
137
138// Track status/control
139
140// Number of milliseconds (1000 msec = 1 second) played since beginning of track
141long Track_tell( struct Sgc_Emu* this );
142
143// Seek to new time in track. Seeking backwards or far forward can take a while.
144blargg_err_t Track_seek( struct Sgc_Emu* this, long msec );
145
146// Skip n samples
147blargg_err_t Track_skip( struct Sgc_Emu* this, long n );
148
149// Set start time and length of track fade out. Once fade ends track_ended() returns
150// true. Fade time can be changed while track is playing.
151void Track_set_fade( struct Sgc_Emu* this, long start_msec, long length_msec );
152
153// Get track length in milliseconds
154static inline long Track_get_length( struct Sgc_Emu* this, int n )
155{
156 long length = 120 * 1000; /* 2 minutes */
157 if ( (this->m3u.size > 0) && (n < this->m3u.size) ) {
158 struct entry_t* entry = &this->m3u.entries [n];
159 length = entry->length;
160 }
161
162 return length;
163}
164
165// Sound customization
166
167// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed.
168// Track length as returned by track_info() assumes a tempo of 1.0.
169void Sound_set_tempo( struct Sgc_Emu* this, double t );
170
171// Mute/unmute voice i, where voice 0 is first voice
172void Sound_mute_voice( struct Sgc_Emu* this, int index, bool mute );
173
174// Set muting state of all voices at once using a bit mask, where -1 mutes them all,
175// 0 unmutes them all, 0x01 mutes just the first voice, etc.
176void Sound_mute_voices( struct Sgc_Emu* this, int mask );
177
178// Change overall output amplitude, where 1.0 results in minimal clamping.
179// Must be called before set_sample_rate().
180static inline void Sound_set_gain( struct Sgc_Emu* this, double g )
181{
182 assert( !this->sample_rate ); // you must set gain before setting sample rate
183 this->gain = g;
184}
185
186// True if Master System or Game Gear
187static inline bool sega_mapping( struct Sgc_Emu* this )
188{
189 return this->header.system <= 1;
190}
191
192// Emulation (You shouldn't touch these)
193
194bool run_cpu( struct Sgc_Emu* this, cpu_time_t end_time ) ICODE_ATTR;
195void cpu_out( struct Sgc_Emu* this, cpu_time_t time, addr_t addr, int data ) ICODE_ATTR;
196void cpu_write( struct Sgc_Emu* this, addr_t addr, int data ) ICODE_ATTR;
197void jsr( struct Sgc_Emu* this, byte addr [2] ) ICODE_ATTR;
198
199#endif
diff --git a/apps/codecs/libgme/sms_apu.c b/apps/codecs/libgme/sms_apu.c
new file mode 100644
index 0000000000..4be63db073
--- /dev/null
+++ b/apps/codecs/libgme/sms_apu.c
@@ -0,0 +1,310 @@
1// Sms_Snd_Emu 0.1.1. http://www.slack.net/~ant/
2
3#include "sms_apu.h"
4
5/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18int const noise_osc = 3;
19
20void Sms_apu_volume( struct Sms_Apu* this, double vol )
21{
22 vol *= 0.85 / sms_osc_count / 64;
23 Synth_volume( &this->synth, vol );
24}
25
26inline int calc_output( struct Sms_Apu* this, int i )
27{
28 int flags = this->ggstereo >> i;
29 return (flags >> 3 & 2) | (flags & 1);
30}
31
32void Sms_apu_set_output( struct Sms_Apu* this, int i, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right )
33{
34#if defined(ROCKBOX)
35 (void) left;
36 (void) right;
37#endif
38
39 // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL)
40 require( !center || (center && !left && !right) || (center && left && right) );
41 require( (unsigned) i < sms_osc_count ); // fails if you pass invalid osc index
42
43 if ( center )
44 {
45 unsigned const divisor = 16384 * 16 * 2;
46 this->min_tone_period = ((unsigned) Blip_clock_rate( center ) + divisor/2) / divisor;
47 }
48
49 if ( !center || !left || !right )
50 {
51 left = center;
52 right = center;
53 }
54
55 struct Osc* o = &this->oscs [i];
56 o->outputs [0] = NULL;
57 o->outputs [1] = right;
58 o->outputs [2] = left;
59 o->outputs [3] = center;
60 o->output = o->outputs [calc_output( this, i )];
61}
62
63static inline unsigned fibonacci_to_galois_lfsr( unsigned fibonacci, int width )
64{
65 unsigned galois = 0;
66 while ( --width >= 0 )
67 {
68 galois = (galois << 1) | (fibonacci & 1);
69 fibonacci >>= 1;
70 }
71 return galois;
72}
73
74void Sms_apu_reset( struct Sms_Apu* this, unsigned feedback, int noise_width )
75{
76 this->last_time = 0;
77 this->latch = 0;
78 this->ggstereo = 0;
79
80 // Calculate noise feedback values
81 if ( !feedback || !noise_width )
82 {
83 feedback = 0x0009;
84 noise_width = 16;
85 }
86 this->looped_feedback = 1 << (noise_width - 1);
87 this->noise_feedback = fibonacci_to_galois_lfsr( feedback, noise_width );
88
89 // Reset oscs
90 int i;
91 for ( i = sms_osc_count; --i >= 0; )
92 {
93 struct Osc* o = &this->oscs [i];
94 o->output = NULL;
95 o->last_amp = 0;
96 o->delay = 0;
97 o->phase = 0;
98 o->period = 0;
99 o->volume = 15; // silent
100 }
101
102 this->oscs [noise_osc].phase = 0x8000;
103 Sms_apu_write_ggstereo( this, 0, 0xFF );
104}
105
106void Sms_apu_init( struct Sms_Apu* this )
107{
108 this->min_tone_period = 7;
109
110 Synth_init( &this->synth );
111
112 // Clear outputs to NULL FIRST
113 this->ggstereo = 0;
114
115 int i;
116 for ( i = sms_osc_count; --i >= 0; )
117 Sms_apu_set_output( this, i, NULL, NULL, NULL );
118
119 Sms_apu_volume( this, 1.0 );
120 Sms_apu_reset( this, 0, 0 );
121}
122
123static void run_until( struct Sms_Apu* this, blip_time_t end_time )
124{
125 require( end_time >= this->last_time );
126 if ( end_time <= this->last_time )
127 return;
128
129 // Synthesize each oscillator
130 int idx;
131 for ( idx = sms_osc_count; --idx >= 0; )
132 {
133 struct Osc* osc = &this->oscs [idx];
134 int vol = 0;
135 int amp = 0;
136
137 // Determine what will be generated
138 struct Blip_Buffer* const out = osc->output;
139 if ( out )
140 {
141 // volumes [i] ~= 64 * pow( 1.26, 15 - i ) / pow( 1.26, 15 )
142 static unsigned char const volumes [16] ICONST_ATTR = {
143 64, 50, 40, 32, 25, 20, 16, 13, 10, 8, 6, 5, 4, 3, 2, 0
144 };
145
146 vol = volumes [osc->volume];
147 amp = (osc->phase & 1) * vol;
148
149 // Square freq above 16 kHz yields constant amplitude at half volume
150 if ( idx != noise_osc && osc->period < this->min_tone_period )
151 {
152 amp = vol >> 1;
153 vol = 0;
154 }
155
156 // Update amplitude
157 int delta = amp - osc->last_amp;
158 if ( delta )
159 {
160 osc->last_amp = amp;
161 /* norm_synth.offset( last_time, delta, out ); */
162 Synth_offset( &this->synth, this->last_time, delta, out );
163 /* out->set_modified(); */
164 Blip_set_modified( out );
165 }
166 }
167
168 // Generate wave
169 blip_time_t time = this->last_time + osc->delay;
170 if ( time < end_time )
171 {
172 // Calculate actual period
173 int period = osc->period;
174 if ( idx == noise_osc )
175 {
176 period = 0x20 << (period & 3);
177 if ( period == 0x100 )
178 period = this->oscs [2].period * 2;
179 }
180 period *= 0x10;
181 if ( !period )
182 period = 0x10;
183
184 // Maintain phase when silent
185 int phase = osc->phase;
186 if ( !vol )
187 {
188 int count = (end_time - time + period - 1) / period;
189 time += count * period;
190 if ( idx != noise_osc ) // TODO: maintain noise LFSR phase?
191 phase ^= count & 1;
192 }
193 else
194 {
195 int delta = amp * 2 - vol;
196
197 if ( idx != noise_osc )
198 {
199 // Square
200 do
201 {
202 delta = -delta;
203 /* norm_synth.offset( time, delta, out ); */
204 Synth_offset( &this->synth, time, delta, out );
205 time += period;
206 }
207 while ( time < end_time );
208 phase = (delta >= 0);
209 }
210 else
211 {
212 // Noise
213 unsigned const feedback = (osc->period & 4 ? this->noise_feedback : this->looped_feedback);
214 do
215 {
216 unsigned changed = phase + 1;
217 phase = ((phase & 1) * feedback) ^ (phase >> 1);
218 if ( changed & 2 ) // true if bits 0 and 1 differ
219 {
220 delta = -delta;
221 /* fast_synth.offset_inline( time, delta, out ); */
222 Synth_offset_inline( &this->synth, time, delta, out );
223 }
224 time += period;
225 }
226 while ( time < end_time );
227 check( phase );
228 }
229 osc->last_amp = (phase & 1) * vol;
230 Blip_set_modified( out );
231 }
232 osc->phase = phase;
233 }
234 osc->delay = time - end_time;
235 }
236 this->last_time = end_time;
237}
238
239void Sms_apu_write_ggstereo( struct Sms_Apu* this, blip_time_t time, int data )
240{
241 require( (unsigned) data <= 0xFF );
242
243 run_until( this, time );
244 this->ggstereo = data;
245
246 int i;
247 for ( i = sms_osc_count; --i >= 0; )
248 {
249 struct Osc* osc = &this->oscs [i];
250
251 struct Blip_Buffer* old = osc->output;
252 osc->output = osc->outputs [calc_output( this, i )];
253 if ( osc->output != old )
254 {
255 int delta = -osc->last_amp;
256 if ( delta )
257 {
258 osc->last_amp = 0;
259 if ( old )
260 {
261 Blip_set_modified( old );
262 Synth_offset( &this->synth, this->last_time, delta, old );
263 }
264 }
265 }
266 }
267}
268
269void Sms_apu_write_data( struct Sms_Apu* this, blip_time_t time, int data )
270{
271 require( (unsigned) data <= 0xFF );
272
273 run_until( this, time );
274
275 if ( data & 0x80 )
276 this->latch = data;
277
278 // We want the raw values written so our save state format can be
279 // as close to hardware as possible and unspecific to any emulator.
280 int idx = this->latch >> 5 & 3;
281 struct Osc* osc = &this->oscs [idx];
282 if ( this->latch & 0x10 )
283 {
284 osc->volume = data & 0x0F;
285 }
286 else
287 {
288 if ( idx == noise_osc )
289 osc->phase = 0x8000; // reset noise LFSR
290
291 // Replace high 6 bits/low 4 bits of register with data
292 int lo = osc->period;
293 int hi = data << 4;
294 if ( idx == noise_osc || (data & 0x80) )
295 {
296 hi = lo;
297 lo = data;
298 }
299 osc->period = (hi & 0x3F0) | (lo & 0x00F);
300 }
301}
302
303void Sms_apu_end_frame( struct Sms_Apu* this, blip_time_t end_time )
304{
305 if ( end_time > this->last_time )
306 run_until( this, end_time );
307
308 this->last_time -= end_time;
309 assert( this->last_time >= 0 );
310}
diff --git a/apps/codecs/libgme/sms_apu.h b/apps/codecs/libgme/sms_apu.h
new file mode 100644
index 0000000000..25f4e74ae5
--- /dev/null
+++ b/apps/codecs/libgme/sms_apu.h
@@ -0,0 +1,63 @@
1// Sega Master System SN76489 PSG sound chip emulator
2
3// Sms_Snd_Emu 0.1.2
4#ifndef SMS_APU_H
5#define SMS_APU_H
6
7#include "blargg_common.h"
8#include "blip_buffer.h"
9
10// 0: Square 1, 1: Square 2, 2: Square 3, 3: Noise
11enum { sms_osc_count = 4 }; // 0 <= chan < osc_count
12
13struct Osc
14{
15 struct Blip_Buffer* outputs [4]; // NULL, right, left, center
16 struct Blip_Buffer* output;
17 int last_amp;
18
19 int volume;
20 int period;
21 int delay;
22 unsigned phase;
23};
24
25struct Sms_Apu {
26 struct Osc oscs [sms_osc_count];
27 int ggstereo;
28 int latch;
29
30 blip_time_t last_time;
31 int min_tone_period;
32 unsigned noise_feedback;
33 unsigned looped_feedback;
34 struct Blip_Synth synth;
35};
36
37// Basics
38
39void Sms_apu_init( struct Sms_Apu* this );
40
41// Sets buffer(s) to generate sound into, or 0 to mute. If only center is not 0,
42// output is mono.
43void Sms_apu_set_output( struct Sms_Apu* this, int i, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right);
44
45// Emulates to time t, then writes data to Game Gear left/right assignment byte
46void Sms_apu_write_ggstereo( struct Sms_Apu* this, blip_time_t t, int data ) ICODE_ATTR;
47
48// Emulates to time t, then writes data
49void Sms_apu_write_data( struct Sms_Apu* this, blip_time_t t, int data ) ICODE_ATTR;
50
51// Emulates to time t, then subtracts t from the current time.
52// OK if previous write call had time slightly after t.
53void Sms_apu_end_frame( struct Sms_Apu* this, blip_time_t t ) ICODE_ATTR;
54
55// More features
56
57// Resets sound chip and sets noise feedback bits and width
58void Sms_apu_reset( struct Sms_Apu* this, unsigned noise_feedback, int noise_width );
59
60// Sets overall volume, where 1.0 is normal
61void Sms_apu_volume( struct Sms_Apu* this, double vol );
62
63#endif
diff --git a/apps/codecs/libgme/sms_fm_apu.c b/apps/codecs/libgme/sms_fm_apu.c
new file mode 100644
index 0000000000..b15fc56680
--- /dev/null
+++ b/apps/codecs/libgme/sms_fm_apu.c
@@ -0,0 +1,82 @@
1#include "sms_fm_apu.h"
2
3#include "blargg_source.h"
4
5void Fm_apu_create( struct Sms_Fm_Apu* this )
6{
7 Synth_init( &this->synth );
8 Ym2413_init( &this->apu );
9}
10
11blargg_err_t Fm_apu_init( struct Sms_Fm_Apu* this, double clock_rate, double sample_rate )
12{
13 this->period_ = (blip_time_t) (clock_rate / sample_rate + 0.5);
14 CHECK_ALLOC( !Ym2413_set_rate( &this->apu, sample_rate, clock_rate ) );
15
16 Fm_apu_set_output( this, 0 );
17 Fm_apu_volume( this, 1.0 );
18 Fm_apu_reset( this );
19 return 0;
20}
21
22void Fm_apu_reset( struct Sms_Fm_Apu* this )
23{
24 this->addr = 0;
25 this->next_time = 0;
26 this->last_amp = 0;
27
28 Ym2413_reset( &this->apu );
29}
30
31void fm_run_until( struct Sms_Fm_Apu* this, blip_time_t end_time ) ICODE_ATTR;
32void Fm_apu_write_data( struct Sms_Fm_Apu* this, blip_time_t time, int data )
33{
34 if ( time > this->next_time )
35 fm_run_until( this, time );
36
37 Ym2413_write( &this->apu, this->addr, data );
38}
39
40void fm_run_until( struct Sms_Fm_Apu* this, blip_time_t end_time )
41{
42 assert( end_time > this->next_time );
43
44 struct Blip_Buffer* const output = this->output_;
45 if ( !output )
46 {
47 this->next_time = end_time;
48 return;
49 }
50
51 blip_time_t time = this->next_time;
52 struct Ym2413_Emu* emu = &this->apu;
53 do
54 {
55 short samples [2];
56 Ym2413_run( emu, 1, samples );
57 int amp = (samples [0] + samples [1]) >> 1;
58
59 int delta = amp - this->last_amp;
60 if ( delta )
61 {
62 this->last_amp = amp;
63 Synth_offset_inline( &this->synth, time, delta, output );
64 }
65 time += this->period_;
66 }
67 while ( time < end_time );
68
69 this->next_time = time;
70}
71
72void Fm_apu_end_frame( struct Sms_Fm_Apu* this, blip_time_t time )
73{
74 if ( time > this->next_time )
75 fm_run_until( this, time );
76
77 this->next_time -= time;
78 assert( this->next_time >= 0 );
79
80 if ( this->output_ )
81 Blip_set_modified( this->output_ );
82}
diff --git a/apps/codecs/libgme/sms_fm_apu.h b/apps/codecs/libgme/sms_fm_apu.h
new file mode 100644
index 0000000000..95e1f95e62
--- /dev/null
+++ b/apps/codecs/libgme/sms_fm_apu.h
@@ -0,0 +1,43 @@
1#ifndef SMS_FM_APU_H
2#define SMS_FM_APU_H
3
4#include "blargg_common.h"
5#include "blip_buffer.h"
6#include "ym2413_emu.h"
7
8enum { fm_apu_osc_count = 1 };
9
10struct Sms_Fm_Apu {
11 struct Blip_Buffer* output_;
12 blip_time_t next_time;
13 int last_amp;
14 int addr;
15
16 int clock_;
17 int rate_;
18 blip_time_t period_;
19
20 struct Blip_Synth synth;
21 struct Ym2413_Emu apu;
22};
23
24void Fm_apu_create( struct Sms_Fm_Apu* this );
25
26static inline bool Fm_apu_supported( void ) { return Ym2413_supported(); }
27blargg_err_t Fm_apu_init( struct Sms_Fm_Apu* this, double clock_rate, double sample_rate );
28
29static inline void Fm_apu_set_output( struct Sms_Fm_Apu* this, struct Blip_Buffer* b )
30{
31 this->output_ = b;
32}
33
34static inline void Fm_apu_volume( struct Sms_Fm_Apu* this, double v ) { Synth_volume( &this->synth, 0.4 / 4096 * v ); }
35
36void Fm_apu_reset( struct Sms_Fm_Apu* this );
37
38static inline void Fm_apu_write_addr( struct Sms_Fm_Apu* this, int data ) { this->addr = data; }
39void Fm_apu_write_data( struct Sms_Fm_Apu* this, blip_time_t, int data ) ICODE_ATTR;
40
41void Fm_apu_end_frame( struct Sms_Fm_Apu* this, blip_time_t t ) ICODE_ATTR;
42
43#endif
diff --git a/apps/codecs/libgme/vgm_emu.c b/apps/codecs/libgme/vgm_emu.c
new file mode 100644
index 0000000000..7fed4ef6d1
--- /dev/null
+++ b/apps/codecs/libgme/vgm_emu.c
@@ -0,0 +1,1053 @@
1// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/
2
3#include "vgm_emu.h"
4
5#include "blargg_endian.h"
6#include <string.h>
7#include <math.h>
8
9/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
10can redistribute it and/or modify it under the terms of the GNU Lesser
11General Public License as published by the Free Software Foundation; either
12version 2.1 of the License, or (at your option) any later version. This
13module is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16details. You should have received a copy of the GNU Lesser General Public
17License along with this module; if not, write to the Free Software Foundation,
18Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
19
20#include "blargg_source.h"
21
22const char* const gme_wrong_file_type = "Wrong file type for this emulator";
23
24double const fm_gain = 3.0; // FM emulators are internally quieter to avoid 16-bit overflow
25double const rolloff = 0.990;
26double const oversample_factor = 1.5;
27
28int const silence_max = 6; // seconds
29int const silence_threshold = 0x10;
30long const fade_block_size = 512;
31int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
32
33// VGM commands (Spec v1.50)
34enum {
35 cmd_gg_stereo = 0x4F,
36 cmd_psg = 0x50,
37 cmd_ym2413 = 0x51,
38 cmd_ym2612_port0 = 0x52,
39 cmd_ym2612_port1 = 0x53,
40 cmd_ym2151 = 0x54,
41 cmd_delay = 0x61,
42 cmd_delay_735 = 0x62,
43 cmd_delay_882 = 0x63,
44 cmd_byte_delay = 0x64,
45 cmd_end = 0x66,
46 cmd_data_block = 0x67,
47 cmd_short_delay = 0x70,
48 cmd_pcm_delay = 0x80,
49 cmd_pcm_seek = 0xE0,
50
51 pcm_block_type = 0x00,
52 ym2612_dac_port = 0x2A,
53 ym2612_dac_pan_port = 0xB6
54};
55
56void clear_track_vars( struct Vgm_Emu* this )
57{
58 this->out_time = 0;
59 this->emu_time = 0;
60 this->emu_track_ended_ = true;
61 this->track_ended = true;
62 this->fade_start = INT_MAX / 2 + 1;
63 this->fade_step = 1;
64 this->silence_time = 0;
65 this->silence_count = 0;
66 this->buf_remain = 0;
67}
68
69int play_frame( struct Vgm_Emu* this, blip_time_t blip_time, int sample_count, sample_t* buf );
70static int play_frame_( void* data, blip_time_t blip_time, int sample_count, short int* buf )
71{
72 return play_frame( (struct Vgm_Emu*) data, blip_time, sample_count, buf );
73}
74
75void Vgm_init( struct Vgm_Emu* this )
76{
77 this->sample_rate = 0;
78 this->mute_mask_ = 0;
79 this->tempo = 1.0;
80
81 // defaults
82 this->max_initial_silence = 2;
83 this->silence_lookahead = 1; // tracks should already be trimmed
84 this->ignore_silence = false;
85
86 // Disable oversampling by default
87 this->disable_oversampling = true;
88 this->psg_rate = 0;
89
90 Sms_apu_init( &this->psg );
91 Synth_init( &this->pcm );
92
93 Buffer_init( &this->buf );
94 Buffer_init( &this->stereo_buf );
95 this->blip_buf = &this->stereo_buf.bufs [0];
96
97 // Init fm chips
98 Ym2413_init( &this->ym2413 );
99 Ym2612_init( &this->ym2612 );
100
101 // Init resampler
102 Resampler_init( &this->resampler );
103 Resampler_set_callback( &this->resampler, play_frame_, this );
104
105 // Set sound gain, a value too high
106 // will cause saturation
107 Sound_set_gain(this, 1.0);
108
109 // Unload
110 this->voice_count = 0;
111 clear_track_vars( this );
112}
113
114// Track info
115
116static byte const* skip_gd3_str( byte const* in, byte const* end )
117{
118 while ( end - in >= 2 )
119 {
120 in += 2;
121 if ( !(in [-2] | in [-1]) )
122 break;
123 }
124 return in;
125}
126
127static byte const* get_gd3_str( byte const* in, byte const* end, char* field )
128{
129 byte const* mid = skip_gd3_str( in, end );
130 int i, len = (mid - in) / 2 - 1;
131 if ( field && len > 0 )
132 {
133 len = min( len, (int) gme_max_field );
134 field [len] = 0;
135 for ( i = 0; i < len; i++ )
136 field [i] = (in [i * 2 + 1] ? '?' : in [i * 2]); // TODO: convert to utf-8
137 }
138 return mid;
139}
140
141static byte const* get_gd3_pair( byte const* in, byte const* end, char* field )
142{
143 return skip_gd3_str( get_gd3_str( in, end, field ), end );
144}
145
146static void parse_gd3( byte const* in, byte const* end, struct track_info_t* out )
147{
148 in = get_gd3_pair( in, end, out->song );
149 in = get_gd3_pair( in, end, out->game );
150 in = get_gd3_pair( in, end, NULL ); // Skip system
151 in = get_gd3_pair( in, end, out->author );
152}
153
154int const gd3_header_size = 12;
155
156static long check_gd3_header( byte const* h, long remain )
157{
158 if ( remain < gd3_header_size ) return 0;
159 if ( memcmp( h, "Gd3 ", 4 ) ) return 0;
160 if ( get_le32( h + 4 ) >= 0x200 ) return 0;
161
162 long gd3_size = get_le32( h + 8 );
163 if ( gd3_size > remain - gd3_header_size )
164 gd3_size = remain - gd3_header_size;
165 return gd3_size;
166}
167
168byte const* gd3_data( struct Vgm_Emu* this, int* size )
169{
170 if ( size )
171 *size = 0;
172
173 long gd3_offset = get_le32( header( this )->gd3_offset ) - 0x2C;
174 if ( gd3_offset < 0 )
175 return 0;
176
177 byte const* gd3 = this->file_begin + header_size + gd3_offset;
178 long gd3_size = check_gd3_header( gd3, this->file_end - gd3 );
179 if ( !gd3_size )
180 return 0;
181
182 if ( size )
183 *size = gd3_size + gd3_header_size;
184
185 return gd3;
186}
187
188static void get_vgm_length( struct header_t const* h, struct track_info_t* out )
189{
190 long length = get_le32( h->track_duration ) * 10 / 441;
191 if ( length > 0 )
192 {
193 long loop = get_le32( h->loop_duration );
194 if ( loop > 0 && get_le32( h->loop_offset ) )
195 {
196 out->loop_length = loop * 10 / 441;
197 out->intro_length = length - out->loop_length;
198 }
199 else
200 {
201 out->length = length; // 1000 / 44100 (VGM files used 44100 as timebase)
202 out->intro_length = length; // make it clear that track is no longer than length
203 out->loop_length = 0;
204 }
205 }
206}
207
208blargg_err_t track_info( struct Vgm_Emu* this, struct track_info_t* out )
209{
210 memset(out, 0, sizeof out);
211 get_vgm_length( header( this ), out );
212
213 int size;
214 byte const* gd3 = gd3_data( this, &size );
215 if ( gd3 )
216 parse_gd3( gd3 + gd3_header_size, gd3 + size, out );
217
218 return 0;
219}
220
221static blargg_err_t check_vgm_header( struct header_t* h )
222{
223 if ( memcmp( h->tag, "Vgm ", 4 ) )
224 return gme_wrong_file_type;
225 return 0;
226}
227
228void set_voice( struct Vgm_Emu* this, int i, struct Blip_Buffer* c, struct Blip_Buffer* l, struct Blip_Buffer* r )
229{
230 if ( i < sms_osc_count ) {
231 int j;
232 for ( j = sms_osc_count; --j >= 0; )
233 Sms_apu_set_output( &this->psg, j, c, l, r );
234 }
235}
236
237blargg_err_t setup_fm( struct Vgm_Emu* this );
238blargg_err_t Vgm_load_mem( struct Vgm_Emu* this, byte const* new_data, long new_size, bool parse_info )
239{
240 // Unload
241 this->voice_count = 0;
242 clear_track_vars( this );
243
244 // Clear info
245 memset( &this->info, 0, sizeof this->info );
246
247 assert( offsetof (struct header_t,unused2 [8]) == header_size );
248
249 if ( new_size <= header_size )
250 return gme_wrong_file_type;
251
252 // Reset data pointers
253 this->file_begin = new_data;
254 this->file_end = new_data + new_size;
255
256 struct header_t* h = (struct header_t*) new_data;
257 RETURN_ERR( check_vgm_header( h ) );
258 check( get_le32( h.version ) <= 0x150 );
259
260 // If this was VGZ file gd3 parse info
261 if ( parse_info ) {
262 track_info( this, &this->info );
263
264 // If file was trimmed add an
265 // incomplete token to the game tag
266 if ( get_le32( h->data_size ) > (unsigned) new_size ) {
267 *((char *) this->file_end) = cmd_end;
268 strcat(this->info.game, "(Trimmed VGZ file)" );
269 }
270 }
271
272 // Get loop
273 this->loop_begin = this->file_end;
274
275 // If file was trimmed don't loop
276 if ( get_le32( h->loop_offset ) && get_le32( h->data_size ) <= (unsigned) new_size )
277 this->loop_begin = &new_data [get_le32( h->loop_offset ) + offsetof (struct header_t,loop_offset)];
278
279 // PSG rate
280 this->psg_rate = get_le32( h->psg_rate );
281 if ( !this->psg_rate )
282 this->psg_rate = 3579545;
283
284 Buffer_clock_rate( &this->stereo_buf, this->psg_rate );
285
286 // Disable FM
287 this->fm_rate = 0;
288 Ym2612_enable( &this->ym2612, false );
289 Ym2413_enable( &this->ym2413, false );
290
291 Sound_set_tempo( this, 1 );
292
293 this->voice_count = sms_osc_count;
294
295 RETURN_ERR( setup_fm( this ) );
296
297 // do after FM in case output buffer is changed
298 // setup buffer
299 this->clock_rate_ = this->psg_rate;
300 Buffer_clock_rate( &this->buf, this->psg_rate );
301
302 // Setup bass
303 this->buf_changed_count = Buffer_channels_changed_count( &this->buf );
304
305 // Post load
306 Sound_set_tempo( this, this->tempo );
307 Sound_mute_voices( this, this->mute_mask_ );
308
309 return 0;
310}
311
312void update_fm_rates( struct Vgm_Emu* this, int* ym2413_rate, int* ym2612_rate );
313blargg_err_t init_fm( struct Vgm_Emu* this, double* rate )
314{
315 int ym2612_rate = get_le32( header( this )->ym2612_rate );
316 int ym2413_rate = get_le32( header( this )->ym2413_rate );
317 if ( ym2413_rate && get_le32( header( this )->version ) < 0x110 )
318 update_fm_rates( this, &ym2413_rate, &ym2612_rate );
319
320 if ( ym2612_rate )
321 {
322 if ( !*rate )
323 *rate = ym2612_rate / 144.0;
324 RETURN_ERR( Ym2612_set_rate( &this->ym2612, *rate, ym2612_rate ) );
325 Ym2612_enable( &this->ym2612, true );
326 }
327 else if ( ym2413_rate )
328 {
329 if ( !*rate )
330 *rate = ym2413_rate / 72.0;
331 int result = Ym2413_set_rate( &this->ym2413, *rate, ym2413_rate );
332 if ( result == 2 )
333 return "YM2413 FM sound not supported";
334 CHECK_ALLOC( !result );
335 Ym2413_enable( &this->ym2413, true );
336 }
337
338 this->fm_rate = *rate;
339
340 return 0;
341}
342
343blargg_err_t setup_fm( struct Vgm_Emu* this )
344{
345 double fm_rate = 0.0;
346 if ( !this->disable_oversampling )
347 this->fm_rate = this->sample_rate * oversample_factor;
348 RETURN_ERR( init_fm( this, &fm_rate ) );
349
350 if ( uses_fm( this ) )
351 {
352 this->voice_count = 8;
353 RETURN_ERR( Resampler_setup( &this->resampler, fm_rate / this->sample_rate, rolloff, fm_gain * this->gain ) );
354 RETURN_ERR( Resampler_reset( &this->resampler, Buffer_length( &this->stereo_buf ) * this->sample_rate / 1000 ) );
355 Sms_apu_volume( &this->psg, 0.195 * fm_gain * this->gain );
356 }
357 else
358 {
359 Sms_apu_volume( &this->psg, this->gain );
360 }
361
362 return 0;
363}
364
365// Emulation
366
367blip_time_t run( struct Vgm_Emu* this, vgm_time_t end_time );
368blargg_err_t run_clocks( struct Vgm_Emu* this, blip_time_t* time_io, int msec )
369{
370 *time_io = run( this, msec * this->vgm_rate / 1000 );
371 Sms_apu_end_frame( &this->psg, *time_io );
372 return 0;
373}
374
375
376
377blargg_err_t play_( struct Vgm_Emu* this, long count, sample_t* out )
378{
379 if ( !uses_fm( this ) ) {
380 long remain = count;
381 while ( remain )
382 {
383 remain -= Buffer_read_samples( &this->buf, &out [count - remain], remain );
384 if ( remain )
385 {
386 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->buf ) )
387 {
388 this->buf_changed_count = Buffer_channels_changed_count( &this->buf );
389
390 // Remute voices
391 Sound_mute_voices( this, this->mute_mask_ );
392 }
393 int msec = Buffer_length( &this->buf );
394 blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate_ / 1000 - 100;
395 RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) );
396 assert( clocks_emulated );
397 Buffer_end_frame( &this->buf, clocks_emulated );
398 }
399 }
400
401 return 0;
402 }
403
404 Resampler_play( &this->resampler, count, out, &this->stereo_buf );
405 return 0;
406}
407
408// Vgm_Emu_impl
409
410inline int command_len( int command )
411{
412 static byte const lens [0x10] ICONST_ATTR = {
413 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
414 1,1,1,2,2,3,1,1,1,1,3,3,4,4,5,5
415 };
416 int len = lens [command >> 4];
417 check( len != 1 );
418 return len;
419}
420
421inline fm_time_t to_fm_time( struct Vgm_Emu* this, vgm_time_t t )
422{
423 return (t * this->fm_time_factor + this->fm_time_offset) >> fm_time_bits;
424}
425
426inline blip_time_t to_psg_time( struct Vgm_Emu* this, vgm_time_t t )
427{
428 return (t * this->blip_time_factor) >> blip_time_bits;
429}
430
431void write_pcm( struct Vgm_Emu* this, vgm_time_t vgm_time, int amp )
432{
433 if ( this->blip_buf )
434 {
435 check( amp >= 0 );
436 blip_time_t blip_time = to_psg_time( this, vgm_time );
437 int old = this->dac_amp;
438 int delta = amp - old;
439 this->dac_amp = amp;
440 Blip_set_modified( this->blip_buf );
441 if ( old >= 0 ) // first write is ignored, to avoid click
442 Synth_offset_inline( &this->pcm, blip_time, delta, this->blip_buf );
443 else
444 this->dac_amp |= this->dac_disabled;
445 }
446}
447
448blip_time_t run( struct Vgm_Emu* this, vgm_time_t end_time )
449{
450 vgm_time_t vgm_time = this->vgm_time;
451 byte const* pos = this->pos;
452 if ( pos >= this->file_end )
453 {
454 this->emu_track_ended_ = true;
455 /* if ( pos > data_end )
456 warning( "Stream lacked end event" ); */
457 }
458
459 while ( vgm_time < end_time && pos < this->file_end )
460 {
461 // TODO: be sure there are enough bytes left in stream for particular command
462 // so we don't read past end
463 switch ( *pos++ )
464 {
465 case cmd_end:
466 pos = this->loop_begin; // if not looped, loop_begin == data_end
467 break;
468
469 case cmd_delay_735:
470 vgm_time += 735;
471 break;
472
473 case cmd_delay_882:
474 vgm_time += 882;
475 break;
476
477 case cmd_gg_stereo:
478 Sms_apu_write_ggstereo( &this->psg, to_psg_time( this, vgm_time ), *pos++ );
479 break;
480
481 case cmd_psg:
482 Sms_apu_write_data( &this->psg, to_psg_time( this, vgm_time ), *pos++ );
483 break;
484
485 case cmd_delay:
486 vgm_time += pos [1] * 0x100 + pos [0];
487 pos += 2;
488 break;
489
490 case cmd_byte_delay:
491 vgm_time += *pos++;
492 break;
493
494 case cmd_ym2413:
495 if ( Ym2413_run_until( &this->ym2413, to_fm_time( this, vgm_time ) ) )
496 Ym2413_write( &this->ym2413, pos [0], pos [1] );
497 pos += 2;
498 break;
499
500 case cmd_ym2612_port0:
501 if ( pos [0] == ym2612_dac_port )
502 {
503 write_pcm( this, vgm_time, pos [1] );
504 }
505 else if ( Ym2612_run_until( &this->ym2612, to_fm_time( this, vgm_time ) ) )
506 {
507 if ( pos [0] == 0x2B )
508 {
509 this->dac_disabled = (pos [1] >> 7 & 1) - 1;
510 this->dac_amp |= this->dac_disabled;
511 }
512 Ym2612_write0( &this->ym2612, pos [0], pos [1] );
513 }
514 pos += 2;
515 break;
516
517 case cmd_ym2612_port1:
518 if ( Ym2612_run_until( &this->ym2612, to_fm_time( this, vgm_time ) ) )
519 {
520 if ( pos [0] == ym2612_dac_pan_port )
521 {
522 struct Blip_Buffer* blip_buf = NULL;
523 switch ( pos [1] >> 6 )
524 {
525 case 0: blip_buf = NULL; break;
526 case 1: blip_buf = &this->stereo_buf.bufs [2]; break;
527 case 2: blip_buf = &this->stereo_buf.bufs [1]; break;
528 case 3: blip_buf = &this->stereo_buf.bufs [0]; break;
529 }
530 this->blip_buf = blip_buf;
531 }
532
533 Ym2612_write1( &this->ym2612, pos [0], pos [1] );
534 }
535 pos += 2;
536 break;
537
538 case cmd_data_block: {
539 check( *pos == cmd_end );
540 int type = pos [1];
541 long size = get_le32( pos + 2 );
542 pos += 6;
543 if ( type == pcm_block_type )
544 this->pcm_data = pos;
545 pos += size;
546 break;
547 }
548
549 case cmd_pcm_seek:
550 this->pcm_pos = this->pcm_data + pos [3] * 0x1000000 + pos [2] * 0x10000 +
551 pos [1] * 0x100 + pos [0];
552 pos += 4;
553 break;
554
555 default: {
556 int cmd = pos [-1];
557 switch ( cmd & 0xF0 )
558 {
559 case cmd_pcm_delay:
560 write_pcm( this, vgm_time, *this->pcm_pos++ );
561 vgm_time += cmd & 0x0F;
562 break;
563
564 case cmd_short_delay:
565 vgm_time += (cmd & 0x0F) + 1;
566 break;
567
568 case 0x50:
569 pos += 2;
570 break;
571
572 default:
573 pos += command_len( cmd ) - 1;
574 /* warning( "Unknown stream event" ); */
575 }
576 }
577 }
578 }
579 vgm_time -= end_time;
580 this->pos = pos;
581 this->vgm_time = vgm_time;
582
583 return to_psg_time( this, end_time );
584}
585
586int play_frame( struct Vgm_Emu* this, blip_time_t blip_time, int sample_count, blip_sample_t out [] )
587{
588 // to do: timing is working mostly by luck
589 int min_pairs = (unsigned) sample_count / 2;
590 int vgm_time = (min_pairs << fm_time_bits) / this->fm_time_factor - 1;
591 assert( to_fm_time( this, vgm_time ) <= min_pairs );
592 int pairs;
593 while ( (pairs = to_fm_time( this, vgm_time )) < min_pairs )
594 vgm_time++;
595 //debug_printf( "pairs: %d, min_pairs: %d\n", pairs, min_pairs );
596
597 if ( Ym2612_enabled( &this->ym2612 ) )
598 {
599 Ym2612_begin_frame( &this->ym2612, out );
600 memset( out, 0, pairs * stereo * sizeof *out );
601 }
602 else if ( Ym2413_enabled( &this->ym2413 ) )
603 {
604 Ym2413_begin_frame( &this->ym2413, out );
605 }
606
607 run( this, vgm_time );
608 Ym2612_run_until( &this->ym2612, pairs );
609 Ym2413_run_until( &this->ym2413, pairs );
610
611 this->fm_time_offset = (vgm_time * this->fm_time_factor + this->fm_time_offset) - (pairs << fm_time_bits);
612
613 Sms_apu_end_frame( &this->psg, blip_time );
614
615 return pairs * stereo;
616}
617
618// Update pre-1.10 header FM rates by scanning commands
619void update_fm_rates( struct Vgm_Emu* this, int* ym2413_rate, int* ym2612_rate )
620{
621 byte const* p = this->file_begin + 0x40;
622 while ( p < this->file_end )
623 {
624 switch ( *p )
625 {
626 case cmd_end:
627 return;
628
629 case cmd_psg:
630 case cmd_byte_delay:
631 p += 2;
632 break;
633
634 case cmd_delay:
635 p += 3;
636 break;
637
638 case cmd_data_block:
639 p += 7 + get_le32( p + 3 );
640 break;
641
642 case cmd_ym2413:
643 *ym2612_rate = 0;
644 return;
645
646 case cmd_ym2612_port0:
647 case cmd_ym2612_port1:
648 *ym2612_rate = *ym2413_rate;
649 *ym2413_rate = 0;
650 return;
651
652 case cmd_ym2151:
653 *ym2413_rate = 0;
654 *ym2612_rate = 0;
655 return;
656
657 default:
658 p += command_len( *p );
659 }
660 }
661}
662
663
664// Music Emu
665
666blargg_err_t Vgm_set_sample_rate( struct Vgm_Emu* this, long rate )
667{
668 require( !this->sample_rate ); // sample rate can't be changed once set
669 RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 30 ) );
670 RETURN_ERR( Buffer_set_sample_rate( &this->buf, rate, 1000 / 20 ) );
671
672 // Set bass frequency
673 Buffer_bass_freq( &this->buf, 80 );
674
675 this->sample_rate = rate;
676 return 0;
677}
678
679void Sound_mute_voice( struct Vgm_Emu* this, int index, bool mute )
680{
681 require( (unsigned) index < (unsigned) this->voice_count );
682 int bit = 1 << index;
683 int mask = this->mute_mask_ | bit;
684 if ( !mute )
685 mask ^= bit;
686 Sound_mute_voices( this, mask );
687}
688
689void Sound_mute_voices( struct Vgm_Emu* this, int mask )
690{
691 require( this->sample_rate ); // sample rate must be set first
692 this->mute_mask_ = mask;
693
694 int i;
695 for ( i = this->voice_count; i--; )
696 {
697 if ( mask & (1 << i) )
698 {
699 set_voice( this, i, 0, 0, 0 );
700 }
701 else
702 {
703 struct channel_t ch = Buffer_channel( &this->buf );
704 assert( (ch.center && ch.left && ch.right) ||
705 (!ch.center && !ch.left && !ch.right) ); // all or nothing
706 set_voice( this, i, ch.center, ch.left, ch.right );
707 }
708 }
709
710 // TODO: what was this for?
711 //core.pcm.output( &core.blip_buf );
712
713 // TODO: silence PCM if FM isn't used?
714 if ( uses_fm( this ) )
715 {
716 for ( i = sms_osc_count; --i >= 0; )
717 Sms_apu_set_output( &this->psg, i, ( mask & 0x80 ) ? 0 : &this->stereo_buf.bufs [0], NULL, NULL );
718 if ( Ym2612_enabled( &this->ym2612 ) )
719 {
720 Synth_volume( &this->pcm, (mask & 0x40) ? 0.0 : 0.1115 / 256 * fm_gain * this->gain );
721 Ym2612_mute_voices( &this->ym2612, mask );
722 }
723
724 if ( Ym2413_enabled( &this->ym2413 ) )
725 {
726 int m = mask & 0x3F;
727 if ( mask & 0x20 )
728 m |= 0x01E0; // channels 5-8
729 if ( mask & 0x40 )
730 m |= 0x3E00;
731 Ym2413_mute_voices( &this->ym2413, m );
732 }
733 }
734}
735
736void Sound_set_tempo( struct Vgm_Emu* this, double t )
737{
738 require( this->sample_rate ); // sample rate must be set first
739 double const min = 0.02;
740 double const max = 4.00;
741 if ( t < min ) t = min;
742 if ( t > max ) t = max;
743 this->tempo = t;
744
745 if ( this->file_begin )
746 {
747 this->vgm_rate = (long) (44100 * t + 0.5);
748 this->blip_time_factor = (int) ((double)
749 (1 << blip_time_bits) / this->vgm_rate * Blip_clock_rate( &this->stereo_buf.bufs [0] ) + 0.5);
750 //debug_printf( "blip_time_factor: %ld\n", blip_time_factor );
751 //debug_printf( "vgm_rate: %ld\n", vgm_rate );
752 // TODO: remove? calculates vgm_rate more accurately (above differs at most by one Hz only)
753 //blip_time_factor = (long) floor( double (1L << blip_time_bits) * psg_rate / 44100 / t + 0.5 );
754 //vgm_rate = (long) floor( double (1L << blip_time_bits) * psg_rate / blip_time_factor + 0.5 );
755
756 this->fm_time_factor = 2 + (int) (this->fm_rate * (1 << fm_time_bits) / this->vgm_rate + 0.5);
757 }
758}
759
760void fill_buf( struct Vgm_Emu *this );
761blargg_err_t Vgm_start_track( struct Vgm_Emu* this )
762{
763 clear_track_vars( this );
764
765 Sms_apu_reset( &this->psg, get_le16( header( this )->noise_feedback ), header( this )->noise_width );
766
767 this->blip_buf = &this->stereo_buf.bufs [0];
768
769 this->dac_disabled = -1;
770 this->pos = this->file_begin + header_size;
771 this->pcm_data = this->pos;
772 this->pcm_pos = this->pos;
773 this->dac_amp = -1;
774 this->vgm_time = 0;
775 if ( get_le32( header( this )->version ) >= 0x150 )
776 {
777 long data_offset = get_le32( header( this )->data_offset );
778 check( data_offset );
779 if ( data_offset )
780 this->pos += data_offset + offsetof (struct header_t,data_offset) - 0x40;
781 }
782
783 if ( uses_fm( this ) )
784 {
785 if ( Ym2413_enabled( &this->ym2413 ) )
786 Ym2413_reset( &this->ym2413 );
787
788 if ( Ym2612_enabled( &this->ym2612 ) )
789 Ym2612_reset( &this->ym2612 );
790
791 Buffer_clear( &this->stereo_buf );
792 Resampler_clear( &this->resampler );
793 }
794
795 this->fm_time_offset = 0;
796
797 Buffer_clear( &this->buf );
798
799 this->emu_track_ended_ = false;
800 this->track_ended = false;
801
802 if ( !this->ignore_silence )
803 {
804 // play until non-silence or end of track
805 long end;
806 for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; )
807 {
808 fill_buf( this );
809 if ( this->buf_remain | (int) this->emu_track_ended_ )
810 break;
811 }
812
813 this->emu_time = this->buf_remain;
814 this->out_time = 0;
815 this->silence_time = 0;
816 this->silence_count = 0;
817 }
818 /* return track_ended() ? warning() : 0; */
819 return 0;
820}
821
822// Tell/Seek
823
824blargg_long msec_to_samples( blargg_long msec, long sample_rate )
825{
826 blargg_long sec = msec / 1000;
827 msec -= sec * 1000;
828 return (sec * sample_rate + msec * sample_rate / 1000) * stereo;
829}
830
831long Track_tell( struct Vgm_Emu* this )
832{
833 blargg_long rate = this->sample_rate * stereo;
834 blargg_long sec = this->out_time / rate;
835 return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate;
836}
837
838blargg_err_t Track_seek( struct Vgm_Emu* this, long msec )
839{
840 blargg_long time = msec_to_samples( msec, this->sample_rate );
841 if ( time < this->out_time )
842 RETURN_ERR( Vgm_start_track( this ) );
843 return Track_skip( this, time - this->out_time );
844}
845
846blargg_err_t skip_( struct Vgm_Emu* this, long count );
847blargg_err_t Track_skip( struct Vgm_Emu* this, long count )
848{
849 this->out_time += count;
850
851 // remove from silence and buf first
852 {
853 long n = min( count, this->silence_count );
854 this->silence_count -= n;
855 count -= n;
856
857 n = min( count, this->buf_remain );
858 this->buf_remain -= n;
859 count -= n;
860 }
861
862 if ( count && !this->emu_track_ended_ )
863 {
864 this->emu_time += count;
865 if ( skip_( this, count ) )
866 this->emu_track_ended_ = true;
867 }
868
869 if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended
870 this->track_ended |= this->emu_track_ended_;
871
872 return 0;
873}
874
875blargg_err_t skip_( struct Vgm_Emu* this, long count )
876{
877 // for long skip, mute sound
878 const long threshold = 30000;
879 if ( count > threshold )
880 {
881 int saved_mute = this->mute_mask_;
882 Sound_mute_voices( this, ~0 );
883
884 while ( count > threshold / 2 && !this->emu_track_ended_ )
885 {
886 RETURN_ERR( play_( this, buf_size, this->buf_ ) );
887 count -= buf_size;
888 }
889
890 Sound_mute_voices( this, saved_mute );
891 }
892
893 while ( count && !this->emu_track_ended_ )
894 {
895 long n = buf_size;
896 if ( n > count )
897 n = count;
898 count -= n;
899 RETURN_ERR( play_( this, n, this->buf_ ) );
900 }
901 return 0;
902}
903
904// Fading
905
906void Track_set_fade( struct Vgm_Emu* this, long start_msec, long length_msec )
907{
908 this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo);
909 this->fade_start = msec_to_samples( start_msec, this->sample_rate );
910}
911
912// unit / pow( 2.0, (double) x / step )
913static int int_log( blargg_long x, int step, int unit )
914{
915 int shift = x / step;
916 int fraction = (x - shift * step) * unit / step;
917 return ((unit - fraction) + (fraction >> 1)) >> shift;
918}
919
920void handle_fade( struct Vgm_Emu* this, long out_count, sample_t* out )
921{
922 int i;
923 for ( i = 0; i < out_count; i += fade_block_size )
924 {
925 int const shift = 14;
926 int const unit = 1 << shift;
927 int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size,
928 this->fade_step, unit );
929 if ( gain < (unit >> fade_shift) )
930 this->track_ended = this->emu_track_ended_ = true;
931
932 sample_t* io = &out [i];
933 int count;
934 for ( count = min( fade_block_size, out_count - i ); count; --count )
935 {
936 *io = (sample_t) ((*io * gain) >> shift);
937 ++io;
938 }
939 }
940}
941
942// Silence detection
943
944void emu_play( struct Vgm_Emu* this, long count, sample_t* out )
945{
946 this->emu_time += count;
947 if ( !this->emu_track_ended_ ) {
948 if ( play_( this, count, out ) )
949 this->emu_track_ended_ = true;
950 }
951 else
952 memset( out, 0, count * sizeof *out );
953}
954
955// number of consecutive silent samples at end
956static long count_silence( sample_t* begin, long size )
957{
958 sample_t first = *begin;
959 *begin = silence_threshold; // sentinel
960 sample_t* p = begin + size;
961 while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { }
962 *begin = first;
963 return size - (p - begin);
964}
965
966// fill internal buffer and check it for silence
967void fill_buf( struct Vgm_Emu* this )
968{
969 assert( !this->buf_remain );
970 if ( !this->emu_track_ended_ )
971 {
972 emu_play( this, buf_size, this->buf_ );
973 long silence = count_silence( this->buf_, buf_size );
974 if ( silence < buf_size )
975 {
976 this->silence_time = this->emu_time - silence;
977 this->buf_remain = buf_size;
978 return;
979 }
980 }
981 this->silence_count += buf_size;
982}
983
984blargg_err_t Vgm_play( struct Vgm_Emu* this, long out_count, sample_t* out )
985{
986 if ( this->track_ended )
987 {
988 memset( out, 0, out_count * sizeof *out );
989 }
990 else
991 {
992 require( out_count % stereo == 0 );
993
994 assert( this->emu_time >= this->out_time );
995
996 // prints nifty graph of how far ahead we are when searching for silence
997 //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" );
998
999 long pos = 0;
1000 if ( this->silence_count )
1001 {
1002 // during a run of silence, run emulator at >=2x speed so it gets ahead
1003 long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time;
1004 while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) )
1005 fill_buf( this );
1006
1007 // fill with silence
1008 pos = min( this->silence_count, out_count );
1009 memset( out, 0, pos * sizeof *out );
1010 this->silence_count -= pos;
1011
1012 if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate )
1013 {
1014 this->track_ended = this->emu_track_ended_ = true;
1015 this->silence_count = 0;
1016 this->buf_remain = 0;
1017 }
1018 }
1019
1020 if ( this->buf_remain )
1021 {
1022 // empty silence buf
1023 long n = min( this->buf_remain, out_count - pos );
1024 memcpy( &out [pos], this->buf_ + (buf_size - this->buf_remain), n * sizeof *out );
1025 this->buf_remain -= n;
1026 pos += n;
1027 }
1028
1029 // generate remaining samples normally
1030 long remain = out_count - pos;
1031 if ( remain )
1032 {
1033 emu_play( this, remain, out + pos );
1034 this->track_ended |= this->emu_track_ended_;
1035
1036 if ( !this->ignore_silence || this->out_time > this->fade_start )
1037 {
1038 // check end for a new run of silence
1039 long silence = count_silence( out + pos, remain );
1040 if ( silence < remain )
1041 this->silence_time = this->emu_time - silence;
1042
1043 if ( this->emu_time - this->silence_time >= buf_size )
1044 fill_buf( this ); // cause silence detection on next play()
1045 }
1046 }
1047
1048 if ( this->out_time > this->fade_start )
1049 handle_fade( this, out_count, out );
1050 }
1051 this->out_time += out_count;
1052 return 0;
1053}
diff --git a/apps/codecs/libgme/vgm_emu.h b/apps/codecs/libgme/vgm_emu.h
new file mode 100644
index 0000000000..deb64bc7e0
--- /dev/null
+++ b/apps/codecs/libgme/vgm_emu.h
@@ -0,0 +1,211 @@
1// Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro VGM music file emulator
2
3// Game_Music_Emu 0.5.5
4#ifndef VGM_EMU_H
5#define VGM_EMU_H
6
7#include "blargg_common.h"
8#include "blargg_source.h"
9#include "resampler.h"
10#include "multi_buffer.h"
11#include "ym2413_emu.h"
12#include "ym2612_emu.h"
13#include "sms_apu.h"
14
15typedef short sample_t;
16typedef int vgm_time_t;
17typedef int fm_time_t;
18
19enum { fm_time_bits = 12 };
20enum { blip_time_bits = 12 };
21enum { buf_size = 2048 };
22
23// VGM header format
24enum { header_size = 0x40 };
25struct header_t
26{
27 char tag [4];
28 byte data_size [4];
29 byte version [4];
30 byte psg_rate [4];
31 byte ym2413_rate [4];
32 byte gd3_offset [4];
33 byte track_duration [4];
34 byte loop_offset [4];
35 byte loop_duration [4];
36 byte frame_rate [4];
37 byte noise_feedback [2];
38 byte noise_width;
39 byte unused1;
40 byte ym2612_rate [4];
41 byte ym2151_rate [4];
42 byte data_offset [4];
43 byte unused2 [8];
44};
45
46enum { gme_max_field = 63 };
47struct track_info_t
48{
49 /* times in milliseconds; -1 if unknown */
50 long length;
51 long intro_length;
52 long loop_length;
53
54 /* empty string if not available */
55 char game [64];
56 char song [96];
57 char author [64];
58};
59
60// Emulates VGM music using SN76489/SN76496 PSG, YM2612, and YM2413 FM sound chips.
61// Supports custom sound buffer and frequency equalization when VGM uses just the PSG.
62// FM sound chips can be run at their proper rates, or slightly higher to reduce
63// aliasing on high notes. Currently YM2413 support requires that you supply a
64// YM2413 sound chip emulator. I can provide one I've modified to work with the library.
65struct Vgm_Emu {
66 double fm_rate;
67 long psg_rate;
68 long vgm_rate;
69 bool disable_oversampling;
70
71 long fm_time_offset;
72 int fm_time_factor;
73
74 int blip_time_factor;
75
76 byte const* file_begin;
77 byte const* file_end;
78
79 vgm_time_t vgm_time;
80 byte const* loop_begin;
81 byte const* pos;
82
83 byte const* pcm_data;
84 byte const* pcm_pos;
85 int dac_amp;
86 int dac_disabled; // -1 if disabled
87
88 struct Blip_Buffer* blip_buf;
89
90 // general
91 long clock_rate_;
92 unsigned buf_changed_count;
93 int max_initial_silence;
94 int voice_count;
95 int mute_mask_;
96 double tempo;
97 double gain;
98
99 long sample_rate;
100
101 // track-specific
102 blargg_long out_time; // number of samples played since start of track
103 blargg_long emu_time; // number of samples emulator has generated since start of track
104 bool emu_track_ended_; // emulator has reached end of track
105 volatile bool track_ended;
106
107 // fading
108 blargg_long fade_start;
109 int fade_step;
110
111 // silence detection
112 int silence_lookahead; // speed to run emulator when looking ahead for silence
113 bool ignore_silence;
114 long silence_time; // number of samples where most recent silence began
115 long silence_count; // number of samples of silence to play before using buf
116 long buf_remain; // number of samples left in silence buffer
117
118 // larger items at the end
119 struct track_info_t info;
120 sample_t buf_ [buf_size];
121
122 struct Ym2612_Emu ym2612;
123 struct Ym2413_Emu ym2413;
124
125 struct Sms_Apu psg;
126 struct Blip_Synth pcm;
127 struct Stereo_Buffer stereo_buf;
128
129 struct Resampler resampler;
130
131 struct Stereo_Buffer buf;
132};
133
134void Vgm_init( struct Vgm_Emu* this );
135
136// Disable running FM chips at higher than normal rate. Will result in slightly
137// more aliasing of high notes.
138static inline void Vgm_disable_oversampling( struct Vgm_Emu* this, bool disable ) { this->disable_oversampling = disable; }
139
140// Header for currently loaded file
141static inline struct header_t *header( struct Vgm_Emu* this ) { return (struct header_t*) this->file_begin; }
142
143// Basic functionality (see Gme_File.h for file loading/track info functions)
144blargg_err_t Vgm_load_mem( struct Vgm_Emu* this, byte const* new_data, long new_size, bool parse_info );
145
146// True if any FM chips are used by file. Always false until init_fm()
147// is called.
148static inline bool uses_fm( struct Vgm_Emu* this ) { return Ym2612_enabled( &this->ym2612 ) || Ym2413_enabled( &this->ym2413 ); }
149
150// Set output sample rate. Must be called only once before loading file.
151blargg_err_t Vgm_set_sample_rate( struct Vgm_Emu* this, long sample_rate );
152
153// Start a track, where 0 is the first track. Also clears warning string.
154blargg_err_t Vgm_start_track( struct Vgm_Emu* this );
155
156// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation
157// errors set warning string, and major errors also end track.
158blargg_err_t Vgm_play( struct Vgm_Emu* this, long count, sample_t* buf ) ICODE_ATTR;
159
160// Track status/control
161
162// Number of milliseconds (1000 msec = 1 second) played since beginning of track
163long Track_tell( struct Vgm_Emu* this );
164
165// Seek to new time in track. Seeking backwards or far forward can take a while.
166blargg_err_t Track_seek( struct Vgm_Emu* this, long msec );
167
168// Skip n samples
169blargg_err_t Track_skip( struct Vgm_Emu* this, long n );
170
171// Set start time and length of track fade out. Once fade ends track_ended() returns
172// true. Fade time can be changed while track is playing.
173void Track_set_fade( struct Vgm_Emu* this, long start_msec, long length_msec );
174
175// Get track length in milliseconds
176static inline long Track_get_length( struct Vgm_Emu* this )
177{
178 long length = this->info.length;
179 if ( length <= 0 )
180 {
181 length = this->info.intro_length + 2 * this->info.loop_length; // intro + 2 loops
182 if ( length <= 0 )
183 length = 150 * 1000; // 2.5 minutes
184 }
185
186 return length;
187}
188
189// Sound customization
190
191// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed.
192// Track length as returned by track_info() assumes a tempo of 1.0.
193void Sound_set_tempo( struct Vgm_Emu* this, double t );
194
195// Mute/unmute voice i, where voice 0 is first voice
196void Sound_mute_voice( struct Vgm_Emu* this, int index, bool mute );
197
198// Set muting state of all voices at once using a bit mask, where -1 mutes them all,
199// 0 unmutes them all, 0x01 mutes just the first voice, etc.
200void Sound_mute_voices( struct Vgm_Emu* this, int mask );
201
202// Change overall output amplitude, where 1.0 results in minimal clamping.
203// Must be called before set_sample_rate().
204static inline void Sound_set_gain( struct Vgm_Emu* this, double g )
205{
206 assert( !this->sample_rate ); // you must set gain before setting sample rate
207 this->gain = g;
208}
209
210
211#endif
diff --git a/apps/codecs/libgme/vrc7tone.h b/apps/codecs/libgme/vrc7tone.h
new file mode 100644
index 0000000000..a256c80ba6
--- /dev/null
+++ b/apps/codecs/libgme/vrc7tone.h
@@ -0,0 +1,20 @@
1/* VRC7 TONES by okazaki@angel.ne.jp */
20x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
30x33,0x01,0x09,0x0e,0x94,0x90,0x40,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
40x13,0x41,0x0f,0x0d,0xce,0xd3,0x43,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
50x01,0x12,0x1b,0x06,0xff,0xd2,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
60x61,0x61,0x1b,0x07,0xaf,0x63,0x20,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
70x22,0x21,0x1e,0x06,0xf0,0x76,0x08,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
80x66,0x21,0x15,0x00,0x93,0x94,0x20,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
90x21,0x61,0x1c,0x07,0x82,0x81,0x10,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100x23,0x21,0x20,0x1f,0xc0,0x71,0x07,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
110x25,0x31,0x26,0x05,0x64,0x41,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
120x17,0x21,0x28,0x07,0xff,0x83,0x02,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
130x97,0x81,0x25,0x07,0xcf,0xc8,0x02,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
140x21,0x21,0x54,0x0f,0x80,0x7f,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
150x01,0x01,0x56,0x03,0xd3,0xb2,0x43,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
160x31,0x21,0x0c,0x03,0x82,0xc0,0x40,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
170x21,0x01,0x0c,0x03,0xd4,0xd3,0x40,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
180x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
190x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
200x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
diff --git a/apps/codecs/libgme/ym2413_emu.c b/apps/codecs/libgme/ym2413_emu.c
new file mode 100644
index 0000000000..67870f31dc
--- /dev/null
+++ b/apps/codecs/libgme/ym2413_emu.c
@@ -0,0 +1,45 @@
1// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/
2
3#include "ym2413_emu.h"
4
5void Ym2413_init( struct Ym2413_Emu* this )
6{
7 this->last_time = disabled_time; this->out = 0;
8}
9
10int Ym2413_set_rate( struct Ym2413_Emu* this, double sample_rate, double clock_rate )
11{
12 OPLL_new ( &this->opll, clock_rate, sample_rate );
13 OPLL_reset_patch( &this->opll, OPLL_2413_TONE );
14
15 Ym2413_reset( this );
16 return 0;
17}
18
19void Ym2413_reset( struct Ym2413_Emu* this )
20{
21 OPLL_reset( &this->opll );
22 OPLL_setMask( &this->opll, 0 );
23}
24
25void Ym2413_write( struct Ym2413_Emu* this, int addr, int data )
26{
27 OPLL_writeIO( &this->opll, 0, addr );
28 OPLL_writeIO( &this->opll, 1, data );
29}
30
31void Ym2413_mute_voices( struct Ym2413_Emu* this, int mask )
32{
33 OPLL_setMask( &this->opll, mask );
34}
35
36void Ym2413_run( struct Ym2413_Emu* this, int pair_count, short* out )
37{
38 while ( pair_count-- )
39 {
40 int s = OPLL_calc( &this->opll ) << 1;
41 out [0] = s;
42 out [1] = s;
43 out += 2;
44 }
45}
diff --git a/apps/codecs/libgme/ym2413_emu.h b/apps/codecs/libgme/ym2413_emu.h
new file mode 100644
index 0000000000..71369e9c88
--- /dev/null
+++ b/apps/codecs/libgme/ym2413_emu.h
@@ -0,0 +1,61 @@
1// YM2413 FM sound chip emulator interface
2
3// Game_Music_Emu 0.6-pre
4#ifndef YM2413_EMU_H
5#define YM2413_EMU_H
6
7#include "blargg_common.h"
8#include "emu2413.h"
9
10enum { out_chan_count = 2 }; // stereo
11enum { channel_count = 14 };
12enum { disabled_time = -1 };
13
14struct Ym2413_Emu {
15 OPLL opll;
16
17 // Impl
18 int last_time;
19 short* out;
20};
21
22void Ym2413_init( struct Ym2413_Emu* this );
23
24static inline bool Ym2413_supported( void ) { return true; }
25
26// Sets output sample rate and chip clock rates, in Hz. Returns non-zero
27// if error.
28int Ym2413_set_rate( struct Ym2413_Emu* this, double sample_rate, double clock_rate );
29
30// Resets to power-up state
31void Ym2413_reset( struct Ym2413_Emu* this );
32
33// Mutes voice n if bit n (1 << n) of mask is set
34void Ym2413_mute_voices( struct Ym2413_Emu* this, int mask );
35
36// Writes data to addr
37void Ym2413_write( struct Ym2413_Emu* this, int addr, int data ) ICODE_ATTR;
38
39// Runs and writes pair_count*2 samples to output
40void Ym2413_run( struct Ym2413_Emu* this, int pair_count, short* out ) ICODE_ATTR;
41
42static inline void Ym2413_enable( struct Ym2413_Emu* this, bool b ) { this->last_time = b ? 0 : disabled_time; }
43static inline bool Ym2413_enabled( struct Ym2413_Emu* this ) { return this->last_time != disabled_time; }
44static inline void Ym2413_begin_frame( struct Ym2413_Emu* this, short* buf ) { this->out = buf; this->last_time = 0; }
45
46static inline int Ym2413_run_until( struct Ym2413_Emu* this, int time )
47{
48 int count = time - this->last_time;
49 if ( count > 0 )
50 {
51 if ( this->last_time < 0 )
52 return false;
53 this->last_time = time;
54 short* p = this->out;
55 this->out += count * out_chan_count;
56 Ym2413_run( this, count, p );
57 }
58 return true;
59}
60
61#endif
diff --git a/apps/codecs/libgme/ym2612_emu.c b/apps/codecs/libgme/ym2612_emu.c
new file mode 100644
index 0000000000..a2f32d30ca
--- /dev/null
+++ b/apps/codecs/libgme/ym2612_emu.c
@@ -0,0 +1,1359 @@
1// Game_Music_Emu $vers. http://www.slack.net/~ant/
2
3// Based on Gens 2.10 ym2612.c
4
5#include "ym2612_emu.h"
6
7#include <assert.h>
8#include <stdlib.h>
9#include <string.h>
10#include <limits.h>
11#include <stdio.h>
12#include <math.h>
13
14/* Copyright (C) 2002 Stéphane Dallongeville (gens AT consolemul.com) */
15/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
16can redistribute it and/or modify it under the terms of the GNU Lesser
17General Public License as published by the Free Software Foundation; either
18version 2.1 of the License, or (at your option) any later version. This
19module is distributed in the hope that it will be useful, but WITHOUT ANY
20WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
22details. You should have received a copy of the GNU Lesser General Public
23License along with this module; if not, write to the Free Software Foundation,
24Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
25
26// This is mostly the original source in its C style and all.
27//
28// Somewhat optimized and simplified. Uses a template to generate the many
29// variants of Update_Chan. Rewrote header file. In need of full rewrite by
30// someone more familiar with FM sound and the YM2612. Has some inaccuracies
31// compared to the Sega Genesis sound, particularly being mixed at such a
32// high sample accuracy (the Genesis sounds like it has only 8 bit samples).
33// - Shay
34
35// Ported again to c by gama.
36// Not sure if performance is better than the original c version.
37
38#if !defined(ROCKBOX)
39 #define YM2612_CALCUL_TABLES
40#else
41 #include "ymtables.h"
42#endif
43
44const int output_bits = 14;
45
46static const unsigned char DT_DEF_TAB [4 * 32] ICONST_ATTR =
47{
48// FD = 0
49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51
52// FD = 1
53 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
54 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,
55
56// FD = 2
57 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
58 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 16, 16, 16, 16,
59
60// FD = 3
61 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
62 8 , 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 20, 22, 22, 22, 22
63};
64
65static const unsigned char FKEY_TAB [16] ICONST_ATTR =
66{
67 0, 0, 0, 0,
68 0, 0, 0, 1,
69 2, 3, 3, 3,
70 3, 3, 3, 3
71};
72
73static const unsigned char LFO_AMS_TAB [4] ICONST_ATTR =
74{
75 31, 4, 1, 0
76};
77
78static const unsigned char LFO_FMS_TAB [8] ICONST_ATTR =
79{
80 LFO_FMS_BASE * 0, LFO_FMS_BASE * 1,
81 LFO_FMS_BASE * 2, LFO_FMS_BASE * 3,
82 LFO_FMS_BASE * 4, LFO_FMS_BASE * 6,
83 LFO_FMS_BASE * 12, LFO_FMS_BASE * 24
84};
85
86int in0, in1, in2, in3; // current phase calculation
87// int en0, en1, en2, en3; // current enveloppe calculation
88
89inline void set_seg( struct slot_t* s, int seg )
90{
91 s->env_xor = 0;
92 s->env_max = INT_MAX;
93 s->SEG = seg;
94 if ( seg & 4 )
95 {
96 s->env_xor = ENV_MASK;
97 s->env_max = ENV_MASK;
98 }
99}
100
101inline void YM2612_Special_Update(void) { }
102
103void KEY_ON( struct channel_* ch, struct tables_t *g, int nsl )
104{
105 struct slot_t *SL = &(ch->SLOT [nsl]); // on recupere le bon pointeur de slot
106
107 if (SL->Ecurp == RELEASE) // la touche est-elle rel'chee ?
108 {
109 SL->Fcnt = 0;
110
111 // Fix Ecco 2 splash sound
112
113 SL->Ecnt = (g->DECAY_TO_ATTACK [g->ENV_TAB [SL->Ecnt >> ENV_LBITS]] + ENV_ATTACK) & SL->ChgEnM;
114 SL->ChgEnM = ~0;
115
116// SL->Ecnt = g.DECAY_TO_ATTACK [g.ENV_TAB [SL->Ecnt >> ENV_LBITS]] + ENV_ATTACK;
117// SL->Ecnt = 0;
118
119 SL->Einc = SL->EincA;
120 SL->Ecmp = ENV_DECAY;
121 SL->Ecurp = ATTACK;
122 }
123}
124
125
126void KEY_OFF( struct channel_* ch, struct tables_t *g, int nsl )
127{
128 struct slot_t *SL = &(ch->SLOT [nsl]); // on recupere le bon pointeur de slot
129
130 if (SL->Ecurp != RELEASE) // la touche est-elle appuyee ?
131 {
132 if (SL->Ecnt < ENV_DECAY) // attack phase ?
133 {
134 SL->Ecnt = (g->ENV_TAB [SL->Ecnt >> ENV_LBITS] << ENV_LBITS) + ENV_DECAY;
135 }
136
137 SL->Einc = SL->EincR;
138 SL->Ecmp = ENV_END;
139 SL->Ecurp = RELEASE;
140 }
141}
142
143
144int SLOT_SET( struct Ym2612_Impl* impl, int Adr, int data )
145{
146 int nch = Adr & 3;
147 if ( nch == 3 )
148 return 1;
149
150 struct tables_t *g = &impl->g;
151 struct state_t *YM2612 = &impl->YM2612;
152 struct channel_* ch = &YM2612->CHANNEL [nch + (Adr & 0x100 ? 3 : 0)];
153 struct slot_t* sl = &ch->SLOT [(Adr >> 2) & 3];
154
155 switch ( Adr & 0xF0 )
156 {
157 case 0x30:
158 if ( (sl->MUL = (data & 0x0F)) != 0 ) sl->MUL <<= 1;
159 else sl->MUL = 1;
160
161 sl->DT = (int*) g->DT_TAB [(data >> 4) & 7];
162
163 ch->SLOT [0].Finc = -1;
164
165 break;
166
167 case 0x40:
168 sl->TL = data & 0x7F;
169
170 // SOR2 do a lot of TL adjustement and this fix R.Shinobi jump sound...
171 YM2612_Special_Update();
172
173#if ((ENV_HBITS - 7) < 0)
174 sl->TLL = sl->TL >> (7 - ENV_HBITS);
175#else
176 sl->TLL = sl->TL << (ENV_HBITS - 7);
177#endif
178
179 break;
180
181 case 0x50:
182 sl->KSR_S = 3 - (data >> 6);
183
184 ch->SLOT [0].Finc = -1;
185
186 if (data &= 0x1F) sl->AR = (int*) &g->AR_TAB [data << 1];
187 else sl->AR = (int*) &g->NULL_RATE [0];
188
189 sl->EincA = sl->AR [sl->KSR];
190 if (sl->Ecurp == ATTACK) sl->Einc = sl->EincA;
191 break;
192
193 case 0x60:
194 if ( (sl->AMSon = (data & 0x80)) != 0 ) sl->AMS = ch->AMS;
195 else sl->AMS = 31;
196
197 if (data &= 0x1F) sl->DR = (int*) &g->DR_TAB [data << 1];
198 else sl->DR = (int*) &g->NULL_RATE [0];
199
200 sl->EincD = sl->DR [sl->KSR];
201 if (sl->Ecurp == DECAY) sl->Einc = sl->EincD;
202 break;
203
204 case 0x70:
205 if (data &= 0x1F) sl->SR = (int*) &g->DR_TAB [data << 1];
206 else sl->SR = (int*) &g->NULL_RATE [0];
207
208 sl->EincS = sl->SR [sl->KSR];
209 if ((sl->Ecurp == SUBSTAIN) && (sl->Ecnt < ENV_END)) sl->Einc = sl->EincS;
210 break;
211
212 case 0x80:
213 sl->SLL = g->SL_TAB [data >> 4];
214
215 sl->RR = (int*) &g->DR_TAB [((data & 0xF) << 2) + 2];
216
217 sl->EincR = sl->RR [sl->KSR];
218 if ((sl->Ecurp == RELEASE) && (sl->Ecnt < ENV_END)) sl->Einc = sl->EincR;
219 break;
220
221 case 0x90:
222 // SSG-EG envelope shapes :
223 /*
224 E At Al H
225
226 1 0 0 0 \\\\
227 1 0 0 1 \___
228 1 0 1 0 \/\/
229 1 0 1 1 \
230 1 1 0 0 ////
231 1 1 0 1 /
232 1 1 1 0 /\/\
233 1 1 1 1 /___
234
235 E = SSG-EG enable
236 At = Start negate
237 Al = Altern
238 H = Hold */
239
240 set_seg( sl, (data & 8) ? (data & 0x0F) : 0 );
241 break;
242 }
243
244 return 0;
245}
246
247
248int CHANNEL_SET( struct state_t* YM2612, int Adr, int data )
249{
250 int num = Adr & 3;
251 if ( num == 3 )
252 return 1;
253
254 struct channel_* ch = &YM2612->CHANNEL [num + (Adr & 0x100 ? 3 : 0)];
255
256 switch ( Adr & 0xFC )
257 {
258 case 0xA0:
259 YM2612_Special_Update();
260
261 ch->FNUM [0] = (ch->FNUM [0] & 0x700) + data;
262 ch->KC [0] = (ch->FOCT [0] << 2) | FKEY_TAB [ch->FNUM [0] >> 7];
263
264 ch->SLOT [0].Finc = -1;
265 break;
266
267 case 0xA4:
268 YM2612_Special_Update();
269
270 ch->FNUM [0] = (ch->FNUM [0] & 0x0FF) + ((data & 0x07) << 8);
271 ch->FOCT [0] = (data & 0x38) >> 3;
272 ch->KC [0] = (ch->FOCT [0] << 2) | FKEY_TAB [ch->FNUM [0] >> 7];
273
274 ch->SLOT [0].Finc = -1;
275 break;
276
277 case 0xA8:
278 if ( Adr < 0x100 )
279 {
280 num++;
281
282 YM2612_Special_Update();
283
284 YM2612->CHANNEL [2].FNUM [num] = (YM2612->CHANNEL [2].FNUM [num] & 0x700) + data;
285 YM2612->CHANNEL [2].KC [num] = (YM2612->CHANNEL [2].FOCT [num] << 2) |
286 FKEY_TAB [YM2612->CHANNEL [2].FNUM [num] >> 7];
287
288 YM2612->CHANNEL [2].SLOT [0].Finc = -1;
289 }
290 break;
291
292 case 0xAC:
293 if ( Adr < 0x100 )
294 {
295 num++;
296
297 YM2612_Special_Update();
298
299 YM2612->CHANNEL [2].FNUM [num] = (YM2612->CHANNEL [2].FNUM [num] & 0x0FF) + ((data & 0x07) << 8);
300 YM2612->CHANNEL [2].FOCT [num] = (data & 0x38) >> 3;
301 YM2612->CHANNEL [2].KC [num] = (YM2612->CHANNEL [2].FOCT [num] << 2) |
302 FKEY_TAB [YM2612->CHANNEL [2].FNUM [num] >> 7];
303
304 YM2612->CHANNEL [2].SLOT [0].Finc = -1;
305 }
306 break;
307
308 case 0xB0:
309 if ( ch->ALGO != (data & 7) )
310 {
311 // Fix VectorMan 2 heli sound (level 1)
312 YM2612_Special_Update();
313
314 ch->ALGO = data & 7;
315
316 ch->SLOT [0].ChgEnM = 0;
317 ch->SLOT [1].ChgEnM = 0;
318 ch->SLOT [2].ChgEnM = 0;
319 ch->SLOT [3].ChgEnM = 0;
320 }
321
322 ch->FB = 9 - ((data >> 3) & 7); // Real thing ?
323
324// if (ch->FB = ((data >> 3) & 7)) ch->FB = 9 - ch->FB; // Thunder force 4 (music stage 8), Gynoug, Aladdin bug sound...
325// else ch->FB = 31;
326 break;
327
328 case 0xB4: {
329 YM2612_Special_Update();
330
331 ch->LEFT = 0 - ((data >> 7) & 1);
332 ch->RIGHT = 0 - ((data >> 6) & 1);
333
334 ch->AMS = LFO_AMS_TAB [(data >> 4) & 3];
335 ch->FMS = LFO_FMS_TAB [data & 7];
336
337 int i;
338 for ( i = 0; i < 4; i++ )
339 {
340 struct slot_t* sl = &ch->SLOT [i];
341 sl->AMS = (sl->AMSon ? ch->AMS : 31);
342 }
343 break;
344 }
345 }
346
347 return 0;
348}
349
350
351int YM_SET( struct Ym2612_Impl* impl, int Adr, int data )
352{
353 struct state_t* YM2612 = &impl->YM2612;
354 struct tables_t* g = &impl->g;
355 switch ( Adr )
356 {
357 case 0x22:
358 if (data & 8) // LFO enable
359 {
360 // Cool Spot music 1, LFO modified severals time which
361 // distord the sound, have to check that on a real genesis...
362
363 g->LFOinc = g->LFO_INC_TAB [data & 7];
364 }
365 else
366 {
367 g->LFOinc = g->LFOcnt = 0;
368 }
369 break;
370
371 case 0x24:
372 YM2612->TimerA = (YM2612->TimerA & 0x003) | (((int) data) << 2);
373
374 if (YM2612->TimerAL != (1024 - YM2612->TimerA) << 12)
375 {
376 YM2612->TimerAcnt = YM2612->TimerAL = (1024 - YM2612->TimerA) << 12;
377 }
378 break;
379
380 case 0x25:
381 YM2612->TimerA = (YM2612->TimerA & 0x3FC) | (data & 3);
382
383 if (YM2612->TimerAL != (1024 - YM2612->TimerA) << 12)
384 {
385 YM2612->TimerAcnt = YM2612->TimerAL = (1024 - YM2612->TimerA) << 12;
386 }
387 break;
388
389 case 0x26:
390 YM2612->TimerB = data;
391
392 if (YM2612->TimerBL != (256 - YM2612->TimerB) << (4 + 12))
393 {
394 YM2612->TimerBcnt = YM2612->TimerBL = (256 - YM2612->TimerB) << (4 + 12);
395 }
396 break;
397
398 case 0x27:
399 // Parametre divers
400 // b7 = CSM MODE
401 // b6 = 3 slot mode
402 // b5 = reset b
403 // b4 = reset a
404 // b3 = timer enable b
405 // b2 = timer enable a
406 // b1 = load b
407 // b0 = load a
408
409 if ((data ^ YM2612->Mode) & 0x40)
410 {
411 // We changed the channel 2 mode, so recalculate phase step
412 // This fix the punch sound in Street of Rage 2
413
414 YM2612_Special_Update();
415
416 YM2612->CHANNEL [2].SLOT [0].Finc = -1; // recalculate phase step
417 }
418
419// if ((data & 2) && (YM2612->Status & 2)) YM2612->TimerBcnt = YM2612->TimerBL;
420// if ((data & 1) && (YM2612->Status & 1)) YM2612->TimerAcnt = YM2612->TimerAL;
421
422// YM2612->Status &= (~data >> 4); // Reset du Status au cas ou c'est demande
423 YM2612->Status &= (~data >> 4) & (data >> 2); // Reset Status
424
425 YM2612->Mode = data;
426 break;
427
428 case 0x28: {
429 int nch = data & 3;
430 if ( nch == 3 )
431 return 1;
432 if ( data & 4 )
433 nch += 3;
434 struct channel_* ch = &YM2612->CHANNEL [nch];
435
436 YM2612_Special_Update();
437
438 if (data & 0x10) KEY_ON(ch, g, S0); // On appuie sur la touche pour le slot 1
439 else KEY_OFF(ch, g, S0); // On rel'che la touche pour le slot 1
440 if (data & 0x20) KEY_ON(ch, g, S1); // On appuie sur la touche pour le slot 3
441 else KEY_OFF(ch, g, S1); // On rel'che la touche pour le slot 3
442 if (data & 0x40) KEY_ON(ch, g, S2); // On appuie sur la touche pour le slot 2
443 else KEY_OFF(ch, g, S2); // On rel'che la touche pour le slot 2
444 if (data & 0x80) KEY_ON(ch, g, S3); // On appuie sur la touche pour le slot 4
445 else KEY_OFF(ch, g, S3); // On rel'che la touche pour le slot 4
446 break;
447 }
448
449 case 0x2B:
450 if (YM2612->DAC ^ (data & 0x80)) YM2612_Special_Update();
451
452 YM2612->DAC = data & 0x80; // activation/desactivation du DAC
453 break;
454 }
455
456 return 0;
457}
458
459#if defined(ROCKBOX)
460double fabs(double x)
461{
462 if (x < 0.0) return -x;
463 return x;
464}
465
466double ipow(double a,int b)
467{
468 if (b < 0) {
469 a = 1.0 / a;
470 b = -b;
471 }
472 double result = 1.0;
473 while(b) {
474 if (b & 1) result*=a;
475 a *= a;
476 b >>= 1;
477 }
478 return result;
479}
480#endif
481
482void impl_reset( struct Ym2612_Impl* impl );
483void impl_set_rate( struct Ym2612_Impl* impl, double sample_rate, double clock_rate )
484{
485 assert( sample_rate );
486 assert( !clock_rate || clock_rate > sample_rate );
487
488 int i;
489
490 // 144 = 12 * (prescale * 2) = 12 * 6 * 2
491 // prescale set to 6 by default
492
493 double Frequence = (clock_rate ? clock_rate / sample_rate / 144.0 : 1.0);
494 if ( fabs( Frequence - 1.0 ) < 0.0000001 )
495 Frequence = 1.0;
496 impl->YM2612.TimerBase = (int) (Frequence * 4096.0);
497
498 // Tableau TL :
499 // [0 - 4095] = +output [4095 - ...] = +output overflow (fill with 0)
500 // [12288 - 16383] = -output [16384 - ...] = -output overflow (fill with 0)
501
502 for ( i = 0; i < TL_LENGHT; i++ )
503 {
504 if (i >= PG_CUT_OFF) // YM2612 cut off sound after 78 dB (14 bits output ?)
505 {
506 impl->g.TL_TAB [TL_LENGHT + i] = impl->g.TL_TAB [i] = 0;
507 }
508 else
509 {
510 // Decibel -> Voltage
511 #ifdef YM2612_CALCUL_TABLES
512 impl->g.TL_TAB [i] = (int) (MAX_OUT / pow( 10.0, ENV_STEP / 20.0f * i ));
513 #else
514 impl->g.TL_TAB [i] = tl_coeff [i];
515 #endif
516 impl->g.TL_TAB [TL_LENGHT + i] = -impl->g.TL_TAB [i];
517 }
518 }
519
520 // Tableau SIN :
521 // impl->g.SIN_TAB [x] [y] = sin(x) * y;
522 // x = phase and y = volume
523
524 impl->g.SIN_TAB [0] = impl->g.SIN_TAB [SIN_LENGHT / 2] = PG_CUT_OFF;
525
526 for ( i = 1; i <= SIN_LENGHT / 4; i++ )
527 {
528 // Sinus in dB
529 #ifdef YM2612_CALCUL_TABLES
530 double x = 20 * log10( 1 / sin( 2.0 * PI * i / SIN_LENGHT ) ); // convert to dB
531
532 int j = (int) (x / ENV_STEP); // Get TL range
533
534 if (j > PG_CUT_OFF) j = (int) PG_CUT_OFF;
535 #else
536 int j = sindb_coeff [i-1];
537 #endif
538
539 impl->g.SIN_TAB [i] = impl->g.SIN_TAB [(SIN_LENGHT / 2) - i] = j;
540 impl->g.SIN_TAB [(SIN_LENGHT / 2) + i] = impl->g.SIN_TAB [SIN_LENGHT - i] = TL_LENGHT + j;
541 }
542
543 // Tableau LFO (LFO wav) :
544
545 for ( i = 0; i < LFO_LENGHT; i++ )
546 {
547 #ifdef YM2612_CALCUL_TABLES
548 double x = 1 + sin( 2.0 * PI * i * (1.0 / LFO_LENGHT) ); // Sinus
549 x *= 11.8 / ENV_STEP / 2; // ajusted to MAX enveloppe modulation
550
551 impl->g.LFO_ENV_TAB [i] = (int) x;
552
553 x = sin( 2.0 * PI * i * (1.0 / LFO_LENGHT) ); // Sinus
554 x *= (1 << (LFO_HBITS - 1)) - 1;
555
556 impl->g.LFO_FREQ_TAB [i] = (int) x;
557 #else
558 impl->g.LFO_ENV_TAB [i] = lfo_env_coeff [i];
559 impl->g.LFO_FREQ_TAB [i] = lfo_freq_coeff [i];
560 #endif
561 }
562
563 // Tableau Enveloppe :
564 // impl->g.ENV_TAB [0] -> impl->g.ENV_TAB [ENV_LENGHT - 1] = attack curve
565 // impl->g.ENV_TAB [ENV_LENGHT] -> impl->g.ENV_TAB [2 * ENV_LENGHT - 1] = decay curve
566
567 for ( i = 0; i < ENV_LENGHT; i++ )
568 {
569 // Attack curve (x^8 - music level 2 Vectorman 2)
570 #if defined(ROCKBOX)
571 double x = ipow( ((ENV_LENGHT - 1) - i) / (double) ENV_LENGHT, 8.0 );
572 #else
573 double x = pow( ((ENV_LENGHT - 1) - i) / (double) ENV_LENGHT, 8.0 );
574 #endif
575 x *= ENV_LENGHT;
576
577 impl->g.ENV_TAB [i] = (int) x;
578
579 // Decay curve (just linear)
580 impl->g.ENV_TAB [ENV_LENGHT + i] = i;
581 }
582 for ( i = 0; i < 8; i++ )
583 impl->g.ENV_TAB [i + ENV_LENGHT * 2] = 0;
584
585 impl->g.ENV_TAB [ENV_END >> ENV_LBITS] = ENV_LENGHT - 1; // for the stopped state
586
587 // Tableau pour la conversion Attack -> Decay and Decay -> Attack
588
589 int j = ENV_LENGHT - 1;
590 for ( i = 0; i < ENV_LENGHT; i++ )
591 {
592 while ( j && impl->g.ENV_TAB [j] < i )
593 j--;
594
595 impl->g.DECAY_TO_ATTACK [i] = j << ENV_LBITS;
596 }
597
598 // Tableau pour le Substain Level
599
600 for ( i = 0; i < 15; i++ )
601 {
602 double x = i * 3 / ENV_STEP; // 3 and not 6 (Mickey Mania first music for test)
603
604 impl->g.SL_TAB [i] = ((int) x << ENV_LBITS) + ENV_DECAY;
605 }
606
607 impl->g.SL_TAB [15] = ((ENV_LENGHT - 1) << ENV_LBITS) + ENV_DECAY; // special case : volume off
608
609 // Tableau Frequency Step
610 {
611 // 0.5 because MUL = value * 2
612 #if SIN_LBITS + SIN_HBITS - (21 - 7) < 0
613 double const factor = 0.5 / (1 << ((21 - 7) - SIN_LBITS - SIN_HBITS)) * Frequence;
614 #else
615 double const factor = 0.5 * (1 << (SIN_LBITS + SIN_HBITS - (21 - 7))) * Frequence;
616 #endif
617 for ( i = 0; i < 2048; i++ )
618 impl->g.FINC_TAB [i] = (unsigned) (i * factor);
619 }
620
621 // Tableaux Attack & Decay Rate
622
623 for ( i = 0; i < 4; i++ )
624 {
625 impl->g.AR_TAB [i] = 0;
626 impl->g.DR_TAB [i] = 0;
627 }
628
629 for ( i = 0; i < 60; i++ )
630 {
631 double x =
632 (1.0 + ((i & 3) * 0.25)) * // bits 0-1 : x1.00, x1.25, x1.50, x1.75
633 (ENV_LENGHT << ENV_LBITS) * // on ajuste pour le tableau impl->g.ENV_TAB
634 Frequence *
635 (1 << (i >> 2)); // bits 2-5 : shift bits (x2^0 - x2^15)
636
637 impl->g.AR_TAB [i + 4] = (unsigned int) (x / AR_RATE);
638 impl->g.DR_TAB [i + 4] = (unsigned int) (x / DR_RATE);
639 }
640
641 for ( i = 64; i < 96; i++ )
642 {
643 impl->g.AR_TAB [i] = impl->g.AR_TAB [63];
644 impl->g.DR_TAB [i] = impl->g.DR_TAB [63];
645
646 impl->g.NULL_RATE [i - 64] = 0;
647 }
648
649 for ( i = 96; i < 128; i++ )
650 impl->g.AR_TAB [i] = 0;
651
652 // Tableau Detune
653 {
654 #if SIN_LBITS + SIN_HBITS - 21 < 0
655 double const factor = 1.0 / (1 << (21 - SIN_LBITS - SIN_HBITS)) * Frequence;
656 #else
657 double const factor = (1 << (SIN_LBITS + SIN_HBITS - 21)) * Frequence;
658 #endif
659 for ( i = 0; i < 4; i++ )
660 {
661 int j;
662 for ( j = 0; j < 32; j++ )
663 {
664 double y = DT_DEF_TAB [(i << 5) + j] * factor;
665
666 impl->g.DT_TAB [i + 0] [j] = (int) y;
667 impl->g.DT_TAB [i + 4] [j] = (int) -y;
668 }
669 }
670 }
671
672 // Tableau LFO
673 impl->g.LFO_INC_TAB [0] = (unsigned) (3.98 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
674 impl->g.LFO_INC_TAB [1] = (unsigned) (5.56 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
675 impl->g.LFO_INC_TAB [2] = (unsigned) (6.02 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
676 impl->g.LFO_INC_TAB [3] = (unsigned) (6.37 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
677 impl->g.LFO_INC_TAB [4] = (unsigned) (6.88 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
678 impl->g.LFO_INC_TAB [5] = (unsigned) (9.63 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
679 impl->g.LFO_INC_TAB [6] = (unsigned) (48.1 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
680 impl->g.LFO_INC_TAB [7] = (unsigned) (72.2 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
681
682 impl_reset( impl );
683}
684
685const char* Ym2612_set_rate( struct Ym2612_Emu* this, double sample_rate, double clock_rate )
686{
687// Only set rates if necessary
688#if defined(ROCKBOX)
689 static double last_sample_rate = 0.0, last_clock_rate = 0.0;
690 if (last_sample_rate == sample_rate && last_clock_rate == clock_rate) return 0;
691#endif
692 memset( &this->impl.YM2612, 0, sizeof this->impl.YM2612 );
693 impl_set_rate( &this->impl, sample_rate, clock_rate );
694
695 return 0;
696}
697
698inline void write0( struct Ym2612_Impl* impl, int opn_addr, int data )
699{
700 assert( (unsigned) data <= 0xFF );
701
702 if ( opn_addr < 0x30 )
703 {
704 impl->YM2612.REG [0] [opn_addr] = data;
705 YM_SET( impl, opn_addr, data );
706 }
707 else if ( impl->YM2612.REG [0] [opn_addr] != data )
708 {
709 impl->YM2612.REG [0] [opn_addr] = data;
710
711 if ( opn_addr < 0xA0 )
712 SLOT_SET( impl, opn_addr, data );
713 else
714 CHANNEL_SET( &impl->YM2612, opn_addr, data );
715 }
716}
717
718inline void write1( struct Ym2612_Impl* impl, int opn_addr, int data )
719{
720 assert( (unsigned) data <= 0xFF );
721
722 if ( opn_addr >= 0x30 && impl->YM2612.REG [1] [opn_addr] != data )
723 {
724 impl->YM2612.REG [1] [opn_addr] = data;
725
726 if ( opn_addr < 0xA0 )
727 SLOT_SET( impl, opn_addr + 0x100, data );
728 else
729 CHANNEL_SET( &impl->YM2612, opn_addr + 0x100, data );
730 }
731}
732
733void impl_reset( struct Ym2612_Impl* impl )
734{
735 impl->g.LFOcnt = 0;
736 impl->YM2612.TimerA = 0;
737 impl->YM2612.TimerAL = 0;
738 impl->YM2612.TimerAcnt = 0;
739 impl->YM2612.TimerB = 0;
740 impl->YM2612.TimerBL = 0;
741 impl->YM2612.TimerBcnt = 0;
742 impl->YM2612.DAC = 0;
743
744 impl->YM2612.Status = 0;
745
746 int i;
747 for ( i = 0; i < ym2612_channel_count; i++ )
748 {
749 struct channel_* ch = &impl->YM2612.CHANNEL [i];
750
751 ch->LEFT = ~0;
752 ch->RIGHT = ~0;
753 ch->ALGO = 0;
754 ch->FB = 31;
755 ch->FMS = 0;
756 ch->AMS = 0;
757
758 int j;
759 for ( j = 0 ;j < 4 ; j++ )
760 {
761 ch->S0_OUT [j] = 0;
762 ch->FNUM [j] = 0;
763 ch->FOCT [j] = 0;
764 ch->KC [j] = 0;
765
766 ch->SLOT [j].Fcnt = 0;
767 ch->SLOT [j].Finc = 0;
768 ch->SLOT [j].Ecnt = ENV_END; // Put it at the end of Decay phase...
769 ch->SLOT [j].Einc = 0;
770 ch->SLOT [j].Ecmp = 0;
771 ch->SLOT [j].Ecurp = RELEASE;
772
773 ch->SLOT [j].ChgEnM = 0;
774 }
775 }
776
777 for ( i = 0; i < 0x100; i++ )
778 {
779 impl->YM2612.REG [0] [i] = -1;
780 impl->YM2612.REG [1] [i] = -1;
781 }
782
783 for ( i = 0xB6; i >= 0xB4; i-- )
784 {
785 write0( impl, i, 0xC0 );
786 write1( impl, i, 0xC0 );
787 }
788
789 for ( i = 0xB2; i >= 0x22; i-- )
790 {
791 write0( impl, i, 0 );
792 write1( impl, i, 0 );
793 }
794
795 write0( impl, 0x2A, 0x80 );
796}
797
798void Ym2612_reset( struct Ym2612_Emu* this )
799{
800 impl_reset( &this->impl );
801}
802
803void Ym2612_write0( struct Ym2612_Emu* this, int addr, int data )
804{
805 write0( &this->impl, addr, data );
806}
807
808void Ym2612_write1( struct Ym2612_Emu* this, int addr, int data )
809{
810 write1( &this->impl, addr, data );
811}
812
813void Ym2612_mute_voices( struct Ym2612_Emu* this, int mask ) { this->impl.mute_mask = mask; }
814
815static void update_envelope_( struct slot_t* sl )
816{
817 switch ( sl->Ecurp )
818 {
819 case 0:
820 // Env_Attack_Next
821
822 // Verified with Gynoug even in HQ (explode SFX)
823 sl->Ecnt = ENV_DECAY;
824
825 sl->Einc = sl->EincD;
826 sl->Ecmp = sl->SLL;
827 sl->Ecurp = DECAY;
828 break;
829
830 case 1:
831 // Env_Decay_Next
832
833 // Verified with Gynoug even in HQ (explode SFX)
834 sl->Ecnt = sl->SLL;
835
836 sl->Einc = sl->EincS;
837 sl->Ecmp = ENV_END;
838 sl->Ecurp = SUBSTAIN;
839 break;
840
841 case 2:
842 // Env_Substain_Next(slot_t *SL)
843 if (sl->SEG & 8) // SSG envelope type
844 {
845 int release = sl->SEG & 1;
846
847 if ( !release )
848 {
849 // re KEY ON
850
851 // sl->Fcnt = 0;
852 // sl->ChgEnM = ~0;
853
854 sl->Ecnt = 0;
855 sl->Einc = sl->EincA;
856 sl->Ecmp = ENV_DECAY;
857 sl->Ecurp = ATTACK;
858 }
859
860 set_seg( sl, (sl->SEG << 1) & 4 );
861
862 if ( !release )
863 break;
864 }
865 // fall through
866
867 case 3:
868 // Env_Release_Next
869 sl->Ecnt = ENV_END;
870 sl->Einc = 0;
871 sl->Ecmp = ENV_END + 1;
872 break;
873
874 // default: no op
875 }
876}
877
878static inline void update_envelope( struct slot_t* sl )
879{
880 int ecmp = sl->Ecmp;
881 if ( (sl->Ecnt += sl->Einc) >= ecmp )
882 update_envelope_( sl );
883}
884
885
886typedef void (*ym2612_update_chan_t)( struct tables_t*, struct channel_*, short*, int );
887
888#define GET_CURRENT_PHASE \
889int in0 = ch->SLOT[S0].Fcnt; \
890int in1 = ch->SLOT[S1].Fcnt; \
891int in2 = ch->SLOT[S2].Fcnt; \
892int in3 = ch->SLOT[S3].Fcnt; \
893
894#define GET_CURRENT_LFO \
895int YM2612_LFOinc = g->LFOinc; \
896int YM2612_LFOcnt = g->LFOcnt + YM2612_LFOinc;
897
898#define CALC_EN( x ) \
899 int temp##x = ENV_TAB [ch->SLOT [S##x].Ecnt >> ENV_LBITS] + ch->SLOT [S##x].TLL; \
900 int en##x = ((temp##x ^ ch->SLOT [S##x].env_xor) + (env_LFO >> ch->SLOT [S##x].AMS)) & \
901 ((temp##x - ch->SLOT [S##x].env_max) >> 31);
902
903#define GET_ENV \
904int const env_LFO = g->LFO_ENV_TAB [YM2612_LFOcnt >> LFO_LBITS & LFO_MASK]; \
905short const* const ENV_TAB = g->ENV_TAB; \
906CALC_EN( 0 ) \
907CALC_EN( 1 ) \
908CALC_EN( 2 ) \
909CALC_EN( 3 ) \
910int const* const TL_TAB = g->TL_TAB;
911
912#define DO_FEEDBACK \
913int CH_S0_OUT_0 = ch->S0_OUT [0]; \
914{ \
915 int temp = in0 + ((CH_S0_OUT_0 + CH_S0_OUT_1) >> ch->FB); \
916 CH_S0_OUT_1 = CH_S0_OUT_0; \
917 CH_S0_OUT_0 = SINT( (temp >> SIN_LBITS) & SIN_MASK, en0 ); \
918} \
919
920#define SINT( i, o ) (TL_TAB [g->SIN_TAB [(i)] + (o)])
921
922#define DO_LIMIT \
923CH_OUTd >>= MAX_OUT_BITS - output_bits + 2; \
924
925#define UPDATE_PHASE_CYCLE \
926unsigned freq_LFO = ((g->LFO_FREQ_TAB [YM2612_LFOcnt >> LFO_LBITS & LFO_MASK] * \
927 ch->FMS) >> (LFO_HBITS - 1 + 1)) + (1 << (LFO_FMS_LBITS - 1)); \
928YM2612_LFOcnt += YM2612_LFOinc; \
929in0 += (ch->SLOT [S0].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); \
930in1 += (ch->SLOT [S1].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); \
931in2 += (ch->SLOT [S2].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); \
932in3 += (ch->SLOT [S3].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1);
933
934#define UPDATE_ENV \
935int t0 = buf [0] + (CH_OUTd & ch->LEFT); \
936int t1 = buf [1] + (CH_OUTd & ch->RIGHT); \
937update_envelope( &ch->SLOT [0] ); \
938update_envelope( &ch->SLOT [1] ); \
939update_envelope( &ch->SLOT [2] ); \
940update_envelope( &ch->SLOT [3] );
941
942#define DO_OUTPUT_0 \
943ch->S0_OUT [0] = CH_S0_OUT_0; \
944buf [0] = t0; \
945buf [1] = t1; \
946buf += 2; \
947
948#define DO_OUTPUT_1 \
949ch->S0_OUT [1] = CH_S0_OUT_1;
950
951#define UPDATE_PHASE \
952ch->SLOT [S0].Fcnt = in0; \
953ch->SLOT [S1].Fcnt = in1; \
954ch->SLOT [S2].Fcnt = in2; \
955ch->SLOT [S3].Fcnt = in3;
956
957void ym2612_update_chan0( struct tables_t* g, struct channel_* ch,
958 short* buf, int length )
959{
960 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
961 int CH_S0_OUT_1 = ch->S0_OUT [1];
962
963 GET_CURRENT_PHASE
964 GET_CURRENT_LFO
965
966 if ( !not_end )
967 return;
968
969 do
970 {
971 GET_ENV
972 DO_FEEDBACK
973
974 int CH_OUTd;
975 int temp = in1 + CH_S0_OUT_1;
976 temp = in2 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en1 );
977 temp = in3 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en2 );
978 CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 );
979
980 DO_LIMIT
981 UPDATE_PHASE_CYCLE
982 UPDATE_ENV
983 DO_OUTPUT_0
984 }
985 while ( --length );
986 DO_OUTPUT_1
987 UPDATE_PHASE
988}
989
990void ym2612_update_chan1( struct tables_t* g, struct channel_* ch,
991 short* buf, int length )
992{
993 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
994 int CH_S0_OUT_1 = ch->S0_OUT [1];
995
996 GET_CURRENT_PHASE
997 GET_CURRENT_LFO
998
999 if ( !not_end )
1000 return;
1001
1002 do
1003 {
1004 GET_ENV
1005 DO_FEEDBACK
1006
1007 int CH_OUTd;
1008 int temp = in2 + CH_S0_OUT_1 + SINT( (in1 >> SIN_LBITS) & SIN_MASK, en1 );
1009 temp = in3 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en2 );
1010 CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 );
1011
1012 DO_LIMIT
1013 UPDATE_PHASE_CYCLE
1014 UPDATE_ENV
1015 DO_OUTPUT_0
1016 }
1017 while ( --length );
1018 DO_OUTPUT_1
1019 UPDATE_PHASE
1020}
1021
1022void ym2612_update_chan2( struct tables_t* g, struct channel_* ch,
1023 short* buf, int length )
1024{
1025 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1026 int CH_S0_OUT_1 = ch->S0_OUT [1];
1027
1028 GET_CURRENT_PHASE
1029 GET_CURRENT_LFO
1030
1031 if ( !not_end )
1032 return;
1033
1034 do
1035 {
1036 GET_ENV
1037 DO_FEEDBACK
1038
1039 int CH_OUTd;
1040 int temp = in2 + SINT( (in1 >> SIN_LBITS) & SIN_MASK, en1 );
1041 temp = in3 + CH_S0_OUT_1 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en2 );
1042 CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 );
1043
1044 DO_LIMIT
1045 UPDATE_PHASE_CYCLE
1046 UPDATE_ENV
1047 DO_OUTPUT_0
1048 }
1049 while ( --length );
1050 DO_OUTPUT_1
1051 UPDATE_PHASE
1052}
1053
1054void ym2612_update_chan3( struct tables_t* g, struct channel_* ch,
1055 short* buf, int length )
1056{
1057 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1058 int CH_S0_OUT_1 = ch->S0_OUT [1];
1059
1060 GET_CURRENT_PHASE
1061 GET_CURRENT_LFO
1062
1063 if ( !not_end )
1064 return;
1065
1066 do
1067 {
1068 GET_ENV
1069 DO_FEEDBACK
1070
1071 int CH_OUTd;
1072 int temp = in1 + CH_S0_OUT_1;
1073 temp = in3 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en1 ) +
1074 SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 );
1075 CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 );
1076
1077 DO_LIMIT
1078 UPDATE_PHASE_CYCLE
1079 UPDATE_ENV
1080 DO_OUTPUT_0
1081 }
1082 while ( --length );
1083 DO_OUTPUT_1
1084 UPDATE_PHASE
1085}
1086
1087void ym2612_update_chan4( struct tables_t* g, struct channel_* ch,
1088 short* buf, int length )
1089{
1090 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1091 not_end |= ch->SLOT [S1].Ecnt - ENV_END;
1092
1093 int CH_S0_OUT_1 = ch->S0_OUT [1];
1094
1095 GET_CURRENT_PHASE
1096 GET_CURRENT_LFO
1097
1098 if ( !not_end )
1099 return;
1100
1101 do
1102 {
1103 GET_ENV
1104 DO_FEEDBACK
1105
1106 int CH_OUTd;
1107 int temp = in3 + SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 );
1108 CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 ) +
1109 SINT( ((in1 + CH_S0_OUT_1) >> SIN_LBITS) & SIN_MASK, en1 );
1110
1111 DO_LIMIT
1112 UPDATE_PHASE_CYCLE
1113 UPDATE_ENV
1114 DO_OUTPUT_0
1115 }
1116 while ( --length );
1117 DO_OUTPUT_1
1118 UPDATE_PHASE
1119}
1120
1121void ym2612_update_chan5( struct tables_t* g, struct channel_* ch,
1122 short* buf, int length )
1123{
1124 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1125 not_end |= ch->SLOT [S2].Ecnt - ENV_END;
1126 not_end |= ch->SLOT [S1].Ecnt - ENV_END;
1127
1128 int CH_S0_OUT_1 = ch->S0_OUT [1];
1129
1130 GET_CURRENT_PHASE
1131 GET_CURRENT_LFO
1132
1133 if ( !not_end )
1134 return;
1135
1136 do
1137 {
1138 GET_ENV
1139 DO_FEEDBACK
1140
1141 int CH_OUTd;
1142 int temp = CH_S0_OUT_1;
1143 CH_OUTd = SINT( ((in3 + temp) >> SIN_LBITS) & SIN_MASK, en3 ) +
1144 SINT( ((in1 + temp) >> SIN_LBITS) & SIN_MASK, en1 ) +
1145 SINT( ((in2 + temp) >> SIN_LBITS) & SIN_MASK, en2 );
1146
1147 DO_LIMIT
1148 UPDATE_PHASE_CYCLE
1149 UPDATE_ENV
1150 DO_OUTPUT_0
1151 }
1152 while ( --length );
1153 DO_OUTPUT_1
1154 UPDATE_PHASE
1155}
1156
1157void ym2612_update_chan6( struct tables_t* g, struct channel_* ch,
1158 short* buf, int length )
1159{
1160 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1161 not_end |= ch->SLOT [S2].Ecnt - ENV_END;
1162 not_end |= ch->SLOT [S1].Ecnt - ENV_END;
1163
1164 int CH_S0_OUT_1 = ch->S0_OUT [1];
1165
1166 GET_CURRENT_PHASE
1167 GET_CURRENT_LFO
1168
1169 if ( !not_end )
1170 return;
1171
1172 do
1173 {
1174 GET_ENV
1175 DO_FEEDBACK
1176
1177 int CH_OUTd;
1178 CH_OUTd = SINT( (in3 >> SIN_LBITS) & SIN_MASK, en3 ) +
1179 SINT( ((in1 + CH_S0_OUT_1) >> SIN_LBITS) & SIN_MASK, en1 ) +
1180 SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 );
1181
1182 DO_LIMIT
1183 UPDATE_PHASE_CYCLE
1184 UPDATE_ENV
1185 DO_OUTPUT_0
1186 }
1187 while ( --length );
1188 DO_OUTPUT_1
1189 UPDATE_PHASE
1190}
1191
1192void ym2612_update_chan7( struct tables_t* g, struct channel_* ch,
1193 short* buf, int length )
1194{
1195 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1196 not_end |= ch->SLOT [S0].Ecnt - ENV_END;
1197 not_end |= ch->SLOT [S2].Ecnt - ENV_END;
1198 not_end |= ch->SLOT [S1].Ecnt - ENV_END;
1199
1200 int CH_S0_OUT_1 = ch->S0_OUT [1];
1201
1202 GET_CURRENT_PHASE
1203 GET_CURRENT_LFO
1204
1205 if ( !not_end )
1206 return;
1207
1208 do
1209 {
1210 GET_ENV
1211 DO_FEEDBACK
1212
1213 int CH_OUTd;
1214 CH_OUTd = SINT( (in3 >> SIN_LBITS) & SIN_MASK, en3 ) +
1215 SINT( (in1 >> SIN_LBITS) & SIN_MASK, en1 ) +
1216 SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 ) + CH_S0_OUT_1;
1217
1218 DO_LIMIT
1219 UPDATE_PHASE_CYCLE
1220 UPDATE_ENV
1221 DO_OUTPUT_0
1222 }
1223 while ( --length );
1224 DO_OUTPUT_1
1225 UPDATE_PHASE
1226}
1227
1228static void (*UPDATE_CHAN[8])(struct tables_t* g, struct channel_* ch,
1229 short* buf, int length) =
1230{
1231 (void *)ym2612_update_chan0,
1232 (void *)ym2612_update_chan1,
1233 (void *)ym2612_update_chan2,
1234 (void *)ym2612_update_chan3,
1235 (void *)ym2612_update_chan4,
1236 (void *)ym2612_update_chan5,
1237 (void *)ym2612_update_chan6,
1238 (void *)ym2612_update_chan7
1239};
1240
1241void run_timer( struct Ym2612_Impl* impl, int length )
1242{
1243 int const step = 6;
1244 int remain = length;
1245 do
1246 {
1247 int n = step;
1248 if ( n > remain )
1249 n = remain;
1250 remain -= n;
1251
1252 int i = n * impl->YM2612.TimerBase;
1253 if (impl->YM2612.Mode & 1) // Timer A ON ?
1254 {
1255 // if ((impl->YM2612.TimerAcnt -= 14073) <= 0) // 13879=NTSC (old: 14475=NTSC 14586=PAL)
1256 if ((impl->YM2612.TimerAcnt -= i) <= 0)
1257 {
1258 // timer a overflow
1259
1260 impl->YM2612.Status |= (impl->YM2612.Mode & 0x04) >> 2;
1261 impl->YM2612.TimerAcnt += impl->YM2612.TimerAL;
1262
1263 if (impl->YM2612.Mode & 0x80)
1264 {
1265 KEY_ON( &impl->YM2612.CHANNEL [2], &impl->g, 0 );
1266 KEY_ON( &impl->YM2612.CHANNEL [2], &impl->g, 1 );
1267 KEY_ON( &impl->YM2612.CHANNEL [2], &impl->g, 2 );
1268 KEY_ON( &impl->YM2612.CHANNEL [2], &impl->g, 3 );
1269 }
1270 }
1271 }
1272
1273 if (impl->YM2612.Mode & 2) // Timer B ON ?
1274 {
1275 // if ((impl->YM2612.TimerBcnt -= 14073) <= 0) // 13879=NTSC (old: 14475=NTSC 14586=PAL)
1276 if ((impl->YM2612.TimerBcnt -= i) <= 0)
1277 {
1278 // timer b overflow
1279 impl->YM2612.Status |= (impl->YM2612.Mode & 0x08) >> 2;
1280 impl->YM2612.TimerBcnt += impl->YM2612.TimerBL;
1281 }
1282 }
1283 }
1284 while ( remain > 0 );
1285}
1286
1287void impl_run( struct Ym2612_Impl* impl, int pair_count, short out [] )
1288{
1289 if ( pair_count <= 0 )
1290 return;
1291
1292 if ( impl->YM2612.Mode & 3 )
1293 run_timer( impl, pair_count );
1294
1295 // Mise à jour des pas des compteurs-frequences s'ils ont ete modifies
1296
1297 int chi;
1298 for ( chi = 0; chi < ym2612_channel_count; chi++ )
1299 {
1300 struct channel_* ch = &impl->YM2612.CHANNEL [chi];
1301 if ( ch->SLOT [0].Finc != -1 )
1302 continue;
1303
1304 int i2 = 0;
1305 if ( chi == 2 && (impl->YM2612.Mode & 0x40) )
1306 i2 = 2;
1307
1308 int i;
1309 for ( i = 0; i < 4; i++ )
1310 {
1311 // static int seq [4] = { 2, 1, 3, 0 };
1312 // if ( i2 ) i2 = seq [i];
1313
1314 struct slot_t* sl = &ch->SLOT [i];
1315 int finc = impl->g.FINC_TAB [ch->FNUM [i2]] >> (7 - ch->FOCT [i2]);
1316 int ksr = ch->KC [i2] >> sl->KSR_S; // keycode attenuation
1317 sl->Finc = (finc + sl->DT [ch->KC [i2]]) * sl->MUL;
1318 if (sl->KSR != ksr) // si le KSR a change alors
1319 { // les differents taux pour l'enveloppe sont mis à jour
1320 sl->KSR = ksr;
1321
1322 sl->EincA = sl->AR [ksr];
1323 sl->EincD = sl->DR [ksr];
1324 sl->EincS = sl->SR [ksr];
1325 sl->EincR = sl->RR [ksr];
1326
1327 if (sl->Ecurp == ATTACK)
1328 {
1329 sl->Einc = sl->EincA;
1330 }
1331 else if (sl->Ecurp == DECAY)
1332 {
1333 sl->Einc = sl->EincD;
1334 }
1335 else if (sl->Ecnt < ENV_END)
1336 {
1337 if (sl->Ecurp == SUBSTAIN)
1338 sl->Einc = sl->EincS;
1339 else if (sl->Ecurp == RELEASE)
1340 sl->Einc = sl->EincR;
1341 }
1342 }
1343
1344 if ( i2 )
1345 i2 = (i2 ^ 2) ^ (i2 >> 1);
1346 }
1347 }
1348
1349 int i;
1350 for ( i = 0; i < ym2612_channel_count; i++ )
1351 {
1352 if ( !(impl->mute_mask & (1 << i)) && (i != 5 || !impl->YM2612.DAC) )
1353 UPDATE_CHAN [impl->YM2612.CHANNEL [i].ALGO]( &impl->g, &impl->YM2612.CHANNEL [i], out, pair_count );
1354 }
1355
1356 impl->g.LFOcnt += impl->g.LFOinc * pair_count;
1357}
1358
1359void Ym2612_run( struct Ym2612_Emu* this, int pair_count, short out [] ) { impl_run( &this->impl, pair_count, out ); }
diff --git a/apps/codecs/libgme/ym2612_emu.h b/apps/codecs/libgme/ym2612_emu.h
new file mode 100644
index 0000000000..19f0903d61
--- /dev/null
+++ b/apps/codecs/libgme/ym2612_emu.h
@@ -0,0 +1,237 @@
1// YM2612 FM sound chip emulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef YM2612_EMU_H
5#define YM2612_EMU_H
6
7#include "blargg_common.h"
8
9enum { ym2612_out_chan_count = 2 }; // stereo
10enum { ym2612_channel_count = 6 };
11enum { ym2612_disabled_time = -1 };
12
13struct slot_t
14{
15 const int *DT; // parametre detune
16 int MUL; // parametre "multiple de frequence"
17 int TL; // Total Level = volume lorsque l'enveloppe est au plus haut
18 int TLL; // Total Level ajusted
19 int SLL; // Sustin Level (ajusted) = volume où l'enveloppe termine sa premiere phase de regression
20 int KSR_S; // Key Scale Rate Shift = facteur de prise en compte du KSL dans la variations de l'enveloppe
21 int KSR; // Key Scale Rate = cette valeur est calculee par rapport à la frequence actuelle, elle va influer
22 // sur les differents parametres de l'enveloppe comme l'attaque, le decay ... comme dans la realite !
23 int SEG; // Type enveloppe SSG
24 int env_xor;
25 int env_max;
26
27 const int *AR; // Attack Rate (table pointeur) = Taux d'attaque (AR [KSR])
28 const int *DR; // Decay Rate (table pointeur) = Taux pour la regression (DR [KSR])
29 const int *SR; // Sustin Rate (table pointeur) = Taux pour le maintien (SR [KSR])
30 const int *RR; // Release Rate (table pointeur) = Taux pour le rel'chement (RR [KSR])
31 int Fcnt; // Frequency Count = compteur-frequence pour determiner l'amplitude actuelle (SIN [Finc >> 16])
32 int Finc; // frequency step = pas d'incrementation du compteur-frequence
33 // plus le pas est grand, plus la frequence est aïgu (ou haute)
34 int Ecurp; // Envelope current phase = cette variable permet de savoir dans quelle phase
35 // de l'enveloppe on se trouve, par exemple phase d'attaque ou phase de maintenue ...
36 // en fonction de la valeur de cette variable, on va appeler une fonction permettant
37 // de mettre à jour l'enveloppe courante.
38 int Ecnt; // Envelope counter = le compteur-enveloppe permet de savoir où l'on se trouve dans l'enveloppe
39 int Einc; // Envelope step courant
40 int Ecmp; // Envelope counter limite pour la prochaine phase
41 int EincA; // Envelope step for Attack = pas d'incrementation du compteur durant la phase d'attaque
42 // cette valeur est egal à AR [KSR]
43 int EincD; // Envelope step for Decay = pas d'incrementation du compteur durant la phase de regression
44 // cette valeur est egal à DR [KSR]
45 int EincS; // Envelope step for Sustain = pas d'incrementation du compteur durant la phase de maintenue
46 // cette valeur est egal à SR [KSR]
47 int EincR; // Envelope step for Release = pas d'incrementation du compteur durant la phase de rel'chement
48 // cette valeur est egal à RR [KSR]
49 int *OUTp; // pointeur of SLOT output = pointeur permettant de connecter la sortie de ce slot à l'entree
50 // d'un autre ou carrement à la sortie de la voie
51 int INd; // input data of the slot = donnees en entree du slot
52 int ChgEnM; // Change envelop mask.
53 int AMS; // AMS depth level of this SLOT = degre de modulation de l'amplitude par le LFO
54 int AMSon; // AMS enable flag = drapeau d'activation de l'AMS
55};
56
57struct channel_
58{
59 int S0_OUT [4]; // anciennes sorties slot 0 (pour le feed back)
60 int LEFT; // LEFT enable flag
61 int RIGHT; // RIGHT enable flag
62 int ALGO; // Algorythm = determine les connections entre les operateurs
63 int FB; // shift count of self feed back = degre de "Feed-Back" du SLOT 1 (il est son unique entree)
64 int FMS; // Frequency Modulation Sensitivity of channel = degre de modulation de la frequence sur la voie par le LFO
65 int AMS; // Amplitude Modulation Sensitivity of channel = degre de modulation de l'amplitude sur la voie par le LFO
66 int FNUM [4]; // hauteur frequence de la voie (+ 3 pour le mode special)
67 int FOCT [4]; // octave de la voie (+ 3 pour le mode special)
68 int KC [4]; // Key Code = valeur fonction de la frequence (voir KSR pour les slots, KSR = KC >> KSR_S)
69 struct slot_t SLOT [4]; // four slot.operators = les 4 slots de la voie
70 int FFlag; // Frequency step recalculation flag
71};
72
73struct state_t
74{
75 int TimerBase; // TimerBase calculation
76 int Status; // YM2612 Status (timer overflow)
77 int TimerA; // timerA limit = valeur jusqu'à laquelle le timer A doit compter
78 int TimerAL;
79 int TimerAcnt; // timerA counter = valeur courante du Timer A
80 int TimerB; // timerB limit = valeur jusqu'à laquelle le timer B doit compter
81 int TimerBL;
82 int TimerBcnt; // timerB counter = valeur courante du Timer B
83 int Mode; // Mode actuel des voie 3 et 6 (normal / special)
84 int DAC; // DAC enabled flag
85 struct channel_ CHANNEL [ym2612_channel_count]; // Les 6 voies du YM2612
86 int REG [2] [0x100]; // Sauvegardes des valeurs de tout les registres, c'est facultatif
87 // cela nous rend le debuggage plus facile
88};
89
90#undef PI
91#define PI 3.14159265358979323846
92
93#define ATTACK 0
94#define DECAY 1
95#define SUBSTAIN 2
96#define RELEASE 3
97
98// SIN_LBITS <= 16
99// LFO_HBITS <= 16
100// (SIN_LBITS + SIN_HBITS) <= 26
101// (ENV_LBITS + ENV_HBITS) <= 28
102// (LFO_LBITS + LFO_HBITS) <= 28
103
104#define SIN_HBITS 12 // Sinus phase counter int part
105#define SIN_LBITS (26 - SIN_HBITS) // Sinus phase counter float part (best setting)
106
107#if (SIN_LBITS > 16)
108#define SIN_LBITS 16 // Can't be greater than 16 bits
109#endif
110
111#define ENV_HBITS 12 // Env phase counter int part
112#define ENV_LBITS (28 - ENV_HBITS) // Env phase counter float part (best setting)
113
114#define LFO_HBITS 10 // LFO phase counter int part
115#define LFO_LBITS (28 - LFO_HBITS) // LFO phase counter float part (best setting)
116
117#define SIN_LENGHT (1 << SIN_HBITS)
118#define ENV_LENGHT (1 << ENV_HBITS)
119#define LFO_LENGHT (1 << LFO_HBITS)
120
121#define TL_LENGHT (ENV_LENGHT * 3) // Env + TL scaling + LFO
122
123#define SIN_MASK (SIN_LENGHT - 1)
124#define ENV_MASK (ENV_LENGHT - 1)
125#define LFO_MASK (LFO_LENGHT - 1)
126
127#define ENV_STEP (96.0 / ENV_LENGHT) // ENV_MAX = 96 dB
128
129#define ENV_ATTACK ((ENV_LENGHT * 0) << ENV_LBITS)
130#define ENV_DECAY ((ENV_LENGHT * 1) << ENV_LBITS)
131#define ENV_END ((ENV_LENGHT * 2) << ENV_LBITS)
132
133#define MAX_OUT_BITS (SIN_HBITS + SIN_LBITS + 2) // Modulation = -4 <--> +4
134#define MAX_OUT ((1 << MAX_OUT_BITS) - 1)
135
136#define PG_CUT_OFF ((int) (78.0 / ENV_STEP))
137//#define ENV_CUT_OFF ((int) (68.0 / ENV_STEP))
138
139#define AR_RATE 399128
140#define DR_RATE 5514396
141
142//#define AR_RATE 426136
143//#define DR_RATE (AR_RATE * 12)
144
145#define LFO_FMS_LBITS 9 // FIXED (LFO_FMS_BASE gives somethink as 1)
146#define LFO_FMS_BASE ((int) (0.05946309436 * 0.0338 * (double) (1 << LFO_FMS_LBITS)))
147
148#define S0 0 // Stupid typo of the YM2612
149#define S1 2
150#define S2 1
151#define S3 3
152
153struct tables_t
154{
155 short SIN_TAB [SIN_LENGHT]; // SINUS TABLE (offset into TL TABLE)
156 int LFOcnt; // LFO counter = compteur-frequence pour le LFO
157 int LFOinc; // LFO step counter = pas d'incrementation du compteur-frequence du LFO
158 // plus le pas est grand, plus la frequence est grande
159 unsigned int AR_TAB [128]; // Attack rate table
160 unsigned int DR_TAB [96]; // Decay rate table
161 unsigned int DT_TAB [8] [32]; // Detune table
162 unsigned int SL_TAB [16]; // Substain level table
163 unsigned int NULL_RATE [32]; // Table for NULL rate
164 int LFO_INC_TAB [8]; // LFO step table
165
166 short ENV_TAB [2 * ENV_LENGHT + 8]; // ENV CURVE TABLE (attack & decay)
167
168 short LFO_ENV_TAB [LFO_LENGHT]; // LFO AMS TABLE (adjusted for 11.8 dB)
169 short LFO_FREQ_TAB [LFO_LENGHT]; // LFO FMS TABLE
170 int TL_TAB [TL_LENGHT * 2]; // TOTAL LEVEL TABLE (positif and minus)
171 unsigned int DECAY_TO_ATTACK [ENV_LENGHT]; // Conversion from decay to attack phase
172 unsigned int FINC_TAB [2048]; // Frequency step table
173};
174
175struct Ym2612_Impl
176{
177 struct state_t YM2612;
178 int mute_mask;
179 struct tables_t g;
180};
181
182void impl_reset( struct Ym2612_Impl* impl );
183
184struct Ym2612_Emu {
185 struct Ym2612_Impl impl;
186
187 // Impl
188 int last_time;
189 int sample_rate;
190 int clock_rate;
191 short* out;
192};
193
194static inline void Ym2612_init( struct Ym2612_Emu* this_ )
195{
196 this_->last_time = ym2612_disabled_time; this_->out = 0;
197 this_->impl.mute_mask = 0;
198}
199
200// Sets sample rate and chip clock rate, in Hz. Returns non-zero
201// if error. If clock_rate=0, uses sample_rate*144
202const char* Ym2612_set_rate( struct Ym2612_Emu* this_, double sample_rate, double clock_rate );
203
204// Resets to power-up state
205void Ym2612_reset( struct Ym2612_Emu* this_ );
206
207// Mutes voice n if bit n (1 << n) of mask is set
208void Ym2612_mute_voices( struct Ym2612_Emu* this_, int mask );
209
210// Writes addr to register 0 then data to register 1
211void Ym2612_write0( struct Ym2612_Emu* this_, int addr, int data ) ICODE_ATTR;
212
213// Writes addr to register 2 then data to register 3
214void Ym2612_write1( struct Ym2612_Emu* this_, int addr, int data ) ICODE_ATTR;
215
216// Runs and adds pair_count*2 samples into current output buffer contents
217void Ym2612_run( struct Ym2612_Emu* this_, int pair_count, short* out ) ICODE_ATTR;
218
219static inline void Ym2612_enable( struct Ym2612_Emu* this_, bool b ) { this_->last_time = b ? 0 : ym2612_disabled_time; }
220static inline bool Ym2612_enabled( struct Ym2612_Emu* this_ ) { return this_->last_time != ym2612_disabled_time; }
221static inline void Ym2612_begin_frame( struct Ym2612_Emu* this_, short* buf ) { this_->out = buf; this_->last_time = 0; }
222
223static inline int Ym2612_run_until( struct Ym2612_Emu* this_, int time )
224{
225 int count = time - this_->last_time;
226 if ( count > 0 )
227 {
228 if ( this_->last_time < 0 )
229 return false;
230 this_->last_time = time;
231 short* p = this_->out;
232 this_->out += count * ym2612_out_chan_count;
233 Ym2612_run( this_, count, p );
234 }
235 return true;
236}
237#endif
diff --git a/apps/codecs/libgme/ymdeltat.c b/apps/codecs/libgme/ymdeltat.c
new file mode 100644
index 0000000000..ea0be59013
--- /dev/null
+++ b/apps/codecs/libgme/ymdeltat.c
@@ -0,0 +1,655 @@
1/*
2**
3** File: ymdeltat.c
4**
5** YAMAHA DELTA-T adpcm sound emulation subroutine
6** used by fmopl.c (Y8950) and fm.c (YM2608 and YM2610/B)
7**
8** Base program is YM2610 emulator by Hiromitsu Shioya.
9** Written by Tatsuyuki Satoh
10** Improvements by Jarek Burczynski (bujar at mame dot net)
11**
12**
13** History:
14**
15** 03-08-2003 Jarek Burczynski:
16** - fixed BRDY flag implementation.
17**
18** 24-07-2003 Jarek Burczynski, Frits Hilderink:
19** - fixed delault value for control2 in YM_DELTAT_ADPCM_Reset
20**
21** 22-07-2003 Jarek Burczynski, Frits Hilderink:
22** - fixed external memory support
23**
24** 15-06-2003 Jarek Burczynski:
25** - implemented CPU -> AUDIO ADPCM synthesis (via writes to the ADPCM data reg $08)
26** - implemented support for the Limit address register
27** - supported two bits from the control register 2 ($01): RAM TYPE (x1 bit/x8 bit), ROM/RAM
28** - implemented external memory access (read/write) via the ADPCM data reg reads/writes
29** Thanks go to Frits Hilderink for the example code.
30**
31** 14-06-2003 Jarek Burczynski:
32** - various fixes to enable proper support for status register flags: BSRDY, PCM BSY, ZERO
33** - modified EOS handling
34**
35** 05-04-2003 Jarek Burczynski:
36** - implemented partial support for external/processor memory on sample replay
37**
38** 01-12-2002 Jarek Burczynski:
39** - fixed first missing sound in gigandes thanks to previous fix (interpolator) by ElSemi
40** - renamed/removed some YM_DELTAT struct fields
41**
42** 28-12-2001 Acho A. Tang
43** - added EOS status report on ADPCM playback.
44**
45** 05-08-2001 Jarek Burczynski:
46** - now_step is initialized with 0 at the start of play.
47**
48** 12-06-2001 Jarek Burczynski:
49** - corrected end of sample bug in YM_DELTAT_ADPCM_CALC.
50** Checked on real YM2610 chip - address register is 24 bits wide.
51** Thanks go to Stefan Jokisch (stefan.jokisch@gmx.de) for tracking down the problem.
52**
53** TO DO:
54** Check size of the address register on the other chips....
55**
56** Version 0.72
57**
58** sound chips that have this unit:
59** YM2608 OPNA
60** YM2610/B OPNB
61** Y8950 MSX AUDIO
62**
63*/
64
65#include "ymdeltat.h"
66#define INLINE __inline
67#define logerror (void)
68
69#define YM_DELTAT_DELTA_MAX (24576)
70#define YM_DELTAT_DELTA_MIN (127)
71#define YM_DELTAT_DELTA_DEF (127)
72
73#define YM_DELTAT_DECODE_RANGE 32768
74#define YM_DELTAT_DECODE_MIN (-(YM_DELTAT_DECODE_RANGE))
75#define YM_DELTAT_DECODE_MAX ((YM_DELTAT_DECODE_RANGE)-1)
76
77
78/* Forecast to next Forecast (rate = *8) */
79/* 1/8 , 3/8 , 5/8 , 7/8 , 9/8 , 11/8 , 13/8 , 15/8 */
80static const INT32 ym_deltat_decode_tableB1[16] ICONST_ATTR = {
81 1, 3, 5, 7, 9, 11, 13, 15,
82 -1, -3, -5, -7, -9, -11, -13, -15,
83};
84/* delta to next delta (rate= *64) */
85/* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 */
86static const INT32 ym_deltat_decode_tableB2[16] ICONST_ATTR = {
87 57, 57, 57, 57, 77, 102, 128, 153,
88 57, 57, 57, 57, 77, 102, 128, 153
89};
90
91#if 0
92void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT)
93{
94 logerror("BRDY_callback reached (flag set) !\n");
95
96 /* set BRDY bit in status register */
97 if(DELTAT->status_set_handler)
98 if(DELTAT->status_change_BRDY_bit)
99 (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
100}
101#endif
102
103UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT)
104{
105 UINT8 v = 0;
106
107 /* external memory read */
108 if ( (DELTAT->portstate & 0xe0)==0x20 )
109 {
110 /* two dummy reads */
111 if (DELTAT->memread)
112 {
113 DELTAT->now_addr = DELTAT->start << 1;
114 DELTAT->memread--;
115 return 0;
116 }
117
118
119 if ( DELTAT->now_addr != (DELTAT->end<<1) )
120 {
121 v = DELTAT->memory[DELTAT->now_addr>>1];
122
123 /*logerror("YM Delta-T memory read $%08x, v=$%02x\n", DELTAT->now_addr >> 1, v);*/
124
125 DELTAT->now_addr+=2; /* two nibbles at a time */
126
127 /* reset BRDY bit in status register, which means we are reading the memory now */
128 if(DELTAT->status_reset_handler)
129 if(DELTAT->status_change_BRDY_bit)
130 (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
131
132 /* setup a timer that will callback us in 10 master clock cycles for Y8950
133 * in the callback set the BRDY flag to 1 , which means we have another data ready.
134 * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work.
135 */
136 /* set BRDY bit in status register */
137 if(DELTAT->status_set_handler)
138 if(DELTAT->status_change_BRDY_bit)
139 (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
140 }
141 else
142 {
143 /* set EOS bit in status register */
144 if(DELTAT->status_set_handler)
145 if(DELTAT->status_change_EOS_bit)
146 (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit);
147 }
148 }
149
150 return v;
151}
152
153
154/* 0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */
155static const UINT8 dram_rightshift[4] ICONST_ATTR ={3,0,0,0};
156
157/* DELTA-T ADPCM write register */
158void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v)
159{
160 if(r>=0x10) return;
161 DELTAT->reg[r] = v; /* stock data */
162
163 switch( r )
164 {
165 case 0x00:
166/*
167START:
168 Accessing *external* memory is started when START bit (D7) is set to "1", so
169 you must set all conditions needed for recording/playback before starting.
170 If you access *CPU-managed* memory, recording/playback starts after
171 read/write of ADPCM data register $08.
172
173REC:
174 0 = ADPCM synthesis (playback)
175 1 = ADPCM analysis (record)
176
177MEMDATA:
178 0 = processor (*CPU-managed*) memory (means: using register $08)
179 1 = external memory (using start/end/limit registers to access memory: RAM or ROM)
180
181
182SPOFF:
183 controls output pin that should disable the speaker while ADPCM analysis
184
185RESET and REPEAT only work with external memory.
186
187
188some examples:
189value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning:
190 C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register
191 E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register
192 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register
193 a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register
194
195 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08
196 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08
197
198*/
199 /* handle emulation mode */
200 if(DELTAT->emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610)
201 {
202 v |= 0x20; /* YM2610 always uses external memory and doesn't even have memory flag bit. */
203 }
204
205 DELTAT->portstate = v & (0x80|0x40|0x20|0x10|0x01); /* start, rec, memory mode, repeat flag copy, reset(bit0) */
206
207 if( DELTAT->portstate&0x80 )/* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */
208 {
209 /* set PCM BUSY bit */
210 DELTAT->PCM_BSY = 1;
211
212 /* start ADPCM */
213 DELTAT->now_step = 0;
214 DELTAT->acc = 0;
215 DELTAT->prev_acc = 0;
216 DELTAT->adpcml = 0;
217 DELTAT->adpcmd = YM_DELTAT_DELTA_DEF;
218 DELTAT->now_data = 0;
219
220 }
221
222 if( DELTAT->portstate&0x20 ) /* do we access external memory? */
223 {
224 DELTAT->now_addr = DELTAT->start << 1;
225 DELTAT->memread = 2; /* two dummy reads needed before accesing external memory via register $08*/
226
227 /* if yes, then let's check if ADPCM memory is mapped and big enough */
228 if(DELTAT->memory == 0)
229 {
230 logerror("YM Delta-T ADPCM rom not mapped\n");
231 DELTAT->portstate = 0x00;
232 DELTAT->PCM_BSY = 0;
233 }
234 else
235 {
236 if( DELTAT->end >= DELTAT->memory_size ) /* Check End in Range */
237 {
238 /* logerror("YM Delta-T ADPCM end out of range: $%08x\n", DELTAT->end); */
239 DELTAT->end = DELTAT->memory_size - 1;
240 }
241 if( DELTAT->start >= DELTAT->memory_size ) /* Check Start in Range */
242 {
243 /* logerror("YM Delta-T ADPCM start out of range: $%08x\n", DELTAT->start); */
244 DELTAT->portstate = 0x00;
245 DELTAT->PCM_BSY = 0;
246 }
247 }
248 }
249 else /* we access CPU memory (ADPCM data register $08) so we only reset now_addr here */
250 {
251 DELTAT->now_addr = 0;
252 }
253
254 if( DELTAT->portstate&0x01 )
255 {
256 DELTAT->portstate = 0x00;
257
258 /* clear PCM BUSY bit (in status register) */
259 DELTAT->PCM_BSY = 0;
260
261 /* set BRDY flag */
262 if(DELTAT->status_set_handler)
263 if(DELTAT->status_change_BRDY_bit)
264 (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
265 }
266 break;
267 case 0x01: /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */
268 /* handle emulation mode */
269 if(DELTAT->emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610)
270 {
271 v |= 0x01; /* YM2610 always uses ROM as an external memory and doesn't tave ROM/RAM memory flag bit. */
272 }
273
274 DELTAT->pan = &DELTAT->output_pointer[(v>>6)&0x03];
275 if ((DELTAT->control2 & 3) != (v & 3))
276 {
277 /*0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */
278 if (DELTAT->DRAMportshift != dram_rightshift[v&3])
279 {
280 DELTAT->DRAMportshift = dram_rightshift[v&3];
281
282 /* final shift value depends on chip type and memory type selected:
283 8 for YM2610 (ROM only),
284 5 for ROM for Y8950 and YM2608,
285 5 for x8bit DRAMs for Y8950 and YM2608,
286 2 for x1bit DRAMs for Y8950 and YM2608.
287 */
288
289 /* refresh addresses */
290 DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << (DELTAT->portshift - DELTAT->DRAMportshift);
291 DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << (DELTAT->portshift - DELTAT->DRAMportshift);
292 DELTAT->end += (1 << (DELTAT->portshift-DELTAT->DRAMportshift) ) - 1;
293 DELTAT->limit = (DELTAT->reg[0xd]*0x0100 | DELTAT->reg[0xc]) << (DELTAT->portshift - DELTAT->DRAMportshift);
294 }
295 }
296 DELTAT->control2 = v;
297 break;
298 case 0x02: /* Start Address L */
299 case 0x03: /* Start Address H */
300 DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << (DELTAT->portshift - DELTAT->DRAMportshift);
301 /*logerror("DELTAT start: 02=%2x 03=%2x addr=%8x\n",DELTAT->reg[0x2], DELTAT->reg[0x3],DELTAT->start );*/
302 break;
303 case 0x04: /* Stop Address L */
304 case 0x05: /* Stop Address H */
305 DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << (DELTAT->portshift - DELTAT->DRAMportshift);
306 DELTAT->end += (1 << (DELTAT->portshift-DELTAT->DRAMportshift) ) - 1;
307 /*logerror("DELTAT end : 04=%2x 05=%2x addr=%8x\n",DELTAT->reg[0x4], DELTAT->reg[0x5],DELTAT->end );*/
308 break;
309 case 0x06: /* Prescale L (ADPCM and Record frq) */
310 case 0x07: /* Prescale H */
311 break;
312 case 0x08: /* ADPCM data */
313
314/*
315some examples:
316value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning:
317 C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register
318 E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register
319 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register
320 a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register
321
322 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08
323 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08
324
325*/
326
327 /* external memory write */
328 if ( (DELTAT->portstate & 0xe0)==0x60 )
329 {
330 if (DELTAT->memread)
331 {
332 DELTAT->now_addr = DELTAT->start << 1;
333 DELTAT->memread = 0;
334 }
335
336 /*logerror("YM Delta-T memory write $%08x, v=$%02x\n", DELTAT->now_addr >> 1, v);*/
337
338 if ( DELTAT->now_addr != (DELTAT->end<<1) )
339 {
340 DELTAT->memory[DELTAT->now_addr>>1] = v;
341 DELTAT->now_addr+=2; /* two nibbles at a time */
342
343 /* reset BRDY bit in status register, which means we are processing the write */
344 if(DELTAT->status_reset_handler)
345 if(DELTAT->status_change_BRDY_bit)
346 (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
347
348 /* setup a timer that will callback us in 10 master clock cycles for Y8950
349 * in the callback set the BRDY flag to 1 , which means we have written the data.
350 * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work.
351 */
352 /* set BRDY bit in status register */
353 if(DELTAT->status_set_handler)
354 if(DELTAT->status_change_BRDY_bit)
355 (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
356
357 }
358 else
359 {
360 /* set EOS bit in status register */
361 if(DELTAT->status_set_handler)
362 if(DELTAT->status_change_EOS_bit)
363 (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit);
364 }
365
366 return;
367 }
368
369 /* ADPCM synthesis from CPU */
370 if ( (DELTAT->portstate & 0xe0)==0x80 )
371 {
372 DELTAT->CPU_data = v;
373
374 /* Reset BRDY bit in status register, which means we are full of data */
375 if(DELTAT->status_reset_handler)
376 if(DELTAT->status_change_BRDY_bit)
377 (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
378 return;
379 }
380
381 break;
382 case 0x09: /* DELTA-N L (ADPCM Playback Prescaler) */
383 case 0x0a: /* DELTA-N H */
384 DELTAT->delta = (DELTAT->reg[0xa]*0x0100 | DELTAT->reg[0x9]);
385 DELTAT->step = (UINT32)( (double)(DELTAT->delta /* *(1<<(YM_DELTAT_SHIFT-16)) */ ) * (DELTAT->freqbase) );
386 /*logerror("DELTAT deltan:09=%2x 0a=%2x\n",DELTAT->reg[0x9], DELTAT->reg[0xa]);*/
387 break;
388 case 0x0b: /* Output level control (volume, linear) */
389 {
390 INT32 oldvol = DELTAT->volume;
391 DELTAT->volume = (v&0xff) * (DELTAT->output_range/256) / YM_DELTAT_DECODE_RANGE;
392/* v * ((1<<16)>>8) >> 15;
393* thus: v * (1<<8) >> 15;
394* thus: output_range must be (1 << (15+8)) at least
395* v * ((1<<23)>>8) >> 15;
396* v * (1<<15) >> 15;
397*/
398 /*logerror("DELTAT vol = %2x\n",v&0xff);*/
399 if( oldvol != 0 )
400 {
401 DELTAT->adpcml = (int)((double)DELTAT->adpcml / (double)oldvol * (double)DELTAT->volume);
402 }
403 }
404 break;
405 case 0x0c: /* Limit Address L */
406 case 0x0d: /* Limit Address H */
407 DELTAT->limit = (DELTAT->reg[0xd]*0x0100 | DELTAT->reg[0xc]) << (DELTAT->portshift - DELTAT->DRAMportshift);
408 /*logerror("DELTAT limit: 0c=%2x 0d=%2x addr=%8x\n",DELTAT->reg[0xc], DELTAT->reg[0xd],DELTAT->limit );*/
409 break;
410 }
411}
412
413void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode)
414{
415 DELTAT->now_addr = 0;
416 DELTAT->now_step = 0;
417 DELTAT->step = 0;
418 DELTAT->start = 0;
419 DELTAT->end = 0;
420 DELTAT->limit = ~0; /* this way YM2610 and Y8950 (both of which don't have limit address reg) will still work */
421 DELTAT->volume = 0;
422 DELTAT->pan = &DELTAT->output_pointer[pan];
423 DELTAT->acc = 0;
424 DELTAT->prev_acc = 0;
425 DELTAT->adpcmd = 127;
426 DELTAT->adpcml = 0;
427 DELTAT->emulation_mode = (UINT8)emulation_mode;
428 DELTAT->portstate = (emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x20 : 0;
429 DELTAT->control2 = (emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x01 : 0; /* default setting depends on the emulation mode. MSX demo called "facdemo_4" doesn't setup control2 register at all and still works */
430 DELTAT->DRAMportshift = dram_rightshift[DELTAT->control2 & 3];
431
432 /* The flag mask register disables the BRDY after the reset, however
433 ** as soon as the mask is enabled the flag needs to be set. */
434
435 /* set BRDY bit in status register */
436 if(DELTAT->status_set_handler)
437 if(DELTAT->status_change_BRDY_bit)
438 (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
439}
440
441#if 0
442void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs)
443{
444 int r;
445
446 /* to keep adpcml */
447 DELTAT->volume = 0;
448 /* update */
449 for(r=1;r<16;r++)
450 YM_DELTAT_ADPCM_Write(DELTAT,r,regs[r]);
451 DELTAT->reg[0] = regs[0];
452
453 /* current rom data */
454 if (DELTAT->memory)
455 DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1) );
456
457}
458void YM_DELTAT_savestate(const device_config *device,YM_DELTAT *DELTAT)
459{
460#ifdef __STATE_H__
461 state_save_register_device_item(device, 0, DELTAT->portstate);
462 state_save_register_device_item(device, 0, DELTAT->now_addr);
463 state_save_register_device_item(device, 0, DELTAT->now_step);
464 state_save_register_device_item(device, 0, DELTAT->acc);
465 state_save_register_device_item(device, 0, DELTAT->prev_acc);
466 state_save_register_device_item(device, 0, DELTAT->adpcmd);
467 state_save_register_device_item(device, 0, DELTAT->adpcml);
468#endif
469}
470#endif
471
472
473#define YM_DELTAT_Limit(val,max,min) \
474{ \
475 if ( val > max ) val = max; \
476 else if ( val < min ) val = min; \
477}
478
479static INLINE void YM_DELTAT_synthesis_from_external_memory(YM_DELTAT *DELTAT)
480{
481 UINT32 step;
482 int data;
483
484 DELTAT->now_step += DELTAT->step;
485 if ( DELTAT->now_step >= (1<<YM_DELTAT_SHIFT) )
486 {
487 step = DELTAT->now_step >> YM_DELTAT_SHIFT;
488 DELTAT->now_step &= (1<<YM_DELTAT_SHIFT)-1;
489 do{
490
491 if ( DELTAT->now_addr == (DELTAT->limit<<1) )
492 DELTAT->now_addr = 0;
493
494 if ( DELTAT->now_addr == (DELTAT->end<<1) ) { /* 12-06-2001 JB: corrected comparison. Was > instead of == */
495 if( DELTAT->portstate&0x10 ){
496 /* repeat start */
497 DELTAT->now_addr = DELTAT->start<<1;
498 DELTAT->acc = 0;
499 DELTAT->adpcmd = YM_DELTAT_DELTA_DEF;
500 DELTAT->prev_acc = 0;
501 }else{
502 /* set EOS bit in status register */
503 if(DELTAT->status_set_handler)
504 if(DELTAT->status_change_EOS_bit)
505 (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit);
506
507 /* clear PCM BUSY bit (reflected in status register) */
508 DELTAT->PCM_BSY = 0;
509
510 DELTAT->portstate = 0;
511 DELTAT->adpcml = 0;
512 DELTAT->prev_acc = 0;
513 return;
514 }
515 }
516
517 if( DELTAT->now_addr&1 ) data = DELTAT->now_data & 0x0f;
518 else
519 {
520 DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1));
521 data = DELTAT->now_data >> 4;
522 }
523
524 DELTAT->now_addr++;
525 /* 12-06-2001 JB: */
526 /* YM2610 address register is 24 bits wide.*/
527 /* The "+1" is there because we use 1 bit more for nibble calculations.*/
528 /* WARNING: */
529 /* Side effect: we should take the size of the mapped ROM into account */
530 DELTAT->now_addr &= ( (1<<(24+1))-1);
531
532 /* store accumulator value */
533 DELTAT->prev_acc = DELTAT->acc;
534
535 /* Forecast to next Forecast */
536 DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8);
537 YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN);
538
539 /* delta to next delta */
540 DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64;
541 YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN );
542
543 /* ElSemi: Fix interpolator. */
544 /*DELTAT->prev_acc = prev_acc + ((DELTAT->acc - prev_acc) / 2 );*/
545
546 }while(--step);
547
548 }
549
550 /* ElSemi: Fix interpolator. */
551 DELTAT->adpcml = DELTAT->prev_acc * (int)((1<<YM_DELTAT_SHIFT)-DELTAT->now_step);
552 DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step);
553 DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume;
554
555 /* output for work of output channels (outd[OPNxxxx])*/
556 *(DELTAT->pan) += DELTAT->adpcml;
557}
558
559
560
561static INLINE void YM_DELTAT_synthesis_from_CPU_memory(YM_DELTAT *DELTAT)
562{
563 UINT32 step;
564 int data;
565
566 DELTAT->now_step += DELTAT->step;
567 if ( DELTAT->now_step >= (1<<YM_DELTAT_SHIFT) )
568 {
569 step = DELTAT->now_step >> YM_DELTAT_SHIFT;
570 DELTAT->now_step &= (1<<YM_DELTAT_SHIFT)-1;
571 do{
572
573 if( DELTAT->now_addr&1 )
574 {
575 data = DELTAT->now_data & 0x0f;
576
577 DELTAT->now_data = DELTAT->CPU_data;
578
579 /* after we used CPU_data, we set BRDY bit in status register,
580 * which means we are ready to accept another byte of data */
581 if(DELTAT->status_set_handler)
582 if(DELTAT->status_change_BRDY_bit)
583 (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
584 }
585 else
586 {
587 data = DELTAT->now_data >> 4;
588 }
589
590 DELTAT->now_addr++;
591
592 /* store accumulator value */
593 DELTAT->prev_acc = DELTAT->acc;
594
595 /* Forecast to next Forecast */
596 DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8);
597 YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN);
598
599 /* delta to next delta */
600 DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64;
601 YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN );
602
603
604 }while(--step);
605
606 }
607
608 /* ElSemi: Fix interpolator. */
609 DELTAT->adpcml = DELTAT->prev_acc * (int)((1<<YM_DELTAT_SHIFT)-DELTAT->now_step);
610 DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step);
611 DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume;
612
613 /* output for work of output channels (outd[OPNxxxx])*/
614 *(DELTAT->pan) += DELTAT->adpcml;
615}
616
617
618
619/* ADPCM B (Delta-T control type) */
620void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT)
621{
622
623/*
624some examples:
625value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning:
626 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register
627 a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register
628 C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register
629 E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register
630
631 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08
632 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08
633
634*/
635
636 if ( (DELTAT->portstate & 0xe0)==0xa0 )
637 {
638 YM_DELTAT_synthesis_from_external_memory(DELTAT);
639 return;
640 }
641
642 if ( (DELTAT->portstate & 0xe0)==0x80 )
643 {
644 /* ADPCM synthesis from CPU-managed memory (from reg $08) */
645 YM_DELTAT_synthesis_from_CPU_memory(DELTAT); /* change output based on data in ADPCM data reg ($08) */
646 return;
647 }
648
649//todo: ADPCM analysis
650// if ( (DELTAT->portstate & 0xe0)==0xc0 )
651// if ( (DELTAT->portstate & 0xe0)==0xe0 )
652
653 return;
654}
655
diff --git a/apps/codecs/libgme/ymdeltat.h b/apps/codecs/libgme/ymdeltat.h
new file mode 100644
index 0000000000..01af4998a0
--- /dev/null
+++ b/apps/codecs/libgme/ymdeltat.h
@@ -0,0 +1,100 @@
1#pragma once
2
3#ifndef __YMDELTAT_H__
4#define __YMDELTAT_H__
5
6#include "blargg_common.h"
7
8/* compiler dependence */
9#ifndef __OSDCOMM_H__
10#define __OSDCOMM_H__
11typedef unsigned char UINT8; /* unsigned 8bit */
12typedef unsigned short UINT16; /* unsigned 16bit */
13typedef unsigned int UINT32; /* unsigned 32bit */
14typedef signed char INT8; /* signed 8bit */
15typedef signed short INT16; /* signed 16bit */
16typedef signed int INT32; /* signed 32bit */
17
18typedef INT32 stream_sample_t;
19
20#endif /* __OSDCOMM_H__ */
21
22#define YM_DELTAT_SHIFT (16)
23
24#define YM_DELTAT_EMULATION_MODE_NORMAL 0
25#define YM_DELTAT_EMULATION_MODE_YM2610 1
26
27
28typedef void (*STATUS_CHANGE_HANDLER)(void *chip, UINT8 status_bits);
29
30
31/* DELTA-T (adpcm type B) struct */
32typedef struct deltat_adpcm_state { /* AT: rearranged and tigntened structure */
33 UINT8 *memory;
34 INT32 *output_pointer;/* pointer of output pointers */
35 INT32 *pan; /* pan : &output_pointer[pan] */
36 double freqbase;
37#if 0
38 double write_time; /* Y8950: 10 cycles of main clock; YM2608: 20 cycles of main clock */
39 double read_time; /* Y8950: 8 cycles of main clock; YM2608: 18 cycles of main clock */
40#endif
41 UINT32 memory_size;
42 int output_range;
43 UINT32 now_addr; /* current address */
44 UINT32 now_step; /* currect step */
45 UINT32 step; /* step */
46 UINT32 start; /* start address */
47 UINT32 limit; /* limit address */
48 UINT32 end; /* end address */
49 UINT32 delta; /* delta scale */
50 INT32 volume; /* current volume */
51 INT32 acc; /* shift Measurement value*/
52 INT32 adpcmd; /* next Forecast */
53 INT32 adpcml; /* current value */
54 INT32 prev_acc; /* leveling value */
55 UINT8 now_data; /* current rom data */
56 UINT8 CPU_data; /* current data from reg 08 */
57 UINT8 portstate; /* port status */
58 UINT8 control2; /* control reg: SAMPLE, DA/AD, RAM TYPE (x8bit / x1bit), ROM/RAM */
59 UINT8 portshift; /* address bits shift-left:
60 ** 8 for YM2610,
61 ** 5 for Y8950 and YM2608 */
62
63 UINT8 DRAMportshift; /* address bits shift-right:
64 ** 0 for ROM and x8bit DRAMs,
65 ** 3 for x1 DRAMs */
66
67 UINT8 memread; /* needed for reading/writing external memory */
68
69 /* handlers and parameters for the status flags support */
70 STATUS_CHANGE_HANDLER status_set_handler;
71 STATUS_CHANGE_HANDLER status_reset_handler;
72
73 /* note that different chips have these flags on different
74 ** bits of the status register
75 */
76 void * status_change_which_chip; /* this chip id */
77 UINT8 status_change_EOS_bit; /* 1 on End Of Sample (record/playback/cycle time of AD/DA converting has passed)*/
78 UINT8 status_change_BRDY_bit; /* 1 after recording 2 datas (2x4bits) or after reading/writing 1 data */
79 UINT8 status_change_ZERO_bit; /* 1 if silence lasts for more than 290 miliseconds on ADPCM recording */
80
81 /* neither Y8950 nor YM2608 can generate IRQ when PCMBSY bit changes, so instead of above,
82 ** the statusflag gets ORed with PCM_BSY (below) (on each read of statusflag of Y8950 and YM2608)
83 */
84 UINT8 PCM_BSY; /* 1 when ADPCM is playing; Y8950/YM2608 only */
85
86 UINT8 reg[16]; /* adpcm registers */
87 UINT8 emulation_mode; /* which chip we're emulating */
88}YM_DELTAT;
89
90/*void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT);*/
91
92UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT) ICODE_ATTR;
93void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v) ICODE_ATTR;
94void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode);
95void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT) ICODE_ATTR;
96
97/*void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs);
98void YM_DELTAT_savestate(const device_config *device,YM_DELTAT *DELTAT);*/
99
100#endif /* __YMDELTAT_H__ */
diff --git a/apps/codecs/libgme/ymtables.h b/apps/codecs/libgme/ymtables.h
new file mode 100644
index 0000000000..4e8f62a39b
--- /dev/null
+++ b/apps/codecs/libgme/ymtables.h
@@ -0,0 +1,559 @@
1#ifndef _EMUTABLES_H_
2#define _EMUTABLES_H_
3
4/* Precompiled ym2612 tables for use in Rockbox */
5
6static const int tl_coeff[] ICONST_ATTR = {
7 268435455, 267712100, 266990695, 266271234, 265553712, 264838123, 264124462, 263412725, 262702906, 261994999, 261289000,
8 260584903, 259882704, 259182396, 258483976, 257787438, 257092777, 256399988, 255709066, 255020006, 254332802, 253647450,
9 252963945, 252282282, 251602456, 250924462, 250248294, 249573949, 248901421, 248230705, 247561797, 246894691, 246229383,
10 245565867, 244904140, 244244195, 243586029, 242929637, 242275013, 241622154, 240971053, 240321708, 239674112, 239028261,
11 238384150, 237741775, 237101131, 236462214, 235825018, 235189539, 234555773, 233923714, 233293359, 232664702, 232037740,
12 231412466, 230788878, 230166970, 229546738, 228928178, 228311284, 227696052, 227082479, 226470558, 225860287, 225251660,
13 224644674, 224039323, 223435603, 222833510, 222233039, 221634187, 221036948, 220441319, 219847295, 219254871, 218664044,
14 218074809, 217487162, 216901098, 216316614, 215733704, 215152366, 214572594, 213994384, 213417732, 212842635, 212269087,
15 211697084, 211126623, 210557699, 209990308, 209424446, 208860109, 208297293, 207735993, 207176206, 206617927, 206061153,
16 205505879, 204952102, 204399816, 203849019, 203299706, 202751873, 202205517, 201660633, 201117217, 200575266, 200034774,
17 199495740, 198958158, 198422024, 197887335, 197354088, 196822277, 196291899, 195762950, 195235427, 194709325, 194184641,
18 193661370, 193139510, 192619056, 192100005, 191582352, 191066094, 190551228, 190037748, 189525653, 189014937, 188505598,
19 187997631, 187491033, 186985800, 186481928, 185979414, 185478255, 184978446, 184479983, 183982864, 183487085, 182992641,
20 182499530, 182007748, 181517291, 181028155, 180540338, 180053835, 179568643, 179084759, 178602178, 178120898, 177640915,
21 177162225, 176684825, 176208712, 175733881, 175260330, 174788055, 174317053, 173847320, 173378853, 172911648, 172445702,
22 171981012, 171517574, 171055385, 170594441, 170134740, 169676277, 169219049, 168763054, 168308287, 167854746, 167402427,
23 166951327, 166501443, 166052770, 165605307, 165159050, 164713995, 164270139, 163827480, 163386013, 162945736, 162506646,
24 162068738, 161632011, 161196460, 160762083, 160328877, 159896838, 159465963, 159036250, 158607694, 158180293, 157754044,
25 157328943, 156904988, 156482176, 156060502, 155639965, 155220562, 154802288, 154385142, 153969119, 153554218, 153140435,
26 152727766, 152316210, 151905763, 151496422, 151088184, 150681046, 150275005, 149870058, 149466203, 149063435, 148661753,
27 148261154, 147861634, 147463190, 147065821, 146669522, 146274291, 145880125, 145487021, 145094976, 144703988, 144314054,
28 143925170, 143537334, 143150543, 142764795, 142380086, 141996414, 141613775, 141232168, 140851589, 140472035, 140093505,
29 139715994, 139339501, 138964022, 138589555, 138216097, 137843646, 137472198, 137101751, 136732302, 136363849, 135996388,
30 135629918, 135264436, 134899938, 134536423, 134173887, 133812328, 133451743, 133092130, 132733486, 132375808, 132019095,
31 131663342, 131308548, 130954711, 130601826, 130249893, 129898908, 129548869, 129199773, 128851618, 128504401, 128158119,
32 127812771, 127468353, 127124864, 126782300, 126440659, 126099939, 125760137, 125421250, 125083277, 124746214, 124410060,
33 124074812, 123740467, 123407023, 123074477, 122742828, 122412072, 122082208, 121753232, 121425143, 121097939, 120771615,
34 120446172, 120121605, 119797912, 119475092, 119153142, 118832060, 118511843, 118192488, 117873994, 117556359, 117239579,
35 116923653, 116608578, 116294353, 115980974, 115668439, 115356747, 115045894, 114735880, 114426700, 114118354, 113810839,
36 113504152, 113198292, 112893256, 112589042, 112285648, 111983071, 111681310, 111380362, 111080225, 110780896, 110482375,
37 110184657, 109887742, 109591627, 109296310, 109001789, 108708061, 108415125, 108122978, 107831619, 107541044, 107251253,
38 106962243, 106674011, 106386556, 106099876, 105813968, 105528830, 105244461, 104960859, 104678020, 104395944, 104114628,
39 103834069, 103554267, 103275219, 102996923, 102719377, 102442578, 102166526, 101891217, 101616650, 101342823, 101069734,
40 100797381, 100525762, 100254875, 99984718, 99715288, 99446585, 99178606, 98911349, 98644812, 98378993, 98113891,
41 97849503, 97585828, 97322863, 97060606, 96799057, 96538212, 96278070, 96018629, 95759887, 95501842, 95244493,
42 94987837, 94731873, 94476599, 94222012, 93968112, 93714895, 93462361, 93210508, 92959333, 92708835, 92459012,
43 92209863, 91961384, 91713575, 91466434, 91219959, 90974149, 90729000, 90484512, 90240683, 89997511, 89754994,
44 89513131, 89271920, 89031358, 88791445, 88552178, 88313556, 88075578, 87838240, 87601542, 87365481, 87130057,
45 86895267, 86661110, 86427584, 86194687, 85962418, 85730775, 85499756, 85269359, 85039583, 84810427, 84581888,
46 84353965, 84126656, 83899959, 83673874, 83448397, 83223528, 82999266, 82775607, 82552551, 82330096, 82108241,
47 81886984, 81666322, 81446256, 81226782, 81007900, 80789608, 80571904, 80354786, 80138254, 79922305, 79706938,
48 79492151, 79277943, 79064313, 78851258, 78638777, 78426868, 78215531, 78004763, 77794564, 77584930, 77375862,
49 77167357, 76959413, 76752031, 76545207, 76338940, 76133229, 75928072, 75723469, 75519416, 75315914, 75112960,
50 74910552, 74708690, 74507373, 74306597, 74106363, 73906668, 73707512, 73508892, 73310807, 73113256, 72916237,
51 72719749, 72523791, 72328361, 72133457, 71939079, 71745225, 71551892, 71359081, 71166789, 70975016, 70783759,
52 70593018, 70402791, 70213076, 70023872, 69835179, 69646994, 69459315, 69272143, 69085475, 68899310, 68713647,
53 68528484, 68343820, 68159653, 67975983, 67792808, 67610127, 67427937, 67246239, 67065030, 66884310, 66704076,
54 66524328, 66345065, 66166285, 65987986, 65810168, 65632829, 65455968, 65279583, 65103674, 64928239, 64753277,
55 64578786, 64404765, 64231213, 64058129, 63885511, 63713359, 63541670, 63370444, 63199679, 63029375, 62859529,
56 62690141, 62521210, 62352734, 62184711, 62017142, 61850024, 61683357, 61517138, 61351368, 61186044, 61021166,
57 60856731, 60692741, 60529192, 60366083, 60203414, 60041184, 59879391, 59718034, 59557111, 59396622, 59236566,
58 59076941, 58917746, 58758980, 58600642, 58442730, 58285245, 58128183, 57971545, 57815329, 57659533, 57504158,
59 57349201, 57194662, 57040539, 56886832, 56733539, 56580659, 56428190, 56276133, 56124486, 55973247, 55822415,
60 55671990, 55521971, 55372355, 55223143, 55074333, 54925924, 54777915, 54630305, 54483092, 54336276, 54189856,
61 54043830, 53898198, 53752959, 53608110, 53463652, 53319583, 53175903, 53032610, 52889702, 52747180, 52605042,
62 52463287, 52321914, 52180922, 52040310, 51900076, 51760221, 51620743, 51481640, 51342912, 51204558, 51066577,
63 50928968, 50791729, 50654860, 50518360, 50382228, 50246463, 50111064, 49976029, 49841359, 49707051, 49573105,
64 49439520, 49306295, 49173429, 49040922, 48908771, 48776976, 48645537, 48514451, 48383719, 48253339, 48123311,
65 47993633, 47864304, 47735324, 47606691, 47478405, 47350465, 47222869, 47095618, 46968709, 46842142, 46715916,
66 46590031, 46464484, 46339276, 46214406, 46089871, 45965673, 45841809, 45718279, 45595082, 45472216, 45349682,
67 45227478, 45105603, 44984057, 44862838, 44741946, 44621380, 44501139, 44381221, 44261627, 44142355, 44023404,
68 43904774, 43786464, 43668472, 43550798, 43433442, 43316402, 43199677, 43083266, 42967170, 42851386, 42735914,
69 42620753, 42505903, 42391362, 42277130, 42163206, 42049588, 41936277, 41823271, 41710570, 41598172, 41486077,
70 41374285, 41262793, 41151602, 41040711, 40930118, 40819823, 40709826, 40600125, 40490720, 40381609, 40272793,
71 40164269, 40056039, 39948099, 39840451, 39733093, 39626024, 39519243, 39412751, 39306545, 39200625, 39094991,
72 38989642, 38884576, 38779794, 38675294, 38571075, 38467138, 38363480, 38260102, 38157002, 38054180, 37951635,
73 37849367, 37747374, 37645656, 37544212, 37443042, 37342144, 37241518, 37141163, 37041078, 36941264, 36841718,
74 36742440, 36643430, 36544687, 36446210, 36347998, 36250051, 36152368, 36054948, 35957790, 35860895, 35764260,
75 35667886, 35571772, 35475916, 35380319, 35284980, 35189897, 35095071, 35000500, 34906184, 34812122, 34718314,
76 34624758, 34531454, 34438402, 34345601, 34253050, 34160748, 34068695, 33976890, 33885332, 33794021, 33702956,
77 33612137, 33521562, 33431231, 33341144, 33251299, 33161697, 33072336, 32983216, 32894336, 32805695, 32717294,
78 32629130, 32541204, 32453515, 32366063, 32278846, 32191864, 32105116, 32018602, 31932322, 31846273, 31760457,
79 31674872, 31589518, 31504393, 31419498, 31334832, 31250394, 31166183, 31082200, 30998442, 30914911, 30831604,
80 30748522, 30665664, 30583029, 30500617, 30418426, 30336458, 30254710, 30173183, 30091875, 30010786, 29929916,
81 29849263, 29768829, 29688610, 29608608, 29528822, 29449250, 29369893, 29290750, 29211820, 29133103, 29054598,
82 28976304, 28898222, 28820350, 28742687, 28665234, 28587990, 28510954, 28434125, 28357503, 28281088, 28204879,
83 28128875, 28053076, 27977482, 27902091, 27826903, 27751917, 27677134, 27602552, 27528172, 27453991, 27380011,
84 27306230, 27232648, 27159264, 27086078, 27013089, 26940296, 26867700, 26795300, 26723094, 26651083, 26579267,
85 26507643, 26436213, 26364975, 26293929, 26223075, 26152412, 26081939, 26011656, 25941562, 25871657, 25801940,
86 25732412, 25663071, 25593916, 25524948, 25456166, 25387569, 25319157, 25250929, 25182886, 25115025, 25047348,
87 24979852, 24912539, 24845407, 24778456, 24711686, 24645095, 24578684, 24512451, 24446397, 24380522, 24314823,
88 24249302, 24183957, 24118789, 24053796, 23988978, 23924335, 23859866, 23795570, 23731448, 23667499, 23603722,
89 23540117, 23476683, 23413421, 23350328, 23287406, 23224653, 23162070, 23099655, 23037408, 22975329, 22913417,
90 22851673, 22790094, 22728681, 22667434, 22606352, 22545435, 22484682, 22424092, 22363666, 22303402, 22243301,
91 22183362, 22123584, 22063968, 22004512, 21945216, 21886080, 21827104, 21768286, 21709627, 21651126, 21592783,
92 21534597, 21476567, 21418694, 21360977, 21303416, 21246009, 21188758, 21131660, 21074717, 21017926, 20961289,
93 20904805, 20848473, 20792292, 20736263, 20680385, 20624657, 20569080, 20513652, 20458374, 20403245, 20348264,
94 20293432, 20238747, 20184209, 20129819, 20075575, 20021477, 19967525, 19913719, 19860057, 19806540, 19753167,
95 19699938, 19646853, 19593910, 19541111, 19488453, 19435937, 19383563, 19331330, 19279238, 19227286, 19175474,
96 19123802, 19072269, 19020875, 18969619, 18918502, 18867522, 18816680, 18765974, 18715405, 18664973, 18614676,
97 18564515, 18514489, 18464598, 18414842, 18365219, 18315730, 18266375, 18217152, 18168062, 18119105, 18070279,
98 18021585, 17973022, 17924590, 17876289, 17828118, 17780076, 17732164, 17684381, 17636727, 17589201, 17541803,
99 17494533, 17447391, 17400375, 17353486, 17306724, 17260087, 17213577, 17167191, 17120930, 17074795, 17028783,
100 16982896, 16937132, 16891491, 16845974, 16800579, 16755306, 16710155, 16665126, 16620219, 16575432, 16530766,
101 16486221, 16441795, 16397490, 16353303, 16309236, 16265287, 16221457, 16177745, 16134151, 16090674, 16047314,
102 16004072, 15960945, 15917935, 15875041, 15832263, 15789599, 15747051, 15704617, 15662298, 15620093, 15578001,
103 15536023, 15494158, 15452406, 15410766, 15369239, 15327823, 15286519, 15245327, 15204245, 15163274, 15122414,
104 15081663, 15041023, 15000491, 14960070, 14919757, 14879552, 14839456, 14799468, 14759588, 14719815, 14680150,
105 14640591, 14601139, 14561793, 14522554, 14483420, 14444391, 14405468, 14366649, 14327935, 14289326, 14250820,
106 14212418, 14174120, 14135925, 14097833, 14059843, 14021956, 13984171, 13946488, 13908906, 13871426, 13834047,
107 13796768, 13759590, 13722512, 13685534, 13648655, 13611876, 13575196, 13538615, 13502132, 13465748, 13429462,
108 13393273, 13357183, 13321189, 13285292, 13249492, 13213789, 13178182, 13142670, 13107255, 13071934, 13036709,
109 13001579, 12966544, 12931603, 12896756, 12862003, 12827344, 12792778, 12758305, 12723925, 12689638, 12655443,
110 12621341, 12587330, 12553411, 12519583, 12485846, 12452201, 12418646, 12385181, 12351807, 12318522, 12285327,
111 12252222, 12219206, 12186279, 12153440, 12120690, 12088029, 12055455, 12022969, 11990571, 11958260, 11926036,
112 11893899, 11861848, 11829884, 11798006, 11766214, 11734507, 11702886, 11671350, 11639900, 11608533, 11577252,
113 11546055, 11514941, 11483912, 11452966, 11422104, 11391325, 11360628, 11330015, 11299484, 11269035, 11238668,
114 11208384, 11178180, 11148058, 11118018, 11088058, 11058179, 11028380, 10998662, 10969024, 10939466, 10909987,
115 10880588, 10851268, 10822027, 10792865, 10763781, 10734776, 10705849, 10677000, 10648228, 10619535, 10590918,
116 10562379, 10533916, 10505530, 10477221, 10448988, 10420831, 10392750, 10364745, 10336815, 10308960, 10281180,
117 10253476, 10225846, 10198290, 10170809, 10143401, 10116068, 10088808, 10061622, 10034509, 10007468, 9980501,
118 9953607, 9926785, 9900035, 9873357, 9846752, 9820217, 9793755, 9767364, 9741043, 9714794, 9688616,
119 9662508, 9636470, 9610503, 9584605, 9558778, 9533019, 9507331, 9481711, 9456161, 9430679, 9405266,
120 9379922, 9354646, 9329438, 9304298, 9279225, 9254221, 9229283, 9204413, 9179610, 9154874, 9130204,
121 9105601, 9081064, 9056593, 9032188, 9007849, 8983576, 8959368, 8935225, 8911147, 8887134, 8863186,
122 8839302, 8815483, 8791728, 8768037, 8744409, 8720846, 8697346, 8673909, 8650535, 8627225, 8603977,
123 8580792, 8557669, 8534608, 8511610, 8488674, 8465799, 8442987, 8420235, 8397545, 8374916, 8352348,
124 8329841, 8307395, 8285009, 8262683, 8240418, 8218212, 8196067, 8173981, 8151954, 8129987, 8108079,
125 8086230, 8064440, 8042709, 8021036, 7999422, 7977866, 7956368, 7934928, 7913545, 7892221, 7870954,
126 7849744, 7828591, 7807495, 7786456, 7765474, 7744548, 7723679, 7702866, 7682109, 7661408, 7640763,
127 7620173, 7599639, 7579160, 7558737, 7538368, 7518055, 7497796, 7477591, 7457441, 7437346, 7417304,
128 7397317, 7377383, 7357503, 7337677, 7317904, 7298185, 7278518, 7258905, 7239344, 7219836, 7200381,
129 7180978, 7161627, 7142329, 7123082, 7103888, 7084745, 7065654, 7046614, 7027625, 7008688, 6989802,
130 6970966, 6952181, 6933447, 6914764, 6896130, 6877547, 6859014, 6840531, 6822098, 6803715, 6785381,
131 6767096, 6748861, 6730675, 6712537, 6694449, 6676410, 6658419, 6640476, 6622582, 6604736, 6586938,
132 6569188, 6551486, 6533832, 6516225, 6498666, 6481154, 6463689, 6446272, 6428901, 6411577, 6394299,
133 6377069, 6359884, 6342746, 6325655, 6308609, 6291609, 6274655, 6257747, 6240884, 6224066, 6207294,
134 6190568, 6173886, 6157249, 6140657, 6124110, 6107607, 6091149, 6074735, 6058365, 6042040, 6025758,
135 6009521, 5993327, 5977177, 5961070, 5945007, 5928987, 5913010, 5897076, 5881185, 5865337, 5849532,
136 5833769, 5818049, 5802371, 5786735, 5771141, 5755590, 5740080, 5724612, 5709186, 5693802, 5678459,
137 5663157, 5647896, 5632677, 5617498, 5602361, 5587264, 5572208, 5557193, 5542218, 5527283, 5512389,
138 5497534, 5482720, 5467946, 5453211, 5438517, 5423861, 5409246, 5394669, 5380132, 5365635, 5351176,
139 5336756, 5322375, 5308033, 5293729, 5279464, 5265237, 5251049, 5236899, 5222787, 5208713, 5194677,
140 5180679, 5166719, 5152796, 5138911, 5125063, 5111252, 5097479, 5083743, 5070044, 5056382, 5042756,
141 5029167, 5015615, 5002100, 4988620, 4975178, 4961771, 4948400, 4935066, 4921767, 4908505, 4895278,
142 4882086, 4868931, 4855810, 4842725, 4829676, 4816661, 4803682, 4790737, 4777827, 4764953, 4752112,
143 4739307, 4726536, 4713799, 4701097, 4688429, 4675795, 4663195, 4650629, 4638097, 4625599, 4613134,
144 4600703, 4588306, 4575941, 4563611, 4551313, 4539049, 4526817, 4514619, 4502453, 4490320, 4478220,
145 4466153, 4454118, 4442115, 4430145, 4418207, 4406301, 4394428, 4382586, 4370776, 4358998, 4347252,
146 4335538, 4323855, 4312203, 4300583, 4288994, 4277437, 4265910, 4254415, 4242950, 4231517, 4220114,
147 4208742, 4197401, 4186090, 4174810, 4163560, 4152340, 4141151, 4129992, 4118863, 4107764, 4096694,
148 4085655, 4074645, 4063665, 4052715, 4041794, 4030903, 4020041, 4009208, 3998404, 3987630, 3976884,
149 3966168, 3955480, 3944821, 3934191, 3923590, 3913017, 3902472, 3891956, 3881469, 3871009, 3860578,
150 3850175, 3839800, 3829453, 3819133, 3808842, 3798578, 3788342, 3778134, 3767953, 3757799, 3747673,
151 3737574, 3727503, 3717458, 3707441, 3697450, 3687487, 3677550, 3667640, 3657757, 3647900, 3638070,
152 3628267, 3618490, 3608739, 3599014, 3589316, 3579644, 3569998, 3560378, 3550783, 3541215, 3531673,
153 3522156, 3512665, 3503199, 3493759, 3484344, 3474955, 3465591, 3456252, 3446939, 3437650, 3428387,
154 3419148, 3409935, 3400746, 3391582, 3382443, 3373328, 3364238, 3355172, 3346131, 3337114, 3328122,
155 3319153, 3310209, 3301289, 3292393, 3283521, 3274673, 3265849, 3257048, 3248271, 3239518, 3230789,
156 3222083, 3213400, 3204741, 3196105, 3187493, 3178903, 3170337, 3161794, 3153274, 3144777, 3136302,
157 3127851, 3119422, 3111016, 3102633, 3094272, 3085934, 3077619, 3069325, 3061054, 3052806, 3044579,
158 3036375, 3028193, 3020033, 3011895, 3003779, 2995684, 2987612, 2979561, 2971532, 2963525, 2955539,
159 2947575, 2939632, 2931710, 2923810, 2915931, 2908074, 2900237, 2892422, 2884628, 2876855, 2869102,
160 2861371, 2853660, 2845971, 2838302, 2830653, 2823025, 2815418, 2807832, 2800265, 2792719, 2785194,
161 2777689, 2770203, 2762739, 2755294, 2747869, 2740464, 2733080, 2725715, 2718370, 2711045, 2703739,
162 2696453, 2689187, 2681941, 2674714, 2667506, 2660318, 2653149, 2646000, 2638870, 2631759, 2624667,
163 2617594, 2610540, 2603506, 2596490, 2589493, 2582515, 2575556, 2568616, 2561694, 2554791, 2547907,
164 2541041, 2534194, 2527365, 2520554, 2513762, 2506988, 2500233, 2493495, 2486776, 2480075, 2473392,
165 2466727, 2460080, 2453450, 2446839, 2440246, 2433670, 2427112, 2420571, 2414049, 2407544, 2401056,
166 2394586, 2388133, 2381698, 2375280, 2368879, 2362496, 2356130, 2349780, 2343448, 2337134, 2330836,
167 2324555, 2318291, 2312044, 2305813, 2299600, 2293403, 2287223, 2281060, 2274913, 2268783, 2262669,
168 2256572, 2250491, 2244427, 2238379, 2232347, 2226331, 2220332, 2214349, 2208382, 2202431, 2196496,
169 2190577, 2184674, 2178787, 2172916, 2167060, 2161221, 2155397, 2149589, 2143796, 2138019, 2132258,
170 2126512, 2120782, 2115067, 2109368, 2103683, 2098015, 2092361, 2086723, 2081100, 2075492, 2069899,
171 2064321, 2058758, 2053211, 2047678, 2042160, 2036657, 2031169, 2025695, 2020237, 2014793, 2009364,
172 2003949, 1998549, 1993163, 1987792, 1982436, 1977094, 1971766, 1966453, 1961154, 1955869, 1950599,
173 1945342, 1940100, 1934872, 1929658, 1924458, 1919272, 1914101, 1908943, 1903799, 1898668, 1893552,
174 1888450, 1883361, 1878286, 1873224, 1868176, 1863142, 1858122, 1853115, 1848121, 1843141, 1838174,
175 1833221, 1828281, 1823354, 1818441, 1813540, 1808654, 1803780, 1798919, 1794072, 1789237, 1784416,
176 1779607, 1774812, 1770029, 1765259, 1760502, 1755758, 1751027, 1746309, 1741603, 1736910, 1732229,
177 1727561, 1722906, 1718263, 1713633, 1709015, 1704410, 1699817, 1695237, 1690669, 1686113, 1681569,
178 1677038, 1672519, 1668012, 1663517, 1659034, 1654564, 1650105, 1645659, 1641224, 1636801, 1632391,
179 1627992, 1623605, 1619230, 1614866, 1610515, 1606175, 1601847, 1597530, 1593225, 1588932, 1584650,
180 1580380, 1576122, 1571874, 1567639, 1563414, 1559201, 1555000, 1550810, 1546631, 1542463, 1538306,
181 1534161, 1530027, 1525904, 1521792, 1517691, 1513602, 1509523, 1505455, 1501399, 1497353, 1493318,
182 1489294, 1485281, 1481278, 1477287, 1473306, 1469336, 1465376, 1461427, 1457489, 1453562, 1449645,
183 1445738, 1441843, 1437957, 1434082, 1430218, 1426364, 1422520, 1418687, 1414864, 1411051, 1407249,
184 1403457, 1399675, 1395903, 1392142, 1388390, 1384649, 1380918, 1377197, 1373486, 1369784, 1366093,
185 1362412, 1358741, 1355079, 1351428, 1347786, 1344154, 1340532, 1336920, 1333317, 1329724, 1326141,
186 1322567, 1319004, 1315449, 1311904, 1308369, 1304844, 1301327, 1297821, 1294323, 1290836, 1287357,
187 1283888, 1280429, 1276978, 1273537, 1270105, 1266683, 1263269, 1259865, 1256470, 1253084, 1249708,
188 1246340, 1242982, 1239632, 1236292, 1232960, 1229638, 1226324, 1223020, 1219724, 1216437, 1213159,
189 1209890, 1206630, 1203378, 1200136, 1196902, 1193676, 1190460, 1187252, 1184052, 1180862, 1177680,
190 1174506, 1171341, 1168185, 1165037, 1161897, 1158767, 1155644, 1152530, 1149424, 1146327, 1143238,
191 1140157, 1137085, 1134021, 1130965, 1127917, 1124878, 1121846, 1118823, 1115809, 1112802, 1109803,
192 1106813, 1103830, 1100855, 1097889, 1094931, 1091980, 1089037, 1086103, 1083176, 1080257, 1077346,
193 1074443, 1071548, 1068660, 1065781, 1062909, 1060044, 1057188, 1054339, 1051498, 1048664, 1045839,
194 1043020, 1040210, 1037407, 1034611, 1031823, 1029043, 1026270, 1023504, 1020746, 1017996, 1015252,
195 1012517, 1009788, 1007067, 1004353, 1001647, 998948, 996256, 993571, 990894, 988224, 985561,
196 982905, 980256, 977615, 974980, 972353, 969733, 967120, 964514, 961915, 959323, 956737,
197 954159, 951588, 949024, 946467, 943916, 941373, 938836, 936306, 933783, 931267, 928757,
198 926254, 923758, 921269, 918787, 916311, 913842, 911379, 908923, 906474, 904031, 901595,
199 899166, 896743, 894326, 891916, 889513, 887116, 884725, 882341, 879963, 877592, 875227,
200 872869, 870517, 868171, 865831, 863498, 861171, 858851, 856536, 854228, 851926, 849631,
201 847341, 845058, 842781, 840510, 838245, 835986, 833733, 831487, 829246, 827011, 824783,
202 822560, 820344, 818133, 815929, 813730, 811537, 809350, 807169, 804994, 802825, 800662,
203 798504, 796352, 794206, 792066, 789932, 787803, 785680, 783563, 781452, 779346, 777246,
204 775151, 773062, 770979, 768902, 766830, 764763, 762703, 760647, 758598, 756553, 754515,
205 752482, 750454, 748432, 746415, 744403, 742397, 740397, 738402, 736412, 734428, 732448,
206 730475, 728506, 726543, 724585, 722633, 720686, 718744, 716807, 714875, 712949, 711028,
207 709112, 707201, 705295, 703394, 701499, 699609, 697723, 695843, 693968, 692098, 690233,
208 688373, 686518, 684668, 682823, 680983, 679148, 677318, 675493, 673673, 671857, 670047,
209 668241, 666441, 664645, 662854, 661067, 659286, 657510, 655738, 653971, 652208, 650451,
210 648698, 646950, 645207, 643468, 641734, 640005, 638280, 636560, 634845, 633134, 631428,
211 629727, 628030, 626337, 624650, 622966, 621288, 619613, 617944, 616279, 614618, 612962,
212 611310, 609663, 608020, 606381, 604747, 603118, 601492, 599872, 598255, 596643, 595035,
213 593432, 591833, 590238, 588647, 587061, 585479, 583901, 582328, 580759, 579194, 577633,
214 576076, 574524, 572976, 571432, 569892, 568356, 566825, 565297, 563774, 562255, 560740,
215 559229, 557722, 556219, 554720, 553225, 551734, 550248, 548765, 547286, 545811, 544341,
216 542874, 541411, 539952, 538497, 537046, 535599, 534155, 532716, 531280, 529849, 528421,
217 526997, 525577, 524161, 522748, 521340, 519935, 518534, 517136, 515743, 514353, 512967,
218 511585, 510206, 508831, 507460, 506093, 504729, 503369, 502012, 500660, 499310, 497965,
219 496623, 495285, 493950, 492619, 491292, 489968, 488648, 487331, 486018, 484708, 483402,
220 482099, 480800, 479504, 478212, 476924, 475638, 474357, 473078, 471804, 470532, 469264,
221 468000, 466739, 465481, 464227, 462976, 461728, 460484, 459243, 458005, 456771, 455540,
222 454313, 453089, 451868, 450650, 449436, 448225, 447017, 445812, 444611, 443413, 442218,
223 441026, 439838, 438653, 437470, 436292, 435116, 433943, 432774, 431608, 430445, 429285,
224 428128, 426974, 425824, 424676, 423532, 422391, 421252, 420117, 418985, 417856, 416730,
225 415607, 414487, 413370, 412256, 411146, 410038, 408933, 407831, 406732, 405636, 404543,
226 403453, 402365, 401281, 400200, 399121, 398046, 396973, 395903, 394837, 393773, 392712,
227 391653, 390598, 389545, 388496, 387449, 386405, 385363, 384325, 383289, 382257, 381226,
228 380199, 379175, 378153, 377134, 376118, 375104, 374093, 373085, 372080, 371077, 370077,
229 369080, 368085, 367094, 366104, 365118, 364134, 363153, 362174, 361198, 360225, 359254,
230 358286, 357321, 356358, 355397, 354440, 353485, 352532, 351582, 350635, 349690, 348748,
231 347808, 346871, 345936, 345004, 344074, 343147, 342222, 341300, 340380, 339463, 338548,
232 337636, 336726, 335819, 334914, 334011, 333111, 332214, 331318, 330426, 329535, 328647,
233 327762, 326878, 325997, 325119, 324243, 323369, 322498, 321629, 320762, 319898, 319036,
234 318176, 317319, 316463, 315611, 314760, 313912, 313066, 312222, 311381, 310542, 309705,
235 308871, 308038, 307208, 306380, 305555, 304731, 303910, 303091, 302275, 301460, 300648,
236 299838, 299030, 298224, 297420, 296619, 295819, 295022, 294227, 293434, 292644, 291855,
237 291069, 290284, 289502, 288722, 287944, 287168, 286394, 285622, 284853, 284085, 283320,
238 282556, 281795, 281035, 280278, 279523, 278770, 278018, 277269, 276522, 275777, 275034,
239 274293, 273553, 272816, 272081, 271348, 270617, 269888, 269160, 268435, 267712, 266990,
240 266271, 265553, 264838, 264124, 263412, 262702, 261994, 261289, 260584, 259882, 259182,
241 258483, 257787, 257092, 256399, 255709, 255020, 254332, 253647, 252963, 252282, 251602,
242 250924, 250248, 249573, 248901, 248230, 247561, 246894, 246229, 245565, 244904, 244244,
243 243586, 242929, 242275, 241622, 240971, 240321, 239674, 239028, 238384, 237741, 237101,
244 236462, 235825, 235189, 234555, 233923, 233293, 232664, 232037, 231412, 230788, 230166,
245 229546, 228928, 228311, 227696, 227082, 226470, 225860, 225251, 224644, 224039, 223435,
246 222833, 222233, 221634, 221036, 220441, 219847, 219254, 218664, 218074, 217487, 216901,
247 216316, 215733, 215152, 214572, 213994, 213417, 212842, 212269, 211697, 211126, 210557,
248 209990, 209424, 208860, 208297, 207735, 207176, 206617, 206061, 205505, 204952, 204399,
249 203849, 203299, 202751, 202205, 201660, 201117, 200575, 200034, 199495, 198958, 198422,
250 197887, 197354, 196822, 196291, 195762, 195235, 194709, 194184, 193661, 193139, 192619,
251 192100, 191582, 191066, 190551, 190037, 189525, 189014, 188505, 187997, 187491, 186985,
252 186481, 185979, 185478, 184978, 184479, 183982, 183487, 182992, 182499, 182007, 181517,
253 181028, 180540, 180053, 179568, 179084, 178602, 178120, 177640, 177162, 176684, 176208,
254 175733, 175260, 174788, 174317, 173847, 173378, 172911, 172445, 171981, 171517, 171055,
255 170594, 170134, 169676, 169219, 168763, 168308, 167854, 167402, 166951, 166501, 166052,
256 165605, 165159, 164713, 164270, 163827, 163386, 162945, 162506, 162068, 161632, 161196,
257 160762, 160328, 159896, 159465, 159036, 158607, 158180, 157754, 157328, 156904, 156482,
258 156060, 155639, 155220, 154802, 154385, 153969, 153554, 153140, 152727, 152316, 151905,
259 151496, 151088, 150681, 150275, 149870, 149466, 149063, 148661, 148261, 147861, 147463,
260 147065, 146669, 146274, 145880, 145487, 145094, 144703, 144314, 143925, 143537, 143150,
261 142764, 142380, 141996, 141613, 141232, 140851, 140472, 140093, 139715, 139339, 138964,
262 138589, 138216, 137843, 137472, 137101, 136732, 136363, 135996, 135629, 135264, 134899,
263 134536, 134173, 133812, 133451, 133092, 132733, 132375, 132019, 131663, 131308, 130954,
264 130601, 130249, 129898, 129548, 129199, 128851, 128504, 128158, 127812, 127468, 127124,
265 126782, 126440, 126099, 125760, 125421, 125083, 124746, 124410, 124074, 123740, 123407,
266 123074, 122742, 122412, 122082, 121753, 121425, 121097, 120771, 120446, 120121, 119797,
267 119475, 119153, 118832, 118511, 118192, 117873, 117556, 117239, 116923, 116608, 116294,
268 115980, 115668, 115356, 115045, 114735, 114426, 114118, 113810, 113504, 113198, 112893,
269 112589, 112285, 111983, 111681, 111380, 111080, 110780, 110482, 110184, 109887, 109591,
270 109296, 109001, 108708, 108415, 108122, 107831, 107541, 107251, 106962, 106674, 106386,
271 106099, 105813, 105528, 105244, 104960, 104678, 104395, 104114, 103834, 103554, 103275,
272 102996, 102719, 102442, 102166, 101891, 101616, 101342, 101069, 100797, 100525, 100254,
273 99984, 99715, 99446, 99178, 98911, 98644, 98378, 98113, 97849, 97585, 97322,
274 97060, 96799, 96538, 96278, 96018, 95759, 95501, 95244, 94987, 94731, 94476,
275 94222, 93968, 93714, 93462, 93210, 92959, 92708, 92459, 92209, 91961, 91713,
276 91466, 91219, 90974, 90729, 90484, 90240, 89997, 89754, 89513, 89271, 89031,
277 88791, 88552, 88313, 88075, 87838, 87601, 87365, 87130, 86895, 86661, 86427,
278 86194, 85962, 85730, 85499, 85269, 85039, 84810, 84581, 84353, 84126, 83899,
279 83673, 83448, 83223, 82999, 82775, 82552, 82330, 82108, 81886, 81666, 81446,
280 81226, 81007, 80789, 80571, 80354, 80138, 79922, 79706, 79492, 79277, 79064,
281 78851, 78638, 78426, 78215, 78004, 77794, 77584, 77375, 77167, 76959, 76752,
282 76545, 76338, 76133, 75928, 75723, 75519, 75315, 75112, 74910, 74708, 74507,
283 74306, 74106, 73906, 73707, 73508, 73310, 73113, 72916, 72719, 72523, 72328,
284 72133, 71939, 71745, 71551, 71359, 71166, 70975, 70783, 70593, 70402, 70213,
285 70023, 69835, 69646, 69459, 69272, 69085, 68899, 68713, 68528, 68343, 68159,
286 67975, 67792, 67610, 67427, 67246, 67065, 66884, 66704, 66524, 66345, 66166,
287 65987, 65810, 65632, 65455, 65279, 65103, 64928, 64753, 64578, 64404, 64231,
288 64058, 63885, 63713, 63541, 63370, 63199, 63029, 62859, 62690, 62521, 62352,
289 62184, 62017, 61850, 61683, 61517, 61351, 61186, 61021, 60856, 60692, 60529,
290 60366, 60203, 60041, 59879, 59718, 59557, 59396, 59236, 59076, 58917, 58758,
291 58600, 58442, 58285, 58128, 57971, 57815, 57659, 57504, 57349, 57194, 57040,
292 56886, 56733, 56580, 56428, 56276, 56124, 55973, 55822, 55671, 55521, 55372,
293 55223, 55074, 54925, 54777, 54630, 54483, 54336, 54189, 54043, 53898, 53752,
294 53608, 53463, 53319, 53175, 53032, 52889, 52747, 52605, 52463, 52321, 52180,
295 52040, 51900, 51760, 51620, 51481, 51342, 51204, 51066, 50928, 50791, 50654,
296 50518, 50382, 50246, 50111, 49976, 49841, 49707, 49573, 49439, 49306, 49173,
297 49040, 48908, 48776, 48645, 48514, 48383, 48253, 48123, 47993, 47864, 47735,
298 47606, 47478, 47350, 47222, 47095, 46968, 46842, 46715, 46590, 46464, 46339,
299 46214, 46089, 45965, 45841, 45718, 45595, 45472, 45349, 45227, 45105, 44984,
300 44862, 44741, 44621, 44501, 44381, 44261, 44142, 44023, 43904, 43786, 43668,
301 43550, 43433, 43316, 43199, 43083, 42967, 42851, 42735, 42620, 42505, 42391,
302 42277, 42163, 42049, 41936, 41823, 41710, 41598, 41486, 41374, 41262, 41151,
303 41040, 40930, 40819, 40709, 40600, 40490, 40381, 40272, 40164, 40056, 39948,
304 39840, 39733, 39626, 39519, 39412, 39306, 39200, 39094, 38989, 38884, 38779,
305 38675, 38571, 38467, 38363, 38260, 38157, 38054, 37951, 37849, 37747, 37645,
306 37544, 37443, 37342, 37241, 37141, 37041, 36941, 36841, 36742, 36643, 36544,
307 36446, 36347, 36250, 36152, 36054, 35957, 35860, 35764, 35667, 35571, 35475,
308 35380, 35284, 35189, 35095, 35000, 34906, 34812, 34718, 34624, 34531, 34438,
309 34345, 34253, 34160, 34068, 33976, 33885
310};
311
312static const short sindb_coeff[] ICONST_ATTR = {
313 2401, 2144, 1994, 1887, 1804, 1737, 1680, 1630, 1587, 1548, 1512, 1480, 1450,
314 1423, 1397, 1373, 1351, 1330, 1310, 1291, 1273, 1255, 1239, 1223, 1208, 1194,
315 1180, 1166, 1153, 1141, 1128, 1117, 1105, 1094, 1084, 1073, 1063, 1053, 1043,
316 1034, 1025, 1016, 1007, 999, 990, 982, 974, 967, 959, 952, 944, 937,
317 930, 923, 916, 910, 903, 897, 890, 884, 878, 872, 866, 860, 855,
318 849, 843, 838, 832, 827, 822, 817, 812, 807, 802, 797, 792, 787,
319 783, 778, 773, 769, 764, 760, 756, 751, 747, 743, 739, 734, 730,
320 726, 722, 718, 715, 711, 707, 703, 699, 696, 692, 688, 685, 681,
321 678, 674, 671, 667, 664, 661, 657, 654, 651, 648, 644, 641, 638,
322 635, 632, 629, 626, 623, 620, 617, 614, 611, 608, 605, 602, 599,
323 597, 594, 591, 588, 586, 583, 580, 578, 575, 572, 570, 567, 565,
324 562, 560, 557, 555, 552, 550, 547, 545, 542, 540, 538, 535, 533,
325 531, 528, 526, 524, 522, 519, 517, 515, 513, 510, 508, 506, 504,
326 502, 500, 498, 495, 493, 491, 489, 487, 485, 483, 481, 479, 477,
327 475, 473, 471, 469, 467, 465, 464, 462, 460, 458, 456, 454, 452,
328 450, 449, 447, 445, 443, 441, 440, 438, 436, 434, 433, 431, 429,
329 427, 426, 424, 422, 421, 419, 417, 416, 414, 412, 411, 409, 408,
330 406, 404, 403, 401, 400, 398, 396, 395, 393, 392, 390, 389, 387,
331 386, 384, 383, 381, 380, 378, 377, 375, 374, 372, 371, 370, 368,
332 367, 365, 364, 362, 361, 360, 358, 357, 355, 354, 353, 351, 350,
333 349, 347, 346, 345, 343, 342, 341, 339, 338, 337, 336, 334, 333,
334 332, 330, 329, 328, 327, 325, 324, 323, 322, 320, 319, 318, 317,
335 316, 314, 313, 312, 311, 310, 308, 307, 306, 305, 304, 303, 301,
336 300, 299, 298, 297, 296, 295, 293, 292, 291, 290, 289, 288, 287,
337 286, 285, 284, 282, 281, 280, 279, 278, 277, 276, 275, 274, 273,
338 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260,
339 259, 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, 247,
340 246, 245, 244, 243, 242, 241, 240, 240, 239, 238, 237, 236, 235,
341 234, 233, 232, 231, 230, 230, 229, 228, 227, 226, 225, 224, 223,
342 222, 222, 221, 220, 219, 218, 217, 216, 216, 215, 214, 213, 212,
343 211, 211, 210, 209, 208, 207, 206, 206, 205, 204, 203, 202, 202,
344 201, 200, 199, 198, 198, 197, 196, 195, 195, 194, 193, 192, 191,
345 191, 190, 189, 188, 188, 187, 186, 185, 185, 184, 183, 182, 182,
346 181, 180, 180, 179, 178, 177, 177, 176, 175, 174, 174, 173, 172,
347 172, 171, 170, 170, 169, 168, 167, 167, 166, 165, 165, 164, 163,
348 163, 162, 161, 161, 160, 159, 159, 158, 157, 157, 156, 155, 155,
349 154, 153, 153, 152, 151, 151, 150, 150, 149, 148, 148, 147, 146,
350 146, 145, 145, 144, 143, 143, 142, 141, 141, 140, 140, 139, 138,
351 138, 137, 137, 136, 135, 135, 134, 134, 133, 133, 132, 131, 131,
352 130, 130, 129, 129, 128, 127, 127, 126, 126, 125, 125, 124, 123,
353 123, 122, 122, 121, 121, 120, 120, 119, 119, 118, 117, 117, 116,
354 116, 115, 115, 114, 114, 113, 113, 112, 112, 111, 111, 110, 110,
355 109, 109, 108, 108, 107, 107, 106, 106, 105, 105, 104, 104, 103,
356 103, 102, 102, 101, 101, 100, 100, 99, 99, 98, 98, 97, 97,
357 96, 96, 95, 95, 94, 94, 94, 93, 93, 92, 92, 91, 91,
358 90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85,
359 85, 84, 84, 83, 83, 82, 82, 82, 81, 81, 80, 80, 79,
360 79, 79, 78, 78, 77, 77, 77, 76, 76, 75, 75, 75, 74,
361 74, 73, 73, 73, 72, 72, 71, 71, 71, 70, 70, 69, 69,
362 69, 68, 68, 68, 67, 67, 66, 66, 66, 65, 65, 65, 64,
363 64, 63, 63, 63, 62, 62, 62, 61, 61, 61, 60, 60, 59,
364 59, 59, 58, 58, 58, 57, 57, 57, 56, 56, 56, 55, 55,
365 55, 54, 54, 54, 53, 53, 53, 52, 52, 52, 51, 51, 51,
366 50, 50, 50, 49, 49, 49, 49, 48, 48, 48, 47, 47, 47,
367 46, 46, 46, 45, 45, 45, 45, 44, 44, 44, 43, 43, 43,
368 43, 42, 42, 42, 41, 41, 41, 40, 40, 40, 40, 39, 39,
369 39, 39, 38, 38, 38, 37, 37, 37, 37, 36, 36, 36, 36,
370 35, 35, 35, 35, 34, 34, 34, 34, 33, 33, 33, 32, 32,
371 32, 32, 31, 31, 31, 31, 31, 30, 30, 30, 30, 29, 29,
372 29, 29, 28, 28, 28, 28, 27, 27, 27, 27, 27, 26, 26,
373 26, 26, 25, 25, 25, 25, 25, 24, 24, 24, 24, 23, 23,
374 23, 23, 23, 22, 22, 22, 22, 22, 21, 21, 21, 21, 21,
375 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 18, 18,
376 18, 18, 18, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16,
377 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14,
378 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12,
379 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10,
380 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8,
381 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7,
382 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5,
383 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4,
384 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3,
385 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2,
386 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
387 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
388 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
391 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
392};
393
394
395static const short lfo_freq_coeff[] ICONST_ATTR = {
396 0, 3, 6, 9, 12, 15, 18, 21, 25, 28, 31, 34, 37,
397 40, 43, 46, 50, 53, 56, 59, 62, 65, 68, 71, 74, 78,
398 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 115, 118,
399 121, 124, 127, 130, 133, 136, 139, 142, 145, 148, 151, 154, 157,
400 160, 163, 166, 169, 172, 175, 178, 180, 183, 186, 189, 192, 195,
401 198, 201, 204, 207, 209, 212, 215, 218, 221, 224, 226, 229, 232,
402 235, 238, 240, 243, 246, 249, 251, 254, 257, 260, 262, 265, 268,
403 270, 273, 276, 278, 281, 283, 286, 289, 291, 294, 296, 299, 301,
404 304, 306, 309, 311, 314, 316, 319, 321, 324, 326, 328, 331, 333,
405 336, 338, 340, 343, 345, 347, 350, 352, 354, 356, 359, 361, 363,
406 365, 367, 370, 372, 374, 376, 378, 380, 382, 384, 386, 388, 391,
407 393, 395, 396, 398, 400, 402, 404, 406, 408, 410, 412, 414, 415,
408 417, 419, 421, 423, 424, 426, 428, 430, 431, 433, 435, 436, 438,
409 439, 441, 443, 444, 446, 447, 449, 450, 452, 453, 455, 456, 457,
410 459, 460, 461, 463, 464, 465, 467, 468, 469, 470, 472, 473, 474,
411 475, 476, 477, 478, 480, 481, 482, 483, 484, 485, 486, 487, 488,
412 488, 489, 490, 491, 492, 493, 494, 494, 495, 496, 497, 497, 498,
413 499, 499, 500, 501, 501, 502, 502, 503, 504, 504, 504, 505, 505,
414 506, 506, 507, 507, 507, 508, 508, 508, 509, 509, 509, 509, 510,
415 510, 510, 510, 510, 510, 510, 510, 510, 510, 511, 510, 510, 510,
416 510, 510, 510, 510, 510, 510, 510, 509, 509, 509, 509, 508, 508,
417 508, 507, 507, 507, 506, 506, 505, 505, 504, 504, 504, 503, 502,
418 502, 501, 501, 500, 499, 499, 498, 497, 497, 496, 495, 494, 494,
419 493, 492, 491, 490, 489, 488, 488, 487, 486, 485, 484, 483, 482,
420 481, 480, 478, 477, 476, 475, 474, 473, 472, 470, 469, 468, 467,
421 465, 464, 463, 461, 460, 459, 457, 456, 455, 453, 452, 450, 449,
422 447, 446, 444, 443, 441, 439, 438, 436, 435, 433, 431, 430, 428,
423 426, 424, 423, 421, 419, 417, 415, 414, 412, 410, 408, 406, 404,
424 402, 400, 398, 396, 395, 393, 391, 388, 386, 384, 382, 380, 378,
425 376, 374, 372, 370, 367, 365, 363, 361, 359, 356, 354, 352, 350,
426 347, 345, 343, 340, 338, 336, 333, 331, 328, 326, 324, 321, 319,
427 316, 314, 311, 309, 306, 304, 301, 299, 296, 294, 291, 289, 286,
428 283, 281, 278, 276, 273, 270, 268, 265, 262, 260, 257, 254, 251,
429 249, 246, 243, 240, 238, 235, 232, 229, 226, 224, 221, 218, 215,
430 212, 209, 207, 204, 201, 198, 195, 192, 189, 186, 183, 180, 178,
431 175, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, 142, 139,
432 136, 133, 130, 127, 124, 121, 118, 115, 111, 108, 105, 102, 99,
433 96, 93, 90, 87, 84, 81, 78, 74, 71, 68, 65, 62, 59,
434 56, 53, 50, 46, 43, 40, 37, 34, 31, 28, 25, 21, 18,
435 15, 12, 9, 6, 3, 0, -3, -6, -9, -12, -15, -18, -21,
436 -25, -28, -31, -34, -37, -40, -43, -46, -50, -53, -56, -59, -62,
437 -65, -68, -71, -74, -78, -81, -84, -87, -90, -93, -96, -99, -102,
438 -105, -108, -111, -115, -118, -121, -124, -127, -130, -133, -136, -139, -142,
439 -145, -148, -151, -154, -157, -160, -163, -166, -169, -172, -175, -178, -180,
440 -183, -186, -189, -192, -195, -198, -201, -204, -207, -209, -212, -215, -218,
441 -221, -224, -226, -229, -232, -235, -238, -240, -243, -246, -249, -251, -254,
442 -257, -260, -262, -265, -268, -270, -273, -276, -278, -281, -283, -286, -289,
443 -291, -294, -296, -299, -301, -304, -306, -309, -311, -314, -316, -319, -321,
444 -324, -326, -328, -331, -333, -336, -338, -340, -343, -345, -347, -350, -352,
445 -354, -356, -359, -361, -363, -365, -367, -370, -372, -374, -376, -378, -380,
446 -382, -384, -386, -388, -391, -393, -395, -396, -398, -400, -402, -404, -406,
447 -408, -410, -412, -414, -415, -417, -419, -421, -423, -424, -426, -428, -430,
448 -431, -433, -435, -436, -438, -439, -441, -443, -444, -446, -447, -449, -450,
449 -452, -453, -455, -456, -457, -459, -460, -461, -463, -464, -465, -467, -468,
450 -469, -470, -472, -473, -474, -475, -476, -477, -478, -480, -481, -482, -483,
451 -484, -485, -486, -487, -488, -488, -489, -490, -491, -492, -493, -494, -494,
452 -495, -496, -497, -497, -498, -499, -499, -500, -501, -501, -502, -502, -503,
453 -504, -504, -504, -505, -505, -506, -506, -507, -507, -507, -508, -508, -508,
454 -509, -509, -509, -509, -510, -510, -510, -510, -510, -510, -510, -510, -510,
455 -510, -511, -510, -510, -510, -510, -510, -510, -510, -510, -510, -510, -509,
456 -509, -509, -509, -508, -508, -508, -507, -507, -507, -506, -506, -505, -505,
457 -504, -504, -504, -503, -502, -502, -501, -501, -500, -499, -499, -498, -497,
458 -497, -496, -495, -494, -494, -493, -492, -491, -490, -489, -488, -488, -487,
459 -486, -485, -484, -483, -482, -481, -480, -478, -477, -476, -475, -474, -473,
460 -472, -470, -469, -468, -467, -465, -464, -463, -461, -460, -459, -457, -456,
461 -455, -453, -452, -450, -449, -447, -446, -444, -443, -441, -439, -438, -436,
462 -435, -433, -431, -430, -428, -426, -424, -423, -421, -419, -417, -415, -414,
463 -412, -410, -408, -406, -404, -402, -400, -398, -396, -395, -393, -391, -388,
464 -386, -384, -382, -380, -378, -376, -374, -372, -370, -367, -365, -363, -361,
465 -359, -356, -354, -352, -350, -347, -345, -343, -340, -338, -336, -333, -331,
466 -328, -326, -324, -321, -319, -316, -314, -311, -309, -306, -304, -301, -299,
467 -296, -294, -291, -289, -286, -283, -281, -278, -276, -273, -270, -268, -265,
468 -262, -260, -257, -254, -251, -249, -246, -243, -240, -238, -235, -232, -229,
469 -226, -224, -221, -218, -215, -212, -209, -207, -204, -201, -198, -195, -192,
470 -189, -186, -183, -180, -178, -175, -172, -169, -166, -163, -160, -157, -154,
471 -151, -148, -145, -142, -139, -136, -133, -130, -127, -124, -121, -118, -115,
472 -111, -108, -105, -102, -99, -96, -93, -90, -87, -84, -81, -78, -74,
473 -71, -68, -65, -62, -59, -56, -53, -50, -46, -43, -40, -37, -34,
474 -31, -28, -25, -21, -18, -15, -12, -9, -6, -3
475};
476
477static const short lfo_env_coeff[] ICONST_ATTR = {
478 251, 253, 254, 256, 257, 259, 260, 262, 264, 265, 267, 268, 270,
479 271, 273, 274, 276, 277, 279, 281, 282, 284, 285, 287, 288, 290,
480 291, 293, 294, 296, 297, 299, 300, 302, 303, 305, 306, 308, 309,
481 311, 312, 314, 315, 317, 318, 320, 321, 323, 324, 326, 327, 329,
482 330, 332, 333, 335, 336, 337, 339, 340, 342, 343, 345, 346, 348,
483 349, 350, 352, 353, 355, 356, 357, 359, 360, 362, 363, 364, 366,
484 367, 369, 370, 371, 373, 374, 375, 377, 378, 379, 381, 382, 383,
485 385, 386, 387, 389, 390, 391, 392, 394, 395, 396, 397, 399, 400,
486 401, 402, 404, 405, 406, 407, 409, 410, 411, 412, 413, 414, 416,
487 417, 418, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 430,
488 431, 432, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444,
489 445, 446, 447, 448, 449, 450, 451, 452, 453, 453, 454, 455, 456,
490 457, 458, 459, 460, 461, 461, 462, 463, 464, 465, 466, 466, 467,
491 468, 469, 469, 470, 471, 472, 473, 473, 474, 475, 475, 476, 477,
492 477, 478, 479, 479, 480, 481, 481, 482, 483, 483, 484, 484, 485,
493 486, 486, 487, 487, 488, 488, 489, 489, 490, 490, 491, 491, 492,
494 492, 493, 493, 493, 494, 494, 495, 495, 495, 496, 496, 497, 497,
495 497, 498, 498, 498, 498, 499, 499, 499, 500, 500, 500, 500, 500,
496 501, 501, 501, 501, 501, 502, 502, 502, 502, 502, 502, 502, 502,
497 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503,
498 503, 503, 503, 503, 503, 503, 502, 502, 502, 502, 502, 502, 502,
499 502, 501, 501, 501, 501, 501, 500, 500, 500, 500, 500, 499, 499,
500 499, 498, 498, 498, 498, 497, 497, 497, 496, 496, 495, 495, 495,
501 494, 494, 493, 493, 493, 492, 492, 491, 491, 490, 490, 489, 489,
502 488, 488, 487, 487, 486, 486, 485, 484, 484, 483, 483, 482, 481,
503 481, 480, 479, 479, 478, 477, 477, 476, 475, 475, 474, 473, 473,
504 472, 471, 470, 469, 469, 468, 467, 466, 466, 465, 464, 463, 462,
505 461, 461, 460, 459, 458, 457, 456, 455, 454, 453, 453, 452, 451,
506 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, 440, 439, 438,
507 437, 436, 435, 434, 432, 431, 430, 429, 428, 427, 426, 425, 424,
508 423, 421, 420, 419, 418, 417, 416, 414, 413, 412, 411, 410, 409,
509 407, 406, 405, 404, 402, 401, 400, 399, 397, 396, 395, 394, 392,
510 391, 390, 389, 387, 386, 385, 383, 382, 381, 379, 378, 377, 375,
511 374, 373, 371, 370, 369, 367, 366, 364, 363, 362, 360, 359, 357,
512 356, 355, 353, 352, 350, 349, 348, 346, 345, 343, 342, 340, 339,
513 337, 336, 335, 333, 332, 330, 329, 327, 326, 324, 323, 321, 320,
514 318, 317, 315, 314, 312, 311, 309, 308, 306, 305, 303, 302, 300,
515 299, 297, 296, 294, 293, 291, 290, 288, 287, 285, 284, 282, 281,
516 279, 277, 276, 274, 273, 271, 270, 268, 267, 265, 264, 262, 260,
517 259, 257, 256, 254, 253, 251, 250, 248, 247, 245, 244, 242, 240,
518 239, 237, 236, 234, 233, 231, 230, 228, 227, 225, 223, 222, 220,
519 219, 217, 216, 214, 213, 211, 210, 208, 207, 205, 204, 202, 201,
520 199, 198, 196, 195, 193, 192, 190, 189, 187, 186, 184, 183, 181,
521 180, 178, 177, 175, 174, 172, 171, 169, 168, 166, 165, 164, 162,
522 161, 159, 158, 156, 155, 153, 152, 151, 149, 148, 146, 145, 144,
523 142, 141, 139, 138, 137, 135, 134, 133, 131, 130, 129, 127, 126,
524 124, 123, 122, 120, 119, 118, 117, 115, 114, 113, 111, 110, 109,
525 108, 106, 105, 104, 103, 101, 100, 99, 98, 96, 95, 94, 93,
526 92, 90, 89, 88, 87, 86, 84, 83, 82, 81, 80, 79, 78,
527 77, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64,
528 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51,
529 50, 49, 48, 47, 46, 45, 45, 44, 43, 42, 41, 40, 39,
530 39, 38, 37, 36, 35, 35, 34, 33, 32, 31, 31, 30, 29,
531 29, 28, 27, 26, 26, 25, 24, 24, 23, 22, 22, 21, 20,
532 20, 19, 19, 18, 17, 17, 16, 16, 15, 15, 14, 14, 13,
533 13, 12, 12, 11, 11, 10, 10, 9, 9, 9, 8, 8, 7,
534 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3,
535 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
536 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
537 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
538 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
539 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6,
540 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11,
541 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18,
542 19, 19, 20, 20, 21, 22, 22, 23, 24, 24, 25, 26, 26,
543 27, 28, 29, 29, 30, 31, 31, 32, 33, 34, 35, 35, 36,
544 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 45, 46, 47,
545 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
546 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
547 74, 75, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88,
548 89, 90, 92, 93, 94, 95, 96, 98, 99, 100, 101, 103, 104,
549 105, 106, 108, 109, 110, 111, 113, 114, 115, 117, 118, 119, 120,
550 122, 123, 124, 126, 127, 129, 130, 131, 133, 134, 135, 137, 138,
551 139, 141, 142, 144, 145, 146, 148, 149, 151, 152, 153, 155, 156,
552 158, 159, 161, 162, 164, 165, 166, 168, 169, 171, 172, 174, 175,
553 177, 178, 180, 181, 183, 184, 186, 187, 189, 190, 192, 193, 195,
554 196, 198, 199, 201, 202, 204, 205, 207, 208, 210, 211, 213, 214,
555 216, 217, 219, 220, 222, 223, 225, 227, 228, 230, 231, 233, 234,
556 236, 237, 239, 240, 242, 244, 245, 247, 248, 250
557};
558
559#endif
diff --git a/apps/codecs/libgme/z80_cpu.c b/apps/codecs/libgme/z80_cpu.c
new file mode 100644
index 0000000000..9151350067
--- /dev/null
+++ b/apps/codecs/libgme/z80_cpu.c
@@ -0,0 +1,85 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "z80_cpu.h"
4
5/* Copyright (C) 2006-2008 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18// flags, named with hex value for clarity
19int const S80 = 0x80;
20int const Z40 = 0x40;
21int const F20 = 0x20;
22int const H10 = 0x10;
23int const F08 = 0x08;
24int const V04 = 0x04;
25int const P04 = 0x04;
26int const N02 = 0x02;
27int const C01 = 0x01;
28
29void Z80_init( struct Z80_Cpu* this )
30{
31 this->cpu_state = &this->cpu_state_;
32
33 int i;
34 for ( i = 0x100; --i >= 0; )
35 {
36 int p, even = 1;
37 for ( p = i; p; p >>= 1 )
38 even ^= p;
39 int n = (i & (S80 | F20 | F08)) | ((even & 1) * P04);
40 this->szpc [i] = n;
41 this->szpc [i + 0x100] = n | C01;
42 }
43 this->szpc [0x000] |= Z40;
44 this->szpc [0x100] |= Z40;
45}
46
47inline void set_page( struct Z80_Cpu* this, int i, void* write, void const* read )
48{
49 int offset = Z80_CPU_OFFSET( i * page_size );
50 byte * write2 = STATIC_CAST(byte *,write) - offset;
51 byte const* read2 = STATIC_CAST(byte const*,read ) - offset;
52 this->cpu_state_.write [i] = write2;
53 this->cpu_state_.read [i] = read2;
54 this->cpu_state->write [i] = write2;
55 this->cpu_state->read [i] = read2;
56}
57
58void Z80_reset( struct Z80_Cpu* this, void* unmapped_write, void const* unmapped_read )
59{
60 check( this->cpu_state == &this->cpu_state_ );
61 this->cpu_state = &this->cpu_state_;
62 this->cpu_state_.time = 0;
63 this->cpu_state_.base = 0;
64 this->end_time_ = 0;
65
66 int i;
67 for ( i = 0; i < page_count + 1; i++ )
68 set_page( this, i, unmapped_write, unmapped_read );
69
70 memset( &this->r, 0, sizeof this->r );
71}
72
73void Z80_map_mem( struct Z80_Cpu* this, addr_t start, int size, void* write, void const* read )
74{
75 // address range must begin and end on page boundaries
76 require( start % page_size == 0 );
77 require( size % page_size == 0 );
78 require( start + size <= 0x10000 );
79
80 int offset;
81 for ( offset = 0; offset < size; offset += page_size )
82 set_page( this, (start + offset) >> page_bits,
83 STATIC_CAST(char *,write) + offset,
84 STATIC_CAST(char const*,read ) + offset );
85}
diff --git a/apps/codecs/libgme/z80_cpu.h b/apps/codecs/libgme/z80_cpu.h
new file mode 100644
index 0000000000..15115b7e53
--- /dev/null
+++ b/apps/codecs/libgme/z80_cpu.h
@@ -0,0 +1,116 @@
1// Z80 CPU emulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef Z80_CPU_H
5#define Z80_CPU_H
6
7#include "blargg_source.h"
8#include "blargg_endian.h"
9
10typedef int cpu_time_t;
11typedef int addr_t;
12
13enum { page_bits = 10 };
14enum { page_size = 1 << page_bits };
15enum { page_count = 0x10000 / page_size };
16
17// Can read this far past end of memory
18enum { cpu_padding = 0x100 };
19
20// Can read this many bytes past end of a page
21enum { page_padding = 4 };
22
23#ifdef BLARGG_BIG_ENDIAN
24 struct regs_t { byte b,c, d,e, h,l, flags,a; };
25#else
26 struct regs_t { byte c,b, e,d, l,h, a,flags; };
27#endif
28// BOOST_STATIC_ASSERT( sizeof (regs_t) == 8 );
29
30struct pairs_t { uint16_t bc, de, hl, fa; };
31
32// Registers are not updated until run() returns
33struct registers_t {
34 uint16_t pc;
35 uint16_t sp;
36 uint16_t ix;
37 uint16_t iy;
38 union {
39 struct regs_t b; // b.b, b.c, b.d, b.e, b.h, b.l, b.flags, b.a
40 struct pairs_t w; // w.bc, w.de, w.hl. w.fa
41 };
42 union {
43 struct regs_t b;
44 struct pairs_t w;
45 } alt;
46 byte iff1;
47 byte iff2;
48 byte r;
49 byte i;
50 byte im;
51};
52
53struct cpu_state_t {
54 byte const* read [page_count + 1];
55 byte * write [page_count + 1];
56 cpu_time_t base;
57 cpu_time_t time;
58};
59
60struct Z80_Cpu {
61 byte szpc [0x200];
62 cpu_time_t end_time_;
63
64 struct cpu_state_t* cpu_state; // points to cpu_state_ or a local copy within run()
65 struct cpu_state_t cpu_state_;
66
67 struct registers_t r;
68};
69
70void Z80_init( struct Z80_Cpu* this );
71
72// Clears registers and maps all pages to unmapped
73void Z80_reset( struct Z80_Cpu* this, void* unmapped_write, void const* unmapped_read );
74
75// TODO: split mapping out of CPU
76
77// Maps memory. Start and size must be multiple of page_size.
78void Z80_map_mem( struct Z80_Cpu* this, addr_t addr, int size, void* write, void const* read );
79
80// Time of beginning of next instruction
81static inline cpu_time_t Z80_time( struct Z80_Cpu* this ) { return this->cpu_state->time + this->cpu_state->base; }
82
83// Alter current time
84static inline void Z80_set_time( struct Z80_Cpu* this, cpu_time_t t ) { this->cpu_state->time = t - this->cpu_state->base; }
85static inline void Z80_adjust_time( struct Z80_Cpu* this, int delta ) { this->cpu_state->time += delta; }
86
87#ifdef BLARGG_NONPORTABLE
88 #define Z80_CPU_OFFSET( addr ) (addr)
89#else
90 #define Z80_CPU_OFFSET( addr ) ((addr) & (page_size - 1))
91#endif
92
93// Maps address to pointer to that byte
94static inline byte* Z80_write( struct Z80_Cpu* this, addr_t addr )
95{
96 return this->cpu_state->write [(unsigned) addr >> page_bits] + Z80_CPU_OFFSET( addr );
97}
98
99static inline byte const* Z80_read( struct Z80_Cpu* this, addr_t addr )
100{
101 return this->cpu_state->read [(unsigned) addr >> page_bits] + Z80_CPU_OFFSET( addr );
102}
103
104static inline void Z80_map_mem_rw( struct Z80_Cpu* this, addr_t addr, int size, void* p )
105{
106 Z80_map_mem( this, addr, size, p, p );
107}
108
109static inline void Z80_set_end_time( struct Z80_Cpu* this, cpu_time_t t )
110{
111 cpu_time_t delta = this->cpu_state->base - t;
112 this->cpu_state->base = t;
113 this->cpu_state->time += delta;
114}
115
116#endif
diff --git a/apps/codecs/libgme/z80_cpu_run.h b/apps/codecs/libgme/z80_cpu_run.h
new file mode 100644
index 0000000000..18195ac92b
--- /dev/null
+++ b/apps/codecs/libgme/z80_cpu_run.h
@@ -0,0 +1,1696 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3// Last validated with zexall 2009.12.05.
4// Doesn't implement the R register or immediate interrupt after EI.
5// Address wrap-around isn't completely correct, but is prevented from crashing emulator.
6// 16-bit memory accesses are made directly to mapped memory, instead of using macro.
7
8#if 0
9/* Define these macros in the source file before #including this file.
10- Parameters might be expressions, so they are best evaluated only once,
11though they NEVER have side-effects, so multiple evaluation is OK.
12- Output parameters might be a multiple-assignment expression like "a=x",
13so they must NOT be parenthesized.
14- Except where noted, time() and related functions will NOT work
15correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and
16CACHE_TIME() the normal time changing functions can be used.
17- Macros "returning" void may use a {} statement block. */
18
19 // 0 <= addr <= 0xFFFF + 0x100
20 // Optional; default uses whatever was set with map_mem()
21 int READ_MEM( addr_t );
22 void WRITE_MEM( addr_t, int data );
23
24 // 0 <= port <= 0xFFFF (apparently upper 8 bits are output by hardware)
25 void OUT_PORT( int port, int data );
26 int IN_PORT int port );
27
28 // Reference to Z80_Cpu object used for emulation
29 #define CPU cpu
30
31// The following can be used within macros:
32
33 // Current time
34 time_t TIME();
35
36 // Allows use of time functions
37 void FLUSH_TIME();
38
39 // Must be used before end of macro if FLUSH_TIME() was used earlier
40 void CACHE_TIME();
41
42// Configuration (optional; commented behavior if defined)
43
44 // Optimizes as if map_mem( 0, 0x10000, FLAT_MEM, FLAT_MEM ) is always in effect
45 #define FLAT_MEM my_mem_array
46
47 // If RST 7 ($FF) is encountered and PC = IDLE_ADDR, stops execution
48 #define IDLE_ADDR 0x1234
49
50 // Expanded just before beginning of code, to help debugger
51 #define CPU_BEGIN void my_run_cpu() {
52
53#endif
54
55/* Copyright (C) 2006-2008 Shay Green. This module is free software; you
56can redistribute it and/or modify it under the terms of the GNU Lesser
57General Public License as published by the Free Software Foundation; either
58version 2.1 of the License, or (at your option) any later version. This
59module is distributed in the hope that it will be useful, but WITHOUT ANY
60WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
61FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
62details. You should have received a copy of the GNU Lesser General Public
63License along with this module; if not, write to the Free Software Foundation,
64Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
65
66#ifdef CPU_BEGIN
67 CPU_BEGIN
68#endif
69
70#define R cpu->r
71
72// flags, named with hex value for clarity
73int const S80 = 0x80;
74int const Z40 = 0x40;
75int const F20 = 0x20;
76int const H10 = 0x10;
77int const F08 = 0x08;
78int const V04 = 0x04;
79int const P04 = 0x04;
80int const N02 = 0x02;
81int const C01 = 0x01;
82
83#define SZ28P( n ) cpu->szpc [n]
84#define SZ28PC( n ) cpu->szpc [n]
85#define SZ28C( n ) (cpu->szpc [n] & ~P04)
86#define SZ28( n ) SZ28C( n )
87
88#define SET_R( n ) (void) (R.r = n)
89#define GET_R() (R.r)
90
91// Time
92#define TIME() (s_time + s.base)
93#define FLUSH_TIME() {s.time = s_time;}
94#define CACHE_TIME() {s_time = s.time;}
95
96// Memory
97#define RW_MEM( addr, rw ) RW_PAGE( addr, rw ) [RW_OFFSET( addr )]
98#define READ_CODE( addr ) RW_MEM( addr, read )
99
100#ifdef FLAT_MEM
101 #define RW_PAGE( addr, rw ) FLAT_MEM
102 #define RW_OFFSET( addr ) (addr)
103 #define INSTR( off, addr ) READ_CODE( addr )
104#else
105 #define RW_PAGE( addr, rw ) s.rw [(unsigned) (addr) >> page_bits]
106 #define RW_OFFSET( addr ) Z80_CPU_OFFSET( addr )
107 #define INSTR( off, addr ) instr [off]
108#endif
109
110#ifndef READ_MEM
111 #define READ_MEM( addr ) RW_MEM( addr, read )
112#endif
113
114#ifndef WRITE_MEM
115 #define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data)
116#endif
117
118#define READ_WORD( addr ) GET_LE16( &RW_MEM( addr, read ) )
119#define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data )
120
121// Truncation
122#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */
123#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */
124#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */
125
126// Misc
127#define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e
128#define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f
129#define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g
130#define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h
131
132#ifdef BLARGG_BIG_ENDIAN
133 #define R8( n, offset ) ((r.r8_ - offset) [n])
134#elif BLARGG_LITTLE_ENDIAN
135 #define R8( n, offset ) ((r.r8_ - offset) [(n) ^ 1])
136#else
137 #error "Byte order of CPU must be known"
138#endif
139
140#define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)])
141
142#define EX( x, y ) \
143 {\
144 int temp = x;\
145 x = y;\
146 y = temp;\
147 }
148
149#define EXX( name ) \
150 EX( R.alt.name, r.name )
151
152bool warning = false;
153{
154 struct cpu_state_t s;
155 #ifdef FLAT_MEM
156 s.base = cpu->cpu_state_.base;
157 #else
158 s = cpu->cpu_state_;
159 #endif
160 cpu->cpu_state = &s;
161
162
163 union r_t {
164 struct regs_t b;
165 struct pairs_t w;
166 byte r8_ [8]; // indexed
167 uint16_t r16_ [4];
168 } r;
169 r.b = R.b;
170
171 cpu_time_t s_time = cpu->cpu_state_.time;
172 int pc = R.pc;
173 int sp = R.sp;
174 int ix = R.ix; // TODO: keep in memory for direct access?
175 int iy = R.iy;
176 int flags = R.b.flags;
177
178 //goto loop; // confuses optimizer
179 s_time += 7;
180 pc -= 2;
181
182call_not_taken:
183 s_time -= 7;
184jp_not_taken:
185 pc += 2;
186loop:
187
188 check( (unsigned) pc < 0x10000 + 1 ); // +1 so emulator can catch wrap-around
189 check( (unsigned) sp < 0x10000 );
190 check( (unsigned) flags < 0x100 );
191 check( (unsigned) ix < 0x10000 );
192 check( (unsigned) iy < 0x10000 );
193
194 byte const* instr = RW_PAGE( pc, read );
195
196 int opcode;
197
198 if ( RW_OFFSET( ~0 ) == ~0 )
199 {
200 opcode = instr [RW_OFFSET( pc )];
201 pc++;
202 instr += RW_OFFSET( pc );
203 }
204 else
205 {
206 instr += RW_OFFSET( pc );
207 opcode = *instr++;
208 pc++;
209 }
210
211 static byte const clock_table [256 * 2] = {
212 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
213 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0
214 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1
215 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, // 2
216 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, // 3
217 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4
218 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5
219 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6
220 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7
221 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8
222 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9
223 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A
224 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B
225 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C
226 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D
227 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E
228 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F
229
230 // high four bits are $ED time - 8, low four bits are $DD/$FD time - 8
231 //0 1 2 3 4 5 6 7 8 9 A B C D E F
232 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
233 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
234 0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00,
235 0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
236 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,
237 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,
238 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,
239 0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00,
240 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,
241 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,
242 0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,
243 0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,
244 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,
245 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
246 0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
247 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
248 };
249
250 if ( s_time >= 0 )
251 goto out_of_time;
252 s_time += clock_table [opcode];
253
254 #ifdef Z80_CPU_LOG_H
255 //log_opcode( opcode, READ_CODE( pc ) );
256 z80_cpu_log( "log.txt", pc - 1, opcode, READ_CODE( pc ),
257 READ_CODE( pc + 1 ), READ_CODE( pc + 2 ) );
258 z80_log_regs( r.b.a, r.w.bc, r.w.de, r.w.hl, sp, ix, iy );
259 #endif
260
261#define GET_ADDR() GET_LE16( &INSTR( 0, pc ) )
262
263 int data;
264 data = INSTR( 0, pc );
265
266 switch ( opcode )
267 {
268// Common
269
270 case 0x00: // NOP
271 CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc.
272 goto loop;
273
274 case 0x08:{// EX AF,AF'
275 EXX( b.a );
276 EX( R.alt.b.flags, flags );
277 goto loop;
278 }
279
280 case 0xD3: // OUT (imm),A
281 pc++;
282 OUT_PORT( (data + r.b.a * 0x100), r.b.a );
283 goto loop;
284
285 case 0x2E: // LD L,imm
286 pc++;
287 r.b.l = data;
288 goto loop;
289
290 case 0x3E: // LD A,imm
291 pc++;
292 r.b.a = data;
293 goto loop;
294
295 case 0x3A:{// LD A,(addr)
296 int addr = GET_ADDR();
297 pc += 2;
298 r.b.a = READ_MEM( addr );
299 goto loop;
300 }
301
302// Conditional
303
304#define ZERO (flags & Z40)
305#define CARRY (flags & C01)
306#define EVEN (flags & P04)
307#define MINUS (flags & S80)
308
309// JR
310// TODO: more efficient way to handle negative branch that wraps PC around
311#define JR_( cond, clocks ) {\
312 pc++;\
313 if ( !(cond) )\
314 goto loop;\
315 int offset = SBYTE( data );\
316 pc = WORD( pc + offset );\
317 s_time += clocks;\
318 goto loop;\
319}
320
321#define JR( cond ) JR_( cond, 5 )
322
323 case 0x20: JR( !ZERO ) // JR NZ,disp
324 case 0x28: JR( ZERO ) // JR Z,disp
325 case 0x30: JR( !CARRY ) // JR NC,disp
326 case 0x38: JR( CARRY ) // JR C,disp
327 case 0x18: JR_( true,0) // JR disp
328
329 case 0x10:{// DJNZ disp
330 int temp = r.b.b - 1;
331 r.b.b = temp;
332 JR( temp )
333 }
334
335// JP
336#define JP( cond ) \
337 if ( !(cond) )\
338 goto jp_not_taken;\
339 pc = GET_ADDR();\
340 goto loop;
341
342 case 0xC2: JP( !ZERO ) // JP NZ,addr
343 case 0xCA: JP( ZERO ) // JP Z,addr
344 case 0xD2: JP( !CARRY ) // JP NC,addr
345 case 0xDA: JP( CARRY ) // JP C,addr
346 case 0xE2: JP( !EVEN ) // JP PO,addr
347 case 0xEA: JP( EVEN ) // JP PE,addr
348 case 0xF2: JP( !MINUS ) // JP P,addr
349 case 0xFA: JP( MINUS ) // JP M,addr
350
351 case 0xC3: // JP addr
352 pc = GET_ADDR();
353 goto loop;
354
355 case 0xE9: // JP HL
356 pc = r.w.hl;
357 goto loop;
358
359// RET
360#define RET( cond ) \
361 if ( cond )\
362 goto ret_taken;\
363 s_time -= 6;\
364 goto loop;
365
366 case 0xC0: RET( !ZERO ) // RET NZ
367 case 0xC8: RET( ZERO ) // RET Z
368 case 0xD0: RET( !CARRY ) // RET NC
369 case 0xD8: RET( CARRY ) // RET C
370 case 0xE0: RET( !EVEN ) // RET PO
371 case 0xE8: RET( EVEN ) // RET PE
372 case 0xF0: RET( !MINUS ) // RET P
373 case 0xF8: RET( MINUS ) // RET M
374
375 case 0xC9: // RET
376 ret_taken:
377 pc = READ_WORD( sp );
378 sp = WORD( sp + 2 );
379 goto loop;
380
381// CALL
382#define CALL( cond ) \
383 if ( cond )\
384 goto call_taken;\
385 goto call_not_taken;
386
387 case 0xC4: CALL( !ZERO ) // CALL NZ,addr
388 case 0xCC: CALL( ZERO ) // CALL Z,addr
389 case 0xD4: CALL( !CARRY ) // CALL NC,addr
390 case 0xDC: CALL( CARRY ) // CALL C,addr
391 case 0xE4: CALL( !EVEN ) // CALL PO,addr
392 case 0xEC: CALL( EVEN ) // CALL PE,addr
393 case 0xF4: CALL( !MINUS ) // CALL P,addr
394 case 0xFC: CALL( MINUS ) // CALL M,addr
395
396 case 0xCD:{// CALL addr
397 call_taken: {
398 int addr = pc + 2;
399 pc = GET_ADDR();
400 sp = WORD( sp - 2 );
401 WRITE_WORD( sp, addr );
402 goto loop;
403 }
404 }
405
406 case 0xFF: // RST
407 #ifdef IDLE_ADDR
408 if ( pc == IDLE_ADDR + 1 )
409 goto hit_idle_addr;
410 #else
411 if ( pc > 0x10000 )
412 {
413 pc = WORD( pc - 1 );
414 s_time -= 11;
415 goto loop;
416 }
417 #endif
418 CASE7( C7, CF, D7, DF, E7, EF, F7 ):
419 data = pc;
420 pc = opcode & 0x38;
421 #ifdef RST_BASE
422 pc += RST_BASE;
423 #endif
424 goto push_data;
425
426// PUSH/POP
427 case 0xF5: // PUSH AF
428 data = r.b.a * 0x100u + flags;
429 goto push_data;
430
431 case 0xC5: // PUSH BC
432 case 0xD5: // PUSH DE
433 case 0xE5: // PUSH HL
434 data = R16( opcode, 4, 0xC5 );
435 push_data:
436 sp = WORD( sp - 2 );
437 WRITE_WORD( sp, data );
438 goto loop;
439
440 case 0xF1: // POP AF
441 flags = READ_MEM( sp );
442 r.b.a = READ_MEM( (sp + 1) );
443 sp = WORD( sp + 2 );
444 goto loop;
445
446 case 0xC1: // POP BC
447 case 0xD1: // POP DE
448 case 0xE1: // POP HL
449 R16( opcode, 4, 0xC1 ) = READ_WORD( sp );
450 sp = WORD( sp + 2 );
451 goto loop;
452
453// ADC/ADD/SBC/SUB
454 case 0x96: // SUB (HL)
455 case 0x86: // ADD (HL)
456 flags &= ~C01;
457 case 0x9E: // SBC (HL)
458 case 0x8E: // ADC (HL)
459 data = READ_MEM( r.w.hl );
460 goto adc_data;
461
462 case 0xD6: // SUB A,imm
463 case 0xC6: // ADD imm
464 flags &= ~C01;
465 case 0xDE: // SBC A,imm
466 case 0xCE: // ADC imm
467 pc++;
468 goto adc_data;
469
470 CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r
471 CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r
472 flags &= ~C01;
473 CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r
474 CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r
475 data = R8( opcode & 7, 0 );
476 adc_data: {
477 int result = data + (flags & C01);
478 data ^= r.b.a;
479 flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes
480 if ( flags )
481 result = -result;
482 result += r.b.a;
483 data ^= result;
484 flags +=(data & H10) +
485 ((data + 0x80) >> 6 & V04) +
486 SZ28C( result & 0x1FF );
487 r.b.a = result;
488 goto loop;
489 }
490
491// CP
492 case 0xBE: // CP (HL)
493 data = READ_MEM( r.w.hl );
494 goto cp_data;
495
496 case 0xFE: // CP imm
497 pc++;
498 goto cp_data;
499
500 CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r
501 data = R8( opcode, 0xB8 );
502 cp_data: {
503 int result = r.b.a - data;
504 flags = N02 + (data & (F20 | F08)) + (result >> 8 & C01);
505 data ^= r.b.a;
506 flags +=(((result ^ r.b.a) & data) >> 5 & V04) +
507 (((data & H10) ^ result) & (S80 | H10));
508 if ( BYTE( result ) )
509 goto loop;
510 flags += Z40;
511 goto loop;
512 }
513
514// ADD HL,r.w
515
516 case 0x39: // ADD HL,SP
517 data = sp;
518 goto add_hl_data;
519
520 case 0x09: // ADD HL,BC
521 case 0x19: // ADD HL,DE
522 case 0x29: // ADD HL,HL
523 data = R16( opcode, 4, 0x09 );
524 add_hl_data: {
525 int sum = r.w.hl + data;
526 data ^= r.w.hl;
527 r.w.hl = sum;
528 flags = (flags & (S80 | Z40 | V04)) +
529 (sum >> 16) +
530 (sum >> 8 & (F20 | F08)) +
531 ((data ^ sum) >> 8 & H10);
532 goto loop;
533 }
534
535 case 0x27:{// DAA
536 int a = r.b.a;
537 if ( a > 0x99 )
538 flags |= C01;
539
540 int adjust = 0x60 * (flags & C01);
541
542 if ( flags & H10 || (a & 0x0F) > 9 )
543 adjust += 0x06;
544
545 if ( flags & N02 )
546 adjust = -adjust;
547 a += adjust;
548
549 flags = (flags & (C01 | N02)) +
550 ((r.b.a ^ a) & H10) +
551 SZ28P( BYTE( a ) );
552 r.b.a = a;
553 goto loop;
554 }
555
556// INC/DEC
557 case 0x34: // INC (HL)
558 data = READ_MEM( r.w.hl ) + 1;
559 WRITE_MEM( r.w.hl, data );
560 goto inc_set_flags;
561
562 CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r
563 data = ++R8( opcode >> 3, 0 );
564 inc_set_flags:
565 flags = (flags & C01) +
566 (((data & 0x0F) - 1) & H10) +
567 SZ28( BYTE( data ) );
568 if ( data != 0x80 )
569 goto loop;
570 flags += V04;
571 goto loop;
572
573 case 0x35: // DEC (HL)
574 data = READ_MEM( r.w.hl ) - 1;
575 WRITE_MEM( r.w.hl, data );
576 goto dec_set_flags;
577
578 CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r
579 data = --R8( opcode >> 3, 0 );
580 dec_set_flags:
581 flags = (flags & C01) + N02 +
582 (((data & 0x0F) + 1) & H10) +
583 SZ28( BYTE( data ) );
584 if ( data != 0x7F )
585 goto loop;
586 flags += V04;
587 goto loop;
588
589 case 0x03: // INC BC
590 case 0x13: // INC DE
591 case 0x23: // INC HL
592 R16( opcode, 4, 0x03 )++;
593 goto loop;
594
595 case 0x33: // INC SP
596 sp = WORD( sp + 1 );
597 goto loop;
598
599 case 0x0B: // DEC BC
600 case 0x1B: // DEC DE
601 case 0x2B: // DEC HL
602 R16( opcode, 4, 0x0B )--;
603 goto loop;
604
605 case 0x3B: // DEC SP
606 sp = WORD( sp - 1 );
607 goto loop;
608
609// AND
610 case 0xA6: // AND (HL)
611 data = READ_MEM( r.w.hl );
612 goto and_data;
613
614 case 0xE6: // AND imm
615 pc++;
616 goto and_data;
617
618 CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r
619 data = R8( opcode, 0xA0 );
620 and_data:
621 r.b.a &= data;
622 flags = SZ28P( r.b.a ) + H10;
623 goto loop;
624
625// OR
626 case 0xB6: // OR (HL)
627 data = READ_MEM( r.w.hl );
628 goto or_data;
629
630 case 0xF6: // OR imm
631 pc++;
632 goto or_data;
633
634 CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r
635 data = R8( opcode, 0xB0 );
636 or_data:
637 r.b.a |= data;
638 flags = SZ28P( r.b.a );
639 goto loop;
640
641// XOR
642 case 0xAE: // XOR (HL)
643 data = READ_MEM( r.w.hl );
644 goto xor_data;
645
646 case 0xEE: // XOR imm
647 pc++;
648 goto xor_data;
649
650 CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r
651 data = R8( opcode, 0xA8 );
652 xor_data:
653 r.b.a ^= data;
654 flags = SZ28P( r.b.a );
655 goto loop;
656
657// LD
658 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r
659 WRITE_MEM( r.w.hl, R8( opcode, 0x70 ) );
660 goto loop;
661
662 CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r
663 CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r
664 CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r
665 CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r
666 CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r
667 CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r
668 CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r
669 R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 );
670 goto loop;
671
672 CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm
673 R8( opcode >> 3, 0 ) = data;
674 pc++;
675 goto loop;
676
677 case 0x36: // LD (HL),imm
678 pc++;
679 WRITE_MEM( r.w.hl, data );
680 goto loop;
681
682 CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL)
683 R8( opcode >> 3, 8 ) = READ_MEM( r.w.hl );
684 goto loop;
685
686 case 0x01: // LD r.w,imm
687 case 0x11:
688 case 0x21:
689 R16( opcode, 4, 0x01 ) = GET_ADDR();
690 pc += 2;
691 goto loop;
692
693 case 0x31: // LD sp,imm
694 sp = GET_ADDR();
695 pc += 2;
696 goto loop;
697
698 case 0x2A:{// LD HL,(addr)
699 int addr = GET_ADDR();
700 pc += 2;
701 r.w.hl = READ_WORD( addr );
702 goto loop;
703 }
704
705 case 0x32:{// LD (addr),A
706 int addr = GET_ADDR();
707 pc += 2;
708 WRITE_MEM( addr, r.b.a );
709 goto loop;
710 }
711
712 case 0x22:{// LD (addr),HL
713 int addr = GET_ADDR();
714 pc += 2;
715 WRITE_WORD( addr, r.w.hl );
716 goto loop;
717 }
718
719 case 0x02: // LD (BC),A
720 case 0x12: // LD (DE),A
721 WRITE_MEM( R16( opcode, 4, 0x02 ), r.b.a );
722 goto loop;
723
724 case 0x0A: // LD A,(BC)
725 case 0x1A: // LD A,(DE)
726 r.b.a = READ_MEM( R16( opcode, 4, 0x0A ) );
727 goto loop;
728
729 case 0xF9: // LD SP,HL
730 sp = r.w.hl;
731 goto loop;
732
733// Rotate
734
735 case 0x07:{// RLCA
736 int temp = r.b.a;
737 temp = (temp << 1) + (temp >> 7);
738 flags = (flags & (S80 | Z40 | P04)) +
739 (temp & (F20 | F08 | C01));
740 r.b.a = temp;
741 goto loop;
742 }
743
744 case 0x0F:{// RRCA
745 int temp = r.b.a;
746 flags = (flags & (S80 | Z40 | P04)) +
747 (temp & C01);
748 temp = (temp << 7) + (temp >> 1);
749 flags += temp & (F20 | F08);
750 r.b.a = temp;
751 goto loop;
752 }
753
754 case 0x17:{// RLA
755 int temp = (r.b.a << 1) + (flags & C01);
756 flags = (flags & (S80 | Z40 | P04)) +
757 (temp & (F20 | F08)) +
758 (temp >> 8);
759 r.b.a = temp;
760 goto loop;
761 }
762
763 case 0x1F:{// RRA
764 int temp = (flags << 7) + (r.b.a >> 1);
765 flags = (flags & (S80 | Z40 | P04)) +
766 (temp & (F20 | F08)) +
767 (r.b.a & C01);
768 r.b.a = temp;
769 goto loop;
770 }
771
772// Misc
773 case 0x2F:{// CPL
774 int temp = ~r.b.a;
775 flags = (flags & (S80 | Z40 | P04 | C01)) +
776 (temp & (F20 | F08)) +
777 (H10 | N02);
778 r.b.a = temp;
779 goto loop;
780 }
781
782 case 0x3F:{// CCF
783 flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) +
784 (flags << 4 & H10) +
785 (r.b.a & (F20 | F08));
786 goto loop;
787 }
788
789 case 0x37: // SCF
790 flags = ((flags & (S80 | Z40 | P04)) | C01) +
791 (r.b.a & (F20 | F08));
792 goto loop;
793
794 case 0xDB: // IN A,(imm)
795 pc++;
796 r.b.a = IN_PORT( (data + r.b.a * 0x100) );
797 goto loop;
798
799 case 0xE3:{// EX (SP),HL
800 int temp = READ_WORD( sp );
801 WRITE_WORD( sp, r.w.hl );
802 r.w.hl = temp;
803 goto loop;
804 }
805
806 case 0xEB: // EX DE,HL
807 EX( r.w.hl, r.w.de );
808 goto loop;
809
810 case 0xD9: // EXX DE,HL
811 EXX( w.bc );
812 EXX( w.de );
813 EXX( w.hl );
814 goto loop;
815
816 case 0xF3: // DI
817 R.iff1 = 0;
818 R.iff2 = 0;
819 goto loop;
820
821 case 0xFB: // EI
822 R.iff1 = 1;
823 R.iff2 = 1;
824 // TODO: delayed effect
825 goto loop;
826
827 case 0x76: // HALT
828 goto halt;
829
830//////////////////////////////////////// CB prefix
831 {
832 case 0xCB:
833 pc++;
834 switch ( data )
835 {
836
837 // Rotate left
838
839 #define RLC( read, write ) {\
840 int result = read;\
841 result = BYTE( result << 1 ) + (result >> 7);\
842 flags = SZ28P( result ) + (result & C01);\
843 write;\
844 goto loop;\
845 }
846
847 case 0x06: // RLC (HL)
848 s_time += 7;
849 data = r.w.hl;
850 rlc_data_addr:
851 RLC( READ_MEM( data ), WRITE_MEM( data, result ) )
852
853 CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r
854 byte* reg = &R8( data, 0 );
855 RLC( *reg, *reg = result )
856 }
857
858 #define RL( read, write ) {\
859 int result = (read << 1) + (flags & C01);\
860 flags = SZ28PC( result );\
861 write;\
862 goto loop;\
863 }
864
865 case 0x16: // RL (HL)
866 s_time += 7;
867 data = r.w.hl;
868 rl_data_addr:
869 RL( READ_MEM( data ), WRITE_MEM( data, result ) )
870
871 CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r
872 byte* reg = &R8( data, 0x10 );
873 RL( *reg, *reg = result )
874 }
875
876 #define SLA( read, low_bit, write ) {\
877 int result = (read << 1) + low_bit;\
878 flags = SZ28PC( result );\
879 write;\
880 goto loop;\
881 }
882
883 case 0x26: // SLA (HL)
884 s_time += 7;
885 data = r.w.hl;
886 sla_data_addr:
887 SLA( READ_MEM( data ), 0, WRITE_MEM( data, result ) )
888
889 CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r
890 byte* reg = &R8( data, 0x20 );
891 SLA( *reg, 0, *reg = result )
892 }
893
894 case 0x36: // SLL (HL)
895 s_time += 7;
896 data = r.w.hl;
897 sll_data_addr:
898 SLA( READ_MEM( data ), 1, WRITE_MEM( data, result ) )
899
900 CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r
901 byte* reg = &R8( data, 0x30 );
902 SLA( *reg, 1, *reg = result )
903 }
904
905 // Rotate right
906
907 #define RRC( read, write ) {\
908 int result = read;\
909 flags = result & C01;\
910 result = BYTE( result << 7 ) + (result >> 1);\
911 flags += SZ28P( result );\
912 write;\
913 goto loop;\
914 }
915
916 case 0x0E: // RRC (HL)
917 s_time += 7;
918 data = r.w.hl;
919 rrc_data_addr:
920 RRC( READ_MEM( data ), WRITE_MEM( data, result ) )
921
922 CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r
923 byte* reg = &R8( data, 0x08 );
924 RRC( *reg, *reg = result )
925 }
926
927 #define RR( read, write ) {\
928 int result = read;\
929 int temp = result & C01;\
930 result = BYTE( flags << 7 ) + (result >> 1);\
931 flags = SZ28P( result ) + temp;\
932 write;\
933 goto loop;\
934 }
935
936 case 0x1E: // RR (HL)
937 s_time += 7;
938 data = r.w.hl;
939 rr_data_addr:
940 RR( READ_MEM( data ), WRITE_MEM( data, result ) )
941
942 CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r
943 byte* reg = &R8( data, 0x18 );
944 RR( *reg, *reg = result )
945 }
946
947 #define SRA( read, write ) {\
948 int result = read;\
949 flags = result & C01;\
950 result = (result & 0x80) + (result >> 1);\
951 flags += SZ28P( result );\
952 write;\
953 goto loop;\
954 }
955
956 case 0x2E: // SRA (HL)
957 data = r.w.hl;
958 s_time += 7;
959 sra_data_addr:
960 SRA( READ_MEM( data ), WRITE_MEM( data, result ) )
961
962 CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r
963 byte* reg = &R8( data, 0x28 );
964 SRA( *reg, *reg = result )
965 }
966
967 #define SRL( read, write ) {\
968 int result = read;\
969 flags = result & C01;\
970 result >>= 1;\
971 flags += SZ28P( result );\
972 write;\
973 goto loop;\
974 }
975
976 case 0x3E: // SRL (HL)
977 s_time += 7;
978 data = r.w.hl;
979 srl_data_addr:
980 SRL( READ_MEM( data ), WRITE_MEM( data, result ) )
981
982 CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r
983 byte* reg = &R8( data, 0x38 );
984 SRL( *reg, *reg = result )
985 }
986
987 // BIT
988 {
989 int temp;
990 CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL)
991 s_time += 4;
992 temp = READ_MEM( r.w.hl );
993 flags &= C01;
994 goto bit_temp;
995 CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r
996 CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r
997 CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r
998 CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r
999 CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r
1000 CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r
1001 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r
1002 CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r
1003 temp = R8( data & 7, 0 );
1004 flags = (flags & C01) + (temp & (F20 | F08));
1005 bit_temp:
1006 temp = temp & (1 << (data >> 3 & 7));
1007 flags += (temp & S80) + H10;
1008 flags += (unsigned) --temp >> 8 & (Z40 | P04);
1009 goto loop;
1010 }
1011
1012 // SET/RES
1013 CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL)
1014 CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL)
1015 s_time += 7;
1016 int temp = READ_MEM( r.w.hl );
1017 int bit = 1 << (data >> 3 & 7);
1018 temp |= bit; // SET
1019 if ( !(data & 0x40) )
1020 temp ^= bit; // RES
1021 WRITE_MEM( r.w.hl, temp );
1022 goto loop;
1023 }
1024
1025 CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r
1026 CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r
1027 CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r
1028 CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r
1029 CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r
1030 CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r
1031 CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r
1032 CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r
1033 R8( data & 7, 0 ) |= 1 << (data >> 3 & 7);
1034 goto loop;
1035
1036 CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r
1037 CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r
1038 CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r
1039 CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r
1040 CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r
1041 CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r
1042 CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r
1043 CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r
1044 R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7));
1045 goto loop;
1046 }
1047 assert( false );
1048 }
1049
1050#undef GET_ADDR
1051#define GET_ADDR() GET_LE16( &INSTR( 1, pc ) )
1052
1053//////////////////////////////////////// ED prefix
1054 {
1055 case 0xED:
1056 pc++;
1057 s_time += (clock_table + 256) [data] >> 4;
1058 switch ( data )
1059 {
1060 {
1061 int temp;
1062 case 0x72: // SBC HL,SP
1063 case 0x7A: // ADC HL,SP
1064 temp = sp;
1065 if ( 0 )
1066 case 0x42: // SBC HL,BC
1067 case 0x52: // SBC HL,DE
1068 case 0x62: // SBC HL,HL
1069 case 0x4A: // ADC HL,BC
1070 case 0x5A: // ADC HL,DE
1071 case 0x6A: // ADC HL,HL
1072 temp = R16( data >> 3 & 6, 1, 0 );
1073 int sum = temp + (flags & C01);
1074 flags = ~data >> 2 & N02;
1075 if ( flags )
1076 sum = -sum;
1077 sum += r.w.hl;
1078 temp ^= r.w.hl;
1079 temp ^= sum;
1080 flags +=(sum >> 16 & C01) +
1081 (temp >> 8 & H10) +
1082 (sum >> 8 & (S80 | F20 | F08)) +
1083 ((temp + 0x8000) >> 14 & V04);
1084 r.w.hl = sum;
1085 if ( WORD( sum ) )
1086 goto loop;
1087 flags += Z40;
1088 goto loop;
1089 }
1090
1091 CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C)
1092 int temp = IN_PORT( r.w.bc );
1093 R8( data >> 3, 8 ) = temp;
1094 flags = (flags & C01) + SZ28P( temp );
1095 goto loop;
1096 }
1097
1098 case 0x71: // OUT (C),0
1099 r.b.flags = 0;
1100 CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r
1101 OUT_PORT( r.w.bc, R8( data >> 3, 8 ) );
1102 goto loop;
1103
1104 {
1105 int temp;
1106 case 0x73: // LD (ADDR),SP
1107 temp = sp;
1108 if ( 0 )
1109 case 0x43: // LD (ADDR),BC
1110 case 0x53: // LD (ADDR),DE
1111 temp = R16( data, 4, 0x43 );
1112 int addr = GET_ADDR();
1113 pc += 2;
1114 WRITE_WORD( addr, temp );
1115 goto loop;
1116 }
1117
1118 case 0x4B: // LD BC,(ADDR)
1119 case 0x5B:{// LD DE,(ADDR)
1120 int addr = GET_ADDR();
1121 pc += 2;
1122 R16( data, 4, 0x4B ) = READ_WORD( addr );
1123 goto loop;
1124 }
1125
1126 case 0x7B:{// LD SP,(ADDR)
1127 int addr = GET_ADDR();
1128 pc += 2;
1129 sp = READ_WORD( addr );
1130 goto loop;
1131 }
1132
1133 case 0x67:{// RRD
1134 int temp = READ_MEM( r.w.hl );
1135 WRITE_MEM( r.w.hl, ((r.b.a << 4) + (temp >> 4)) );
1136 temp = (r.b.a & 0xF0) + (temp & 0x0F);
1137 flags = (flags & C01) + SZ28P( temp );
1138 r.b.a = temp;
1139 goto loop;
1140 }
1141
1142 case 0x6F:{// RLD
1143 int temp = READ_MEM( r.w.hl );
1144 WRITE_MEM( r.w.hl, ((temp << 4) + (r.b.a & 0x0F)) );
1145 temp = (r.b.a & 0xF0) + (temp >> 4);
1146 flags = (flags & C01) + SZ28P( temp );
1147 r.b.a = temp;
1148 goto loop;
1149 }
1150
1151 CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG
1152 opcode = 0x10; // flag to do SBC instead of ADC
1153 flags &= ~C01;
1154 data = r.b.a;
1155 r.b.a = 0;
1156 goto adc_data;
1157
1158 {
1159 int inc;
1160 case 0xA9: // CPD
1161 case 0xB9: // CPDR
1162 inc = -1;
1163 if ( 0 )
1164 case 0xA1: // CPI
1165 case 0xB1: // CPIR
1166 inc = +1;
1167 int addr = r.w.hl;
1168 r.w.hl = addr + inc;
1169 int temp = READ_MEM( addr );
1170
1171 int result = r.b.a - temp;
1172 flags = (flags & C01) + N02 +
1173 ((((temp ^ r.b.a) & H10) ^ result) & (S80 | H10));
1174
1175 if ( !BYTE( result ) )
1176 flags += Z40;
1177 result -= (flags & H10) >> 4;
1178 flags += result & F08;
1179 flags += result << 4 & F20;
1180 if ( !--r.w.bc )
1181 goto loop;
1182
1183 flags += V04;
1184 if ( flags & Z40 || data < 0xB0 )
1185 goto loop;
1186
1187 pc -= 2;
1188 s_time += 5;
1189 goto loop;
1190 }
1191
1192 {
1193 int inc;
1194 case 0xA8: // LDD
1195 case 0xB8: // LDDR
1196 inc = -1;
1197 if ( 0 )
1198 case 0xA0: // LDI
1199 case 0xB0: // LDIR
1200 inc = +1;
1201 int addr = r.w.hl;
1202 r.w.hl = addr + inc;
1203 int temp = READ_MEM( addr );
1204
1205 addr = r.w.de;
1206 r.w.de = addr + inc;
1207 WRITE_MEM( addr, temp );
1208
1209 temp += r.b.a;
1210 flags = (flags & (S80 | Z40 | C01)) +
1211 (temp & F08) + (temp << 4 & F20);
1212 if ( !--r.w.bc )
1213 goto loop;
1214
1215 flags += V04;
1216 if ( data < 0xB0 )
1217 goto loop;
1218
1219 pc -= 2;
1220 s_time += 5;
1221 goto loop;
1222 }
1223
1224 {
1225 int inc;
1226 case 0xAB: // OUTD
1227 case 0xBB: // OTDR
1228 inc = -1;
1229 if ( 0 )
1230 case 0xA3: // OUTI
1231 case 0xB3: // OTIR
1232 inc = +1;
1233 int addr = r.w.hl;
1234 r.w.hl = addr + inc;
1235 int temp = READ_MEM( addr );
1236
1237 int b = --r.b.b;
1238 flags = (temp >> 6 & N02) + SZ28( b );
1239 if ( b && data >= 0xB0 )
1240 {
1241 pc -= 2;
1242 s_time += 5;
1243 }
1244
1245 OUT_PORT( r.w.bc, temp );
1246 goto loop;
1247 }
1248
1249 {
1250 int inc;
1251 case 0xAA: // IND
1252 case 0xBA: // INDR
1253 inc = -1;
1254 if ( 0 )
1255 case 0xA2: // INI
1256 case 0xB2: // INIR
1257 inc = +1;
1258
1259 int addr = r.w.hl;
1260 r.w.hl = addr + inc;
1261
1262 int temp = IN_PORT( r.w.bc );
1263
1264 int b = --r.b.b;
1265 flags = (temp >> 6 & N02) + SZ28( b );
1266 if ( b && data >= 0xB0 )
1267 {
1268 pc -= 2;
1269 s_time += 5;
1270 }
1271
1272 WRITE_MEM( addr, temp );
1273 goto loop;
1274 }
1275
1276 case 0x47: // LD I,A
1277 R.i = r.b.a;
1278 goto loop;
1279
1280 case 0x4F: // LD R,A
1281 SET_R( r.b.a );
1282 dprintf( "LD R,A not supported\n" );
1283 warning = true;
1284 goto loop;
1285
1286 case 0x57: // LD A,I
1287 r.b.a = R.i;
1288 goto ld_ai_common;
1289
1290 case 0x5F: // LD A,R
1291 r.b.a = GET_R();
1292 dprintf( "LD A,R not supported\n" );
1293 warning = true;
1294 ld_ai_common:
1295 flags = (flags & C01) + SZ28( r.b.a ) + (R.iff2 << 2 & V04);
1296 goto loop;
1297
1298 CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN
1299 R.iff1 = R.iff2;
1300 goto ret_taken;
1301
1302 case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0
1303 R.im = 0;
1304 goto loop;
1305
1306 case 0x56: case 0x76: // IM 1
1307 R.im = 1;
1308 goto loop;
1309
1310 case 0x5E: case 0x7E: // IM 2
1311 R.im = 2;
1312 goto loop;
1313
1314 default:
1315 dprintf( "Opcode $ED $%02X not supported\n", data );
1316 warning = true;
1317 goto loop;
1318 }
1319 assert( false );
1320 }
1321
1322//////////////////////////////////////// DD/FD prefix
1323 {
1324 int ixy;
1325 case 0xDD:
1326 ixy = ix;
1327 goto ix_prefix;
1328 case 0xFD:
1329 ixy = iy;
1330 ix_prefix:
1331 pc++;
1332 int data2 = READ_CODE( pc );
1333 s_time += (clock_table + 256) [data] & 0x0F;
1334 switch ( data )
1335 {
1336 // TODO: more efficient way of avoid negative address
1337 // TODO: avoid using this as argument to READ_MEM() since it is evaluated twice
1338 #define IXY_DISP( ixy, disp ) WORD( (ixy ) + (disp))
1339
1340 #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in;
1341
1342 // ADD/ADC/SUB/SBC
1343
1344 case 0x96: // SUB (IXY+disp)
1345 case 0x86: // ADD (IXY+disp)
1346 flags &= ~C01;
1347 case 0x9E: // SBC (IXY+disp)
1348 case 0x8E: // ADC (IXY+disp)
1349 pc++;
1350 opcode = data;
1351 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1352 goto adc_data;
1353
1354 case 0x94: // SUB HXY
1355 case 0x84: // ADD HXY
1356 flags &= ~C01;
1357 case 0x9C: // SBC HXY
1358 case 0x8C: // ADC HXY
1359 opcode = data;
1360 data = ixy >> 8;
1361 goto adc_data;
1362
1363 case 0x95: // SUB LXY
1364 case 0x85: // ADD LXY
1365 flags &= ~C01;
1366 case 0x9D: // SBC LXY
1367 case 0x8D: // ADC LXY
1368 opcode = data;
1369 data = BYTE( ixy );
1370 goto adc_data;
1371
1372 {
1373 int temp;
1374 case 0x39: // ADD IXY,SP
1375 temp = sp;
1376 goto add_ixy_data;
1377
1378 case 0x29: // ADD IXY,HL
1379 temp = ixy;
1380 goto add_ixy_data;
1381
1382 case 0x09: // ADD IXY,BC
1383 case 0x19: // ADD IXY,DE
1384 temp = R16( data, 4, 0x09 );
1385 add_ixy_data: {
1386 int sum = ixy + temp;
1387 temp ^= ixy;
1388 ixy = WORD( sum );
1389 flags = (flags & (S80 | Z40 | V04)) +
1390 (sum >> 16) +
1391 (sum >> 8 & (F20 | F08)) +
1392 ((temp ^ sum) >> 8 & H10);
1393 goto set_ixy;
1394 }
1395 }
1396
1397 // AND
1398 case 0xA6: // AND (IXY+disp)
1399 pc++;
1400 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1401 goto and_data;
1402
1403 case 0xA4: // AND HXY
1404 data = ixy >> 8;
1405 goto and_data;
1406
1407 case 0xA5: // AND LXY
1408 data = BYTE( ixy );
1409 goto and_data;
1410
1411 // OR
1412 case 0xB6: // OR (IXY+disp)
1413 pc++;
1414 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1415 goto or_data;
1416
1417 case 0xB4: // OR HXY
1418 data = ixy >> 8;
1419 goto or_data;
1420
1421 case 0xB5: // OR LXY
1422 data = BYTE( ixy );
1423 goto or_data;
1424
1425 // XOR
1426 case 0xAE: // XOR (IXY+disp)
1427 pc++;
1428 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1429 goto xor_data;
1430
1431 case 0xAC: // XOR HXY
1432 data = ixy >> 8;
1433 goto xor_data;
1434
1435 case 0xAD: // XOR LXY
1436 data = BYTE( ixy );
1437 goto xor_data;
1438
1439 // CP
1440 case 0xBE: // CP (IXY+disp)
1441 pc++;
1442 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1443 goto cp_data;
1444
1445 case 0xBC: // CP HXY
1446 data = ixy >> 8;
1447 goto cp_data;
1448
1449 case 0xBD: // CP LXY
1450 data = BYTE( ixy );
1451 goto cp_data;
1452
1453 // LD
1454 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r
1455 data = R8( data, 0x70 );
1456 if ( 0 )
1457 case 0x36: // LD (IXY+disp),imm
1458 pc++, data = READ_CODE( pc );
1459 pc++;
1460 WRITE_MEM( IXY_DISP( ixy, SBYTE( data2 ) ), data );
1461 goto loop;
1462
1463 CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY
1464 R8( data >> 3, 8 ) = ixy >> 8;
1465 goto loop;
1466
1467 case 0x64: // LD HXY,HXY
1468 case 0x6D: // LD LXY,LXY
1469 goto loop;
1470
1471 CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY
1472 R8( data >> 3, 8 ) = ixy;
1473 goto loop;
1474
1475 CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp)
1476 pc++;
1477 R8( data >> 3, 8 ) = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1478 goto loop;
1479
1480 case 0x26: // LD HXY,imm
1481 pc++;
1482 goto ld_hxy_data;
1483
1484 case 0x65: // LD HXY,LXY
1485 data2 = BYTE( ixy );
1486 goto ld_hxy_data;
1487
1488 CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r
1489 data2 = R8( data, 0x60 );
1490 ld_hxy_data:
1491 ixy = BYTE( ixy ) + (data2 << 8);
1492 goto set_ixy;
1493
1494 case 0x2E: // LD LXY,imm
1495 pc++;
1496 goto ld_lxy_data;
1497
1498 case 0x6C: // LD LXY,HXY
1499 data2 = ixy >> 8;
1500 goto ld_lxy_data;
1501
1502 CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r
1503 data2 = R8( data, 0x68 );
1504 ld_lxy_data:
1505 ixy = (ixy & 0xFF00) + data2;
1506 set_ixy:
1507 if ( opcode == 0xDD )
1508 {
1509 ix = ixy;
1510 goto loop;
1511 }
1512 iy = ixy;
1513 goto loop;
1514
1515 case 0xF9: // LD SP,IXY
1516 sp = ixy;
1517 goto loop;
1518
1519 case 0x22:{// LD (ADDR),IXY
1520 int addr = GET_ADDR();
1521 pc += 2;
1522 WRITE_WORD( addr, ixy );
1523 goto loop;
1524 }
1525
1526 case 0x21: // LD IXY,imm
1527 ixy = GET_ADDR();
1528 pc += 2;
1529 goto set_ixy;
1530
1531 case 0x2A:{// LD IXY,(addr)
1532 int addr = GET_ADDR();
1533 ixy = READ_WORD( addr );
1534 pc += 2;
1535 goto set_ixy;
1536 }
1537
1538 // DD/FD CB prefix
1539 case 0xCB: {
1540 data = IXY_DISP( ixy, SBYTE( data2 ) );
1541 pc++;
1542 data2 = READ_CODE( pc );
1543 pc++;
1544 switch ( data2 )
1545 {
1546 case 0x06: goto rlc_data_addr; // RLC (IXY)
1547 case 0x16: goto rl_data_addr; // RL (IXY)
1548 case 0x26: goto sla_data_addr; // SLA (IXY)
1549 case 0x36: goto sll_data_addr; // SLL (IXY)
1550 case 0x0E: goto rrc_data_addr; // RRC (IXY)
1551 case 0x1E: goto rr_data_addr; // RR (IXY)
1552 case 0x2E: goto sra_data_addr; // SRA (IXY)
1553 case 0x3E: goto srl_data_addr; // SRL (IXY)
1554
1555 CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp)
1556 int temp = READ_MEM( data );
1557 temp = temp & (1 << (data2 >> 3 & 7));
1558 flags = (flags & C01) + H10 + (temp & S80);
1559 flags += (unsigned) --temp >> 8 & (Z40 | P04);
1560 goto loop;
1561 }
1562
1563 CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp)
1564 CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp)
1565 int temp = READ_MEM( data );
1566 int bit = 1 << (data2 >> 3 & 7);
1567 temp |= bit; // SET
1568 if ( !(data2 & 0x40) )
1569 temp ^= bit; // RES
1570 WRITE_MEM( data, temp );
1571 goto loop;
1572 }
1573
1574 default:
1575 dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 );
1576 warning = true;
1577 goto loop;
1578 }
1579 assert( false );
1580 }
1581
1582 // INC/DEC
1583 case 0x23: // INC IXY
1584 ixy = WORD( ixy + 1 );
1585 goto set_ixy;
1586
1587 case 0x2B: // DEC IXY
1588 ixy = WORD( ixy - 1 );
1589 goto set_ixy;
1590
1591 case 0x34: // INC (IXY+disp)
1592 ixy = IXY_DISP( ixy, SBYTE( data2 ) );
1593 pc++;
1594 data = READ_MEM( ixy ) + 1;
1595 WRITE_MEM( ixy, data );
1596 goto inc_set_flags;
1597
1598 case 0x35: // DEC (IXY+disp)
1599 ixy = IXY_DISP( ixy, SBYTE( data2 ) );
1600 pc++;
1601 data = READ_MEM( ixy ) - 1;
1602 WRITE_MEM( ixy, data );
1603 goto dec_set_flags;
1604
1605 case 0x24: // INC HXY
1606 ixy = WORD( ixy + 0x100 );
1607 data = ixy >> 8;
1608 goto inc_xy_common;
1609
1610 case 0x2C: // INC LXY
1611 data = BYTE( ixy + 1 );
1612 ixy = (ixy & 0xFF00) + data;
1613 inc_xy_common:
1614 if ( opcode == 0xDD )
1615 {
1616 ix = ixy;
1617 goto inc_set_flags;
1618 }
1619 iy = ixy;
1620 goto inc_set_flags;
1621
1622 case 0x25: // DEC HXY
1623 ixy = WORD( ixy - 0x100 );
1624 data = ixy >> 8;
1625 goto dec_xy_common;
1626
1627 case 0x2D: // DEC LXY
1628 data = BYTE( ixy - 1 );
1629 ixy = (ixy & 0xFF00) + data;
1630 dec_xy_common:
1631 if ( opcode == 0xDD )
1632 {
1633 ix = ixy;
1634 goto dec_set_flags;
1635 }
1636 iy = ixy;
1637 goto dec_set_flags;
1638
1639 // PUSH/POP
1640 case 0xE5: // PUSH IXY
1641 data = ixy;
1642 goto push_data;
1643
1644 case 0xE1:{// POP IXY
1645 ixy = READ_WORD( sp );
1646 sp = WORD( sp + 2 );
1647 goto set_ixy;
1648 }
1649
1650 // Misc
1651
1652 case 0xE9: // JP (IXY)
1653 pc = ixy;
1654 goto loop;
1655
1656 case 0xE3:{// EX (SP),IXY
1657 int temp = READ_WORD( sp );
1658 WRITE_WORD( sp, ixy );
1659 ixy = temp;
1660 goto set_ixy;
1661 }
1662
1663 default:
1664 dprintf( "Unnecessary DD/FD prefix encountered\n" );
1665 warning = true;
1666 pc--;
1667 goto loop;
1668 }
1669 assert( false );
1670 }
1671
1672 }
1673 dprintf( "Unhandled main opcode: $%02X\n", opcode );
1674 assert( false );
1675
1676#ifdef IDLE_ADDR
1677hit_idle_addr:
1678 s_time -= 11;
1679 goto out_of_time;
1680#endif
1681halt:
1682 s_time &= 3; // increment by multiple of 4
1683out_of_time:
1684 pc--;
1685
1686 r.b.flags = flags;
1687 R.ix = ix;
1688 R.iy = iy;
1689 R.sp = sp;
1690 R.pc = pc;
1691 R.b = r.b;
1692
1693 cpu->cpu_state_.base = s.base;
1694 cpu->cpu_state_.time = s_time;
1695 cpu->cpu_state = &cpu->cpu_state_;
1696}
diff --git a/apps/codecs/nsf.c b/apps/codecs/nsf.c
index d626d528bf..a556f75b27 100644
--- a/apps/codecs/nsf.c
+++ b/apps/codecs/nsf.c
@@ -1,4378 +1,68 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2006 Adam Gashlin (hcs)
10 * Copyright (C) 2004 Disch
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21 1
22/* 2/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
23 * This is a perversion of Disch's excellent NotSoFatso.
24 */
25 3
26#include "codeclib.h" 4#define GME_NSF_TYPE
27#include "inttypes.h"
28#include "system.h"
29 5
30CODEC_HEADER 6#include <codecs/lib/codeclib.h>
31 7#include "libgme/nsf_emu.h"
32#if (CONFIG_CPU == MCF5250)
33#define ICODE_INSTEAD_OF_INLINE
34/* Enough IRAM to move additional data and code to it. */
35#define IBSS_ATTR_NSF_LARGE_IRAM IBSS_ATTR
36#define ICONST_ATTR_NSF_LARGE_IRAM ICONST_ATTR
37
38#elif (CONFIG_CPU == PP5022) || (CONFIG_CPU == PP5024)
39#define ICODE_INSTEAD_OF_INLINE
40/* Enough IRAM to move additional data and code to it. */
41#define IBSS_ATTR_NSF_LARGE_IRAM IBSS_ATTR
42#define ICONST_ATTR_NSF_LARGE_IRAM ICONST_ATTR
43
44#elif defined(CPU_S5L870X)
45#define ICODE_INSTEAD_OF_INLINE
46/* Very large IRAM. Move even more data to it. */
47#define IBSS_ATTR_NSF_LARGE_IRAM IBSS_ATTR
48#define ICONST_ATTR_NSF_LARGE_IRAM ICONST_ATTR
49 8
50#else 9CODEC_HEADER
51#define ICODE_INSTEAD_OF_INLINE
52/* Not enough IRAM available. */
53#define IBSS_ATTR_NSF_LARGE_IRAM
54#define ICONST_ATTR_NSF_LARGE_IRAM
55#endif
56 10
57/* Maximum number of bytes to process in one iteration */ 11/* Maximum number of bytes to process in one iteration */
58#define WAV_CHUNK_SIZE (1024*2) 12#define CHUNK_SIZE (1024*2)
59
60static int16_t samples[WAV_CHUNK_SIZE] IBSS_ATTR MEM_ALIGN_ATTR;
61
62#define ZEROMEMORY(addr,size) memset(addr,0,size)
63
64/* simple profiling with USEC_TIMER
65
66#define NSF_PROFILE
67
68*/
69
70#ifdef NSF_PROFILE
71
72#define CREATE_TIMER(name) static uint32_t nsf_timer_##name##_start,\
73 nsf_timer_##name##_total
74#define ENTER_TIMER(name) nsf_timer_##name##_start=USEC_TIMER
75#define EXIT_TIMER(name) nsf_timer_##name##_total+=\
76 (USEC_TIMER-nsf_timer_##name##_start)
77#define READ_TIMER(name) (nsf_timer_##name##_total)
78#define RESET_TIMER(name) nsf_timer_##name##_total=0
79
80#define PRINT_TIMER_PCT(bname,tname,nstr) ci->fdprintf(
81 logfd,"%10ld ",READ_TIMER(bname));\
82 ci->fdprintf(logfd,"(%3d%%) " nstr "\t",\
83 ((uint64_t)READ_TIMER(bname))*100/READ_TIMER(tname))
84
85CREATE_TIMER(total);
86CREATE_TIMER(cpu);
87CREATE_TIMER(apu);
88CREATE_TIMER(squares);
89CREATE_TIMER(tnd);
90CREATE_TIMER(tnd_enter);
91CREATE_TIMER(tnd_tri);
92CREATE_TIMER(tnd_noise);
93CREATE_TIMER(tnd_dmc);
94CREATE_TIMER(fds);
95CREATE_TIMER(frame);
96CREATE_TIMER(mix);
97
98void reset_profile_timers(void) {
99 RESET_TIMER(total);
100 RESET_TIMER(cpu);
101 RESET_TIMER(apu);
102 RESET_TIMER(squares);
103 RESET_TIMER(tnd);
104 RESET_TIMER(tnd_enter);
105 RESET_TIMER(tnd_tri);
106 RESET_TIMER(tnd_noise);
107 RESET_TIMER(tnd_dmc);
108 RESET_TIMER(fds);
109 RESET_TIMER(frame);
110 RESET_TIMER(mix);
111}
112
113int logfd=-1;
114
115void print_timers(char * path, int track) {
116 logfd = ci->open("/nsflog.txt",O_WRONLY|O_CREAT|O_APPEND, 0666);
117 ci->fdprintf(logfd,"%s[%d]:\t",path,track);
118 ci->fdprintf(logfd,"%10ld total\t",READ_TIMER(total));
119 PRINT_TIMER_PCT(cpu,total,"CPU");
120 PRINT_TIMER_PCT(apu,total,"APU");
121 ci->fdprintf(logfd,"\n\t");
122 PRINT_TIMER_PCT(squares,apu,"squares");
123 PRINT_TIMER_PCT(frame,apu,"frame");
124 PRINT_TIMER_PCT(mix,apu,"mix");
125 PRINT_TIMER_PCT(fds,apu,"FDS");
126 PRINT_TIMER_PCT(tnd,apu,"tnd");
127 ci->fdprintf(logfd,"\n\t\t");
128 PRINT_TIMER_PCT(tnd_enter,tnd,"enter");
129 PRINT_TIMER_PCT(tnd_tri,tnd,"triangle");
130 PRINT_TIMER_PCT(tnd_noise,tnd,"noise");
131 PRINT_TIMER_PCT(tnd_dmc,tnd,"DMC");
132 ci->fdprintf(logfd,"\n");
133
134 ci->close(logfd);
135 logfd=-1;
136}
137
138#else
139
140#define CREATE_TIMER(name)
141#define ENTER_TIMER(name)
142#define EXIT_TIMER(name)
143#define READ_TIMER(name)
144#define RESET_TIMER(name)
145#define print_timers(path,track)
146#define reset_profile_timers()
147
148#endif
149
150/* proper handling of multibyte values */
151#ifdef ROCKBOX_LITTLE_ENDIAN
152union TWIN
153{
154 uint16_t W;
155 struct{ uint8_t l; uint8_t h; } B;
156};
157
158union QUAD
159{
160 uint32_t D;
161 struct{ uint8_t l; uint8_t h; uint16_t w; } B;
162};
163#else
164
165union TWIN
166{
167 uint16_t W;
168 struct{ uint8_t h; uint8_t l; } B;
169};
170
171union QUAD
172{
173 uint32_t D;
174 struct{uint16_t w; uint8_t h; uint8_t l; } B;
175};
176
177#endif
178
179#define NTSC_FREQUENCY 1789772.727273f
180#define PAL_FREQUENCY 1652097.692308f
181#define NTSC_NMIRATE 60.098814f
182#define PAL_NMIRATE 50.006982f
183
184#define NES_FREQUENCY 21477270
185#define NTSC_FRAME_COUNTER_FREQ (NTSC_FREQUENCY / (NES_FREQUENCY / 89490.0f))
186#define PAL_FRAME_COUNTER_FREQ (PAL_FREQUENCY / (NES_FREQUENCY / 89490.0f))
187
188/****************** tables */
189static const int32_t ModulationTable[8] ICONST_ATTR = {0,1,2,4,0,-4,-2,-1};
190static const uint16_t DMC_FREQ_TABLE[2][0x10] ICONST_ATTR_NSF_LARGE_IRAM = {
191 /* NTSC */
192 {0x1AC,0x17C,0x154,0x140,0x11E,0x0FE,0x0E2,0x0D6,0x0BE,0x0A0,0x08E,0x080,
193 0x06A,0x054,0x048,0x036},
194 /* PAL */
195 {0x18C,0x160,0x13A,0x128,0x108,0x0EA,0x0D0,0x0C6,0x0B0,0x094,0x082,0x076,
196 0x062,0x04E,0x042,0x032}
197};
198
199static const uint8_t DUTY_CYCLE_TABLE[4] ICONST_ATTR_NSF_LARGE_IRAM = {
200 2,4,8,12
201};
202
203static const uint8_t LENGTH_COUNTER_TABLE[0x20] ICONST_ATTR_NSF_LARGE_IRAM = {
204 0x0A,0xFE,0x14,0x02,0x28,0x04,0x50,0x06,0xA0,0x08,0x3C,0x0A,0x0E,0x0C,0x1A,
205 0x0E,0x0C,0x10,0x18,0x12,0x30,0x14,0x60,0x16,0xC0,0x18,0x48,0x1A,0x10,0x1C,
206 0x20,0x1E
207};
208
209static const uint16_t NOISE_FREQ_TABLE[0x10] ICONST_ATTR_NSF_LARGE_IRAM = {
210 0x004,0x008,0x010,0x020,0x040,0x060,0x080,0x0A0,0x0CA,0x0FE,0x17C,0x1FC,
211 0x2FA,0x3F8,0x7F2,0xFE4
212};
213
214/****************** NSF loading ******************/
215
216/* file format structs (both are little endian) */
217
218struct NESM_HEADER
219{
220 uint32_t nHeader;
221 uint8_t nHeaderExtra;
222 uint8_t nVersion;
223 uint8_t nTrackCount;
224 uint8_t nInitialTrack;
225 uint16_t nLoadAddress;
226 uint16_t nInitAddress;
227 uint16_t nPlayAddress;
228 uint8_t szGameTitle[32];
229 uint8_t szArtist[32];
230 uint8_t szCopyright[32];
231 uint16_t nSpeedNTSC;
232 uint8_t nBankSwitch[8];
233 uint16_t nSpeedPAL;
234 uint8_t nNTSC_PAL;
235 uint8_t nExtraChip;
236 uint8_t nExpansion[4];
237};
238
239struct NSFE_INFOCHUNK
240{
241 uint16_t nLoadAddress;
242 uint16_t nInitAddress;
243 uint16_t nPlayAddress;
244 uint8_t nIsPal;
245 uint8_t nExt;
246 uint8_t nTrackCount;
247 uint8_t nStartingTrack;
248};
249
250static int32_t LoadFile(uint8_t *,size_t);
251
252static int32_t LoadFile_NESM(uint8_t *,size_t);
253static int32_t LoadFile_NSFE(uint8_t *,size_t);
254
255/* NSF file info */
256
257/* basic NSF info */
258static int32_t bIsExtended=0; /* 0 = NSF, 1 = NSFE */
259static uint8_t nIsPal=0; /* 0 = NTSC, 1 = PAL, 2,3 = mixed
260 NTSC/PAL (interpretted as NTSC) */
261static int32_t nfileLoadAddress=0; /* The address to which the NSF code is
262 loaded */
263static int32_t nfileInitAddress=0; /* The address of the Init routine
264 (called at track change) */
265static int32_t nfilePlayAddress=0; /* The address of the Play routine
266 (called several times a second) */
267static uint8_t nChipExtensions=0; /* Bitwise representation of the
268 external chips used by this NSF. */
269
270/* old NESM speed stuff (blarg) */
271static int32_t nNTSC_PlaySpeed=0;
272static int32_t nPAL_PlaySpeed=0;
273
274/* track info */
275/* The number of tracks in the NSF (1 = 1 track, 5 = 5 tracks, etc) */
276static int32_t nTrackCount=0;
277/* The initial track (ZERO BASED: 0 = 1st track, 4 = 5th track, etc) */
278static int32_t nInitialTrack=0;
279
280/* nsf data */
281static uint8_t* pDataBuffer=0; /* the buffer containing NSF code. */
282static int32_t nDataBufferSize=0; /* the size of the above buffer. */
283
284/* playlist */
285static uint8_t nPlaylist[256]; /* Each entry is the zero based index of
286 the song to play */
287static int32_t nPlaylistSize=0; /* number of tracks in the playlist */
288
289/* track time / fade */
290static int32_t nTrackTime[256]; /* track times -1 if no track times
291 specified */
292static int32_t nTrackFade[256]; /* track fade times -1 if none are
293 specified */
294
295/* string info */
296static uint8_t szGameTitle[0x101];
297static uint8_t szArtist[0x101];
298static uint8_t szCopyright[0x101];
299static uint8_t szRipper[0x101];
300
301/* bankswitching info */
302static uint8_t nBankswitch[8]={0}; /* The initial bankswitching registers
303 needed for some NSFs. If the NSF does
304 not use bankswitching, these values
305 will all be zero */
306
307static int32_t LoadFile(uint8_t * inbuffer, size_t size)
308{
309 if(!inbuffer) return -1;
310
311 int32_t ret = -1;
312
313 if(!memcmp(inbuffer,"NESM",4)) ret = LoadFile_NESM(inbuffer,size);
314 if(!memcmp(inbuffer,"NSFE",4)) ret = LoadFile_NSFE(inbuffer,size);
315
316 /*
317 * Snake's revenge puts '00' for the initial track,
318 * which (after subtracting 1) makes it 256 or -1 (bad!)
319 * This prevents that crap
320 */
321 if(nInitialTrack >= nTrackCount)
322 nInitialTrack = 0;
323 if(nInitialTrack < 0)
324 nInitialTrack = 0;
325
326 /* if there's no tracks... this is a crap NSF */
327 if(nTrackCount < 1)
328 {
329 return -1;
330 }
331
332 return ret;
333}
334
335static int32_t LoadFile_NESM(uint8_t* inbuffer, size_t size)
336{
337 uint8_t ignoreversion=1;
338 uint8_t needdata=1;
339
340 /* read the info */
341 struct NESM_HEADER hdr;
342
343 memcpy(&hdr,inbuffer,sizeof(hdr));
344
345 /* confirm the header */
346 if(memcmp("NESM",&(hdr.nHeader),4)) return -1;
347 if(hdr.nHeaderExtra != 0x1A) return -1;
348 /* stupid NSFs claim to be above version 1 >_> */
349 if((!ignoreversion) && (hdr.nVersion != 1)) return -1;
350
351 /*
352 * NESM is generally easier to work with (but limited!)
353 * just move the data over from NESM_HEADER over to our member data
354 */
355
356 bIsExtended = 0;
357 nIsPal = hdr.nNTSC_PAL & 0x03;
358 nPAL_PlaySpeed = letoh16(hdr.nSpeedPAL);
359 nNTSC_PlaySpeed = letoh16(hdr.nSpeedNTSC);
360 nfileLoadAddress = letoh16(hdr.nLoadAddress);
361 nfileInitAddress = letoh16(hdr.nInitAddress);
362 nfilePlayAddress = letoh16(hdr.nPlayAddress);
363 nChipExtensions = hdr.nExtraChip;
364
365
366 nTrackCount = hdr.nTrackCount;
367 nInitialTrack = hdr.nInitialTrack - 1;
368
369 memcpy(nBankswitch,hdr.nBankSwitch,8);
370
371 memcpy(szGameTitle,hdr.szGameTitle,32);
372 memcpy(szArtist ,hdr.szArtist ,32);
373 memcpy(szCopyright,hdr.szCopyright,32);
374
375 /* read the NSF data */
376 if(needdata)
377 {
378 pDataBuffer=inbuffer+0x80;
379 nDataBufferSize=size-0x80;
380 }
381
382 /* if we got this far... it was a successful read */
383 return 0;
384}
385
386static int32_t LoadFile_NSFE(uint8_t* inbuffer, size_t size)
387{
388 /* the vars we'll be using */
389 uint32_t nChunkType;
390 int32_t nChunkSize;
391 int32_t nChunkUsed;
392 int32_t i;
393 uint8_t * nDataPos = 0;
394 uint8_t bInfoFound = 0;
395 uint8_t bEndFound = 0;
396 uint8_t bBankFound = 0;
397 nPlaylistSize=-1;
398
399 struct NSFE_INFOCHUNK info;
400 ZEROMEMORY(&info,sizeof(struct NSFE_INFOCHUNK));
401 ZEROMEMORY(nBankswitch,8);
402 info.nTrackCount = 1; /* default values */
403
404 if (size < 8) return -1; /* must have at least NSFE,NEND */
405
406 /* confirm the header! */
407 memcpy(&nChunkType,inbuffer,4);
408 inbuffer+=4;
409 if(memcmp(&nChunkType,"NSFE",4)) return -1;
410
411 for (i=0;i<256;i++) {
412 nTrackTime[i]=-1;
413 nTrackFade[i]=-1;
414 }
415
416 /* begin reading chunks */
417 while(!bEndFound)
418 {
419 memcpy(&nChunkSize,inbuffer,4);
420 nChunkSize=letoh32(nChunkSize);
421 inbuffer+=4;
422 memcpy(&nChunkType,inbuffer,4);
423 inbuffer+=4;
424
425 if(!memcmp(&nChunkType,"INFO",4)) {
426 /* only one info chunk permitted */
427 if(bInfoFound) return -1;
428 if(nChunkSize < 8) return -1; /* minimum size */
429
430 bInfoFound = 1;
431 nChunkUsed = MIN((int32_t)sizeof(struct NSFE_INFOCHUNK),
432 nChunkSize);
433
434 memcpy(&info,inbuffer,nChunkUsed);
435 inbuffer+=nChunkSize;
436
437 bIsExtended = 1;
438 nIsPal = info.nIsPal & 3;
439 nfileLoadAddress = letoh16(info.nLoadAddress);
440 nfileInitAddress = letoh16(info.nInitAddress);
441 nfilePlayAddress = letoh16(info.nPlayAddress);
442 nChipExtensions = info.nExt;
443 nTrackCount = info.nTrackCount;
444 nInitialTrack = info.nStartingTrack;
445
446 nPAL_PlaySpeed = (uint16_t)(1000000 / PAL_NMIRATE);
447 nNTSC_PlaySpeed = (uint16_t)(1000000 / NTSC_NMIRATE);
448 } else if (!memcmp(&nChunkType,"DATA",4)) {
449 if(!bInfoFound) return -1;
450 if(nDataPos) return -1;
451 if(nChunkSize < 1) return -1;
452
453 nDataBufferSize = nChunkSize;
454 nDataPos = inbuffer;
455
456 inbuffer+=nChunkSize;
457 } else if (!memcmp(&nChunkType,"NEND",4)) {
458 bEndFound = 1;
459 } else if (!memcmp(&nChunkType,"time",4)) {
460 if(!bInfoFound) return -1;
461 for (nChunkUsed=0; nChunkUsed < MIN(nChunkSize / 4,nTrackCount);
462 nChunkUsed++,inbuffer+=4) {
463 nTrackTime[nChunkUsed]=
464 ((uint32_t)inbuffer[0])|
465 ((uint32_t)inbuffer[1]<<8)|
466 ((uint32_t)inbuffer[2]<<16)|
467 ((uint32_t)inbuffer[3]<<24);
468 }
469
470 inbuffer+=nChunkSize-(nChunkUsed*4);
471
472 /* negative signals to use default time */
473 for(; nChunkUsed < nTrackCount; nChunkUsed++)
474 nTrackTime[nChunkUsed] = -1;
475 } else if (!memcmp(&nChunkType,"fade",4)) {
476 if(!bInfoFound) return -1;
477 for (nChunkUsed=0; nChunkUsed < MIN(nChunkSize / 4,nTrackCount);
478 nChunkUsed++,inbuffer+=4) {
479 nTrackFade[nChunkUsed]=
480 ((uint32_t)inbuffer[0])|
481 ((uint32_t)inbuffer[1]<<8)|
482 ((uint32_t)inbuffer[2]<<16)|
483 ((uint32_t)inbuffer[3]<<24);
484 }
485
486 inbuffer+=nChunkSize-(nChunkUsed*4);
487
488 /* negative signals to use default time */
489 for(; nChunkUsed < nTrackCount; nChunkUsed++)
490 nTrackFade[nChunkUsed] = -1;
491 } else if (!memcmp(&nChunkType,"BANK",4)) {
492 if(bBankFound) return -1;
493
494 bBankFound = 1;
495 nChunkUsed = MIN(8,nChunkSize);
496 memcpy(nBankswitch,inbuffer,nChunkUsed);
497
498 inbuffer+=nChunkSize;
499 } else if (!memcmp(&nChunkType,"plst",4)) {
500
501 nPlaylistSize = nChunkSize;
502 if(nPlaylistSize >= 1) {
503
504 memcpy(nPlaylist,inbuffer,nChunkSize);
505 inbuffer+=nChunkSize;
506 }
507 } else if (!memcmp(&nChunkType,"auth",4)) {
508 uint8_t* ptr;
509
510 ptr = inbuffer;
511
512 uint8_t* ar[4] = {szGameTitle,szArtist,szCopyright,szRipper};
513 int32_t i;
514 for(i = 0; (ptr-inbuffer)<nChunkSize && i < 4; i++)
515 {
516 nChunkUsed = strlen(ptr) + 1;
517 memcpy(ar[i],ptr,nChunkUsed);
518 ptr += nChunkUsed;
519 }
520 inbuffer+=nChunkSize;
521 } else if (!memcmp(&nChunkType,"tlbl",4)) {
522 /* we unfortunately can't use these anyway */
523 inbuffer+=nChunkSize;
524 } else { /* unknown chunk */
525 nChunkType = letoh32(nChunkType)>>24; /* check the first byte */
526 /* chunk is vital... don't continue */
527 if((nChunkType >= 'A') && (nChunkType <= 'Z'))
528 return -1;
529 /* otherwise, just skip it */
530 inbuffer+=nChunkSize;
531 } /* end if series */
532 } /* end while */
533
534 /*
535 * if we exited the while loop without a 'return', we must have hit an NEND
536 * chunk if this is the case, the file was layed out as it was expected.
537 * now.. make sure we found both an info chunk, AND a data chunk... since
538 * these are minimum requirements for a valid NSFE file
539 */
540
541 if(!bInfoFound) return -1;
542 if(!nDataPos) return -1;
543
544 /* if both those chunks existed, this file is valid.
545 Load the data if it's needed */
546
547 pDataBuffer=nDataPos;
548
549 /* return success! */
550 return 0;
551}
552
553
554/****************** Audio Device Structures ******************/
555
556struct FDSWave
557{
558 /* Envelope Unit */
559 uint8_t bEnvelopeEnable;
560 uint8_t nEnvelopeSpeed;
561
562 /* Volume Envelope */
563 uint8_t nVolEnv_Mode;
564 uint8_t nVolEnv_Decay;
565 uint8_t nVolEnv_Gain;
566 int32_t nVolEnv_Timer;
567 int32_t nVolEnv_Count;
568 uint8_t nVolume;
569 uint8_t bVolEnv_On;
570
571 /* Sweep Envenlope */
572 uint8_t nSweep_Mode;
573 uint8_t nSweep_Decay;
574 int32_t nSweep_Timer;
575 int32_t nSweep_Count;
576 uint8_t nSweep_Gain;
577 uint8_t bSweepEnv_On;
578
579 /* Effector / LFO / Modulation Unit */
580 int32_t nSweepBias;
581 uint8_t bLFO_Enabled;
582 union TWIN nLFO_Freq;
583 /*float fLFO_Timer;*/
584 /*float fLFO_Count;*/
585 int32_t nLFO_Timer; /* -17.14*/
586 int32_t nLFO_Count; /* -17.14*/
587 uint8_t nLFO_Addr;
588 uint8_t nLFO_Table[0x40];
589 uint8_t bLFO_On;
590
591 /* Main Output */
592 uint8_t nMainVolume;
593 uint8_t bEnabled;
594 union TWIN nFreq;
595 /*float fFreqCount;*/
596 int32_t nFreqCount; /* -17.14 */
597 uint8_t nMainAddr;
598 uint8_t nWaveTable[0x40];
599 uint8_t bWaveWrite;
600 uint8_t bMain_On;
601
602 /* Output and Downsampling */
603 int32_t nMixL;
604
605 /* Pop Reducer */
606 uint8_t bPopReducer;
607 uint8_t nPopOutput;
608 int32_t nPopCount;
609
610};
611static int16_t FDS_nOutputTable_L[4][0x21][0x40] IBSS_ATTR_NSF_LARGE_IRAM MEM_ALIGN_ATTR;
612
613struct FME07Wave
614{
615 /* Frequency Control */
616 union TWIN nFreqTimer;
617 int32_t nFreqCount;
618
619 /* Channel Disabling */
620 uint8_t bChannelEnabled;
621
622 /* Volume */
623 uint8_t nVolume;
624
625 /* Duty Cycle */
626 uint8_t nDutyCount;
627
628 /* Output and Downsampling */
629 int32_t nMixL;
630};
631
632static int16_t FME07_nOutputTable_L[0x10] IDATA_ATTR MEM_ALIGN_ATTR;
633
634struct N106Wave
635{
636 /* All Channel Stuff */
637
638 uint8_t nActiveChannels;
639 uint8_t bAutoIncrement;
640 uint8_t nCurrentAddress;
641 uint8_t nRAM[0x100]; /* internal memory for registers/wave data */
642 int32_t nFrequencyLookupTable[8]; /* lookup tbl for freq conversions */
643
644 /*
645 * Individual channel stuff
646 */
647 /* Wavelength / Frequency */
648 union QUAD nFreqReg[8];
649 int32_t nFreqTimer[8];
650 int32_t nFreqCount[8];
651
652 /* Wave data length / remaining */
653 uint8_t nWaveSize[8];
654 uint8_t nWaveRemaining[8];
655
656 /* Wave data position */
657 uint8_t nWavePosStart[8];
658 uint8_t nWavePos[8];
659 uint8_t nOutput[8];
660
661 /* Volume */
662 uint8_t nVolume[8];
663
664 /* Pop Reducer */
665 uint8_t nPreVolume[8];
666 uint8_t nPopCheck[8];
667
668 /* Mixing */
669 int32_t nMixL[8];
670};
671
672static int16_t N106_nOutputTable_L[0x10][0x10] IBSS_ATTR_NSF_LARGE_IRAM MEM_ALIGN_ATTR;
673
674struct VRC6PulseWave
675{
676
677 /* Frequency Control */
678 union TWIN nFreqTimer;
679 int32_t nFreqCount;
680
681 /* Flags */
682 uint8_t bChannelEnabled;
683 uint8_t bDigitized;
684
685 /* Volume */
686 uint8_t nVolume;
687
688 /* Duty Cycle */
689 uint8_t nDutyCycle;
690 uint8_t nDutyCount;
691
692 /* Output and Downsampling */
693 int32_t nMixL;
694
695};
696
697static int16_t VRC6Pulse_nOutputTable_L[0x10] IDATA_ATTR MEM_ALIGN_ATTR;
698
699struct VRC6SawWave
700{
701
702 /* Frequency Control */
703 union TWIN nFreqTimer;
704 int32_t nFreqCount;
705
706 /* Flags */
707 uint8_t bChannelEnabled;
708
709 /* Phase Accumulator */
710 uint8_t nAccumRate;
711 uint8_t nAccum;
712 uint8_t nAccumStep;
713
714 /* Output and Downsampling */
715 int32_t nMixL;
716
717};
718
719static int16_t VRC6Saw_nOutputTable_L[0x20] IDATA_ATTR MEM_ALIGN_ATTR;
720
721struct Wave_Squares
722{
723
724 /* Programmable Timer */
725 union TWIN nFreqTimer[2];
726 int32_t nFreqCount[2];
727
728 /* Length Counter */
729 uint8_t nLengthCount[2];
730 uint8_t bLengthEnabled[2];
731 uint8_t bChannelEnabled[2];
732
733 /* Volume / Decay */
734 uint8_t nVolume[2];
735 uint8_t nDecayVolume[2];
736 uint8_t bDecayEnable[2];
737 uint8_t bDecayLoop[2];
738 uint8_t nDecayTimer[2];
739 uint8_t nDecayCount[2];
740
741 /* Sweep Unit */
742 uint8_t bSweepEnable[2];
743 uint8_t bSweepMode[2];
744 uint8_t bSweepForceSilence[2];
745 uint8_t nSweepTimer[2];
746 uint8_t nSweepCount[2];
747 uint8_t nSweepShift[2];
748
749 /* Duty Cycle */
750 uint8_t nDutyCount[2];
751 uint8_t nDutyCycle[2];
752
753 /* Output and Downsampling */
754 int32_t nMixL;
755};
756
757static int16_t Squares_nOutputTable_L[0x10][0x10] IDATA_ATTR MEM_ALIGN_ATTR;
758
759struct Wave_TND
760{
761
762 /*
763 * Triangle
764 */
765
766 /* Programmable Timer */
767 union TWIN nTriFreqTimer;
768 int32_t nTriFreqCount;
769
770 /* Length Counter */
771 uint8_t nTriLengthCount;
772 uint8_t bTriLengthEnabled;
773 uint8_t bTriChannelEnabled;
774
775 /* Linear Counter */
776 uint8_t nTriLinearCount;
777 uint8_t nTriLinearLoad;
778 uint8_t bTriLinearHalt;
779 uint8_t bTriLinearControl;
780
781 /* Tri-Step Generator / Output */
782 uint8_t nTriStep;
783 uint8_t nTriOutput;
784
785 /*
786 * Noise
787 */
788
789 /* Programmable Timer */
790 uint16_t nNoiseFreqTimer;
791 int32_t nNoiseFreqCount;
792
793 /* Length Counter */
794 uint8_t nNoiseLengthCount;
795 uint8_t bNoiseLengthEnabled;
796 uint8_t bNoiseChannelEnabled;
797
798 /* Volume / Decay */
799 uint8_t nNoiseVolume;
800 uint8_t nNoiseDecayVolume;
801 uint8_t bNoiseDecayEnable;
802 uint8_t bNoiseDecayLoop;
803 uint8_t nNoiseDecayTimer;
804 uint8_t nNoiseDecayCount;
805
806 /* Random Number Generator */
807 uint16_t nNoiseRandomShift;
808 uint8_t bNoiseRandomMode; /* 1 = 32k, 6 = 93-bit */
809 uint8_t bNoiseRandomOut;
810
811 /*
812 * DMC
813 */
814
815 /* Play Mode */
816 uint8_t bDMCLoop;
817 uint8_t bDMCIRQEnabled;
818 uint8_t bDMCIRQPending;
819
820 /* Address / DMA */
821 uint8_t nDMCDMABank_Load;
822 uint16_t nDMCDMAAddr_Load;
823 uint8_t nDMCDMABank;
824 uint16_t nDMCDMAAddr;
825 uint8_t* pDMCDMAPtr[8];
826
827 /* Length / Input */
828 uint16_t nDMCLength;
829 uint16_t nDMCBytesRemaining;
830 uint8_t nDMCDelta;
831 uint8_t nDMCDeltaBit;
832 uint8_t bDMCDeltaSilent;
833 uint8_t nDMCSampleBuffer;
834 uint8_t bDMCSampleBufferEmpty;
835
836 /* Frequency */
837 uint16_t nDMCFreqTimer;
838 int32_t nDMCFreqCount;
839
840 /* Output */
841 uint8_t bDMCActive;
842 uint8_t nDMCOutput;
843
844 int32_t nMixL;
845};
846
847/* channels */
848static struct Wave_Squares mWave_Squares IDATA_ATTR; /* Square channels 1 and 2 */
849static struct Wave_TND mWave_TND IDATA_ATTR; /* Triangle/Noise/DMC channels */
850static struct VRC6PulseWave mWave_VRC6Pulse[2] IDATA_ATTR;
851static struct VRC6SawWave mWave_VRC6Saw IDATA_ATTR;
852static struct N106Wave mWave_N106 IDATA_ATTR;
853static struct FDSWave mWave_FDS IDATA_ATTR;
854static struct FME07Wave mWave_FME07[3] IDATA_ATTR; /* FME-07's 3 pulse channels */
855
856
857/****************** MMC5 ******************/
858/* will include MMC5 sound channels some day,
859 currently only multiply is supported */
860
861/****************** N106 (Disch loves this chip) ******************/
862
863#ifdef ICODE_INSTEAD_OF_INLINE
864static void Wave_N106_DoTicks(const int32_t ticks) ICODE_ATTR;
865static void Wave_N106_DoTicks(const int32_t ticks)
866#else
867static inline void Wave_N106_DoTicks(const int32_t ticks);
868static inline void Wave_N106_DoTicks(const int32_t ticks)
869#endif
870{
871 register int32_t i;
872
873 for(i = (7 - mWave_N106.nActiveChannels); i < 8; i++)
874 {
875 if(!mWave_N106.nFreqReg[i].D)
876 {
877 /* written frequency of zero will cause divide by zero error
878 makes me wonder if the formula was supposed to be Reg+1 */
879 mWave_N106.nVolume[i] = mWave_N106.nPreVolume[i];
880 continue;
881 }
882
883 {
884 mWave_N106.nMixL[i] =
885 N106_nOutputTable_L[mWave_N106.nVolume[i]]
886 [mWave_N106.nOutput[i]];
887
888 if(mWave_N106.nFreqTimer[i] < 0)
889 mWave_N106.nFreqTimer[i] =
890 (mWave_N106.nFrequencyLookupTable[mWave_N106.nActiveChannels] /
891 mWave_N106.nFreqReg[i].D);
892 if(mWave_N106.nFreqCount[i] > mWave_N106.nFreqTimer[i])
893 mWave_N106.nFreqCount[i] = mWave_N106.nFreqTimer[i];
894
895 mWave_N106.nFreqCount[i] -= ticks << 8;
896 while(mWave_N106.nFreqCount[i] <= 0)
897 {
898 mWave_N106.nFreqCount[i] += mWave_N106.nFreqTimer[i];
899 if(mWave_N106.nWaveRemaining[i])
900 {
901 mWave_N106.nWaveRemaining[i]--;
902 mWave_N106.nWavePos[i]++;
903 }
904 if(!mWave_N106.nWaveRemaining[i])
905 {
906 mWave_N106.nWaveRemaining[i] = mWave_N106.nWaveSize[i];
907 mWave_N106.nWavePos[i] = mWave_N106.nWavePosStart[i];
908 if(mWave_N106.nVolume[i] != mWave_N106.nPreVolume[i])
909 {
910 if(++mWave_N106.nPopCheck[i] >= 2)
911 {
912 mWave_N106.nPopCheck[i] = 0;
913 mWave_N106.nVolume[i] = mWave_N106.nPreVolume[i];
914 }
915 }
916 }
917
918 mWave_N106.nOutput[i] =
919 mWave_N106.nRAM[mWave_N106.nWavePos[i]];
920
921 if(!mWave_N106.nOutput[i])
922 {
923 mWave_N106.nPopCheck[i] = 0;
924 mWave_N106.nVolume[i] = mWave_N106.nPreVolume[i];
925 }
926
927 }
928 }
929 }
930}
931/****************** VRC6 ******************/
932
933#ifdef ICODE_INSTEAD_OF_INLINE
934static void Wave_VRC6_DoTicks(const int32_t ticks) ICODE_ATTR;
935static void Wave_VRC6_DoTicks(const int32_t ticks)
936#else
937static inline void Wave_VRC6_DoTicks(const int32_t ticks);
938static inline void Wave_VRC6_DoTicks(const int32_t ticks)
939#endif
940{
941 register int32_t i;
942
943 for(i = 0; i < 2; i++) {
944
945 if(mWave_VRC6Pulse[i].bChannelEnabled) {
946
947 mWave_VRC6Pulse[i].nFreqCount -= ticks;
948
949 if(mWave_VRC6Pulse[i].nDutyCount <=
950 mWave_VRC6Pulse[i].nDutyCycle)
951 {
952 mWave_VRC6Pulse[i].nMixL =
953 VRC6Pulse_nOutputTable_L[mWave_VRC6Pulse[i].nVolume];
954 }
955 else
956 mWave_VRC6Pulse[i].nMixL = 0;
957
958 while(mWave_VRC6Pulse[i].nFreqCount <= 0) {
959 mWave_VRC6Pulse[i].nFreqCount +=
960 mWave_VRC6Pulse[i].nFreqTimer.W + 1;
961
962 if(!mWave_VRC6Pulse[i].bDigitized)
963 mWave_VRC6Pulse[i].nDutyCount =
964 (mWave_VRC6Pulse[i].nDutyCount + 1) & 0x0F;
965 }
966 }
967 }
968
969 if(mWave_VRC6Saw.bChannelEnabled) {
970
971 mWave_VRC6Saw.nFreqCount -= ticks;
972
973 mWave_VRC6Saw.nMixL =
974 VRC6Saw_nOutputTable_L[mWave_VRC6Saw.nAccum >> 3];
975
976 while(mWave_VRC6Saw.nFreqCount <= 0) {
977
978 mWave_VRC6Saw.nFreqCount += mWave_VRC6Saw.nFreqTimer.W + 1;
979
980 mWave_VRC6Saw.nAccumStep++;
981 if(mWave_VRC6Saw.nAccumStep == 14)
982 {
983 mWave_VRC6Saw.nAccumStep = 0;
984 mWave_VRC6Saw.nAccum = 0;
985 }
986 else if(!(mWave_VRC6Saw.nAccumStep & 1))
987 mWave_VRC6Saw.nAccum += mWave_VRC6Saw.nAccumRate;
988 }
989 }
990}
991
992/****************** Square waves ******************/
993
994/* decay */
995#ifdef ICODE_INSTEAD_OF_INLINE
996static void Wave_Squares_ClockMajor(void) ICODE_ATTR;
997static void Wave_Squares_ClockMajor()
998#else
999static inline void Wave_Squares_ClockMajor(void);
1000static inline void Wave_Squares_ClockMajor()
1001#endif
1002{
1003 if(mWave_Squares.nDecayCount[0])
1004 mWave_Squares.nDecayCount[0]--;
1005 else
1006 {
1007 mWave_Squares.nDecayCount[0] = mWave_Squares.nDecayTimer[0];
1008 if(mWave_Squares.nDecayVolume[0])
1009 mWave_Squares.nDecayVolume[0]--;
1010 else
1011 {
1012 if(mWave_Squares.bDecayLoop[0])
1013 mWave_Squares.nDecayVolume[0] = 0x0F;
1014 }
1015
1016 if(mWave_Squares.bDecayEnable[0])
1017 mWave_Squares.nVolume[0] = mWave_Squares.nDecayVolume[0];
1018 }
1019
1020 if(mWave_Squares.nDecayCount[1])
1021 mWave_Squares.nDecayCount[1]--;
1022 else
1023 {
1024 mWave_Squares.nDecayCount[1] = mWave_Squares.nDecayTimer[1];
1025 if(mWave_Squares.nDecayVolume[1])
1026 mWave_Squares.nDecayVolume[1]--;
1027 else
1028 {
1029 if(mWave_Squares.bDecayLoop[1])
1030 mWave_Squares.nDecayVolume[1] = 0x0F;
1031 }
1032
1033 if(mWave_Squares.bDecayEnable[1])
1034 mWave_Squares.nVolume[1] = mWave_Squares.nDecayVolume[1];
1035 }
1036
1037}
1038
1039
1040#ifdef ICODE_INSTEAD_OF_INLINE
1041static void Wave_Squares_CheckSweepForcedSilence(const int32_t i) ICODE_ATTR;
1042static void Wave_Squares_CheckSweepForcedSilence(const int32_t i)
1043#else
1044static inline void Wave_Squares_CheckSweepForcedSilence(const int32_t i);
1045static inline void Wave_Squares_CheckSweepForcedSilence(const int32_t i)
1046#endif
1047{
1048 if(mWave_Squares.nFreqTimer[i].W < 8) {
1049 mWave_Squares.bSweepForceSilence[i] = 1; return;
1050 }
1051 if(!mWave_Squares.bSweepMode[i] &&
1052 (( mWave_Squares.nFreqTimer[i].W +
1053 (mWave_Squares.nFreqTimer[i].W >> mWave_Squares.nSweepShift[i]))
1054 >= 0x0800)) { mWave_Squares.bSweepForceSilence[i] = 1; return; }
1055
1056 mWave_Squares.bSweepForceSilence[i] = 0;
1057}
1058
1059/* sweep / length */
1060#ifdef ICODE_INSTEAD_OF_INLINE
1061static void Wave_Squares_ClockMinor(void) ICODE_ATTR;
1062static void Wave_Squares_ClockMinor()
1063#else
1064static inline void Wave_Squares_ClockMinor(void);
1065static inline void Wave_Squares_ClockMinor()
1066#endif
1067{
1068/* unrolled a little loop
1069 static int i = 0;
1070 for(i = 0; i < 2; i++)
1071 {
1072*/
1073 if(mWave_Squares.bLengthEnabled[0] && mWave_Squares.nLengthCount[0])
1074 mWave_Squares.nLengthCount[0]--;
1075
1076 if(!mWave_Squares.bSweepEnable[0] || !mWave_Squares.nLengthCount[0] ||
1077 mWave_Squares.bSweepForceSilence[0] || !mWave_Squares.nSweepShift[0])
1078 goto other_square;
1079
1080 if(mWave_Squares.nSweepCount[0])
1081 mWave_Squares.nSweepCount[0]--;
1082 else
1083 {
1084 mWave_Squares.nSweepCount[0] = mWave_Squares.nSweepTimer[0];
1085 if(mWave_Squares.bSweepMode[0]) mWave_Squares.nFreqTimer[0].W -=
1086 (mWave_Squares.nFreqTimer[0].W >> mWave_Squares.nSweepShift[0])+1;
1087 else mWave_Squares.nFreqTimer[0].W +=
1088 (mWave_Squares.nFreqTimer[0].W >> mWave_Squares.nSweepShift[0]);
1089
1090 Wave_Squares_CheckSweepForcedSilence(0);
1091 }
1092
1093 /* */
1094other_square:
1095 if(mWave_Squares.bLengthEnabled[1] && mWave_Squares.nLengthCount[1])
1096 mWave_Squares.nLengthCount[1]--;
1097
1098 if(!mWave_Squares.bSweepEnable[1] || !mWave_Squares.nLengthCount[1] ||
1099 mWave_Squares.bSweepForceSilence[1] || !mWave_Squares.nSweepShift[1])
1100 return;
1101
1102 if(mWave_Squares.nSweepCount[1])
1103 mWave_Squares.nSweepCount[1]--;
1104 else
1105 {
1106 mWave_Squares.nSweepCount[1] = mWave_Squares.nSweepTimer[1];
1107 if(mWave_Squares.bSweepMode[1]) mWave_Squares.nFreqTimer[1].W -=
1108 (mWave_Squares.nFreqTimer[1].W >> mWave_Squares.nSweepShift[1]);
1109 else mWave_Squares.nFreqTimer[1].W +=
1110 (mWave_Squares.nFreqTimer[1].W >> mWave_Squares.nSweepShift[1]);
1111
1112 Wave_Squares_CheckSweepForcedSilence(1);
1113 }
1114}
1115
1116/****************** Triangle/noise/DMC ******************/
1117
1118/* decay (noise), linear (tri) */
1119
1120#ifdef ICODE_INSTEAD_OF_INLINE
1121static void Wave_TND_ClockMajor(void) ICODE_ATTR;
1122static void Wave_TND_ClockMajor()
1123#else
1124static inline void Wave_TND_ClockMajor(void);
1125static inline void Wave_TND_ClockMajor()
1126#endif
1127{
1128 /* noise's decay */
1129 if(mWave_TND.nNoiseDecayCount)
1130 mWave_TND.nNoiseDecayCount--;
1131 else
1132 {
1133 mWave_TND.nNoiseDecayCount = mWave_TND.nNoiseDecayTimer;
1134 if(mWave_TND.nNoiseDecayVolume)
1135 mWave_TND.nNoiseDecayVolume--;
1136 else
1137 {
1138 if(mWave_TND.bNoiseDecayLoop)
1139 mWave_TND.nNoiseDecayVolume = 0x0F;
1140 }
1141
1142 if(mWave_TND.bNoiseDecayEnable)
1143 mWave_TND.nNoiseVolume = mWave_TND.nNoiseDecayVolume;
1144 }
1145
1146 /* triangle's linear */
1147 if(mWave_TND.bTriLinearHalt)
1148 mWave_TND.nTriLinearCount = mWave_TND.nTriLinearLoad;
1149 else if(mWave_TND.nTriLinearCount)
1150 mWave_TND.nTriLinearCount--;
1151
1152 if(!mWave_TND.bTriLinearControl)
1153 mWave_TND.bTriLinearHalt = 0;
1154}
1155
1156/* length */
1157
1158#ifdef ICODE_INSTEAD_OF_INLINE
1159static void Wave_TND_ClockMinor(void) ICODE_ATTR;
1160static void Wave_TND_ClockMinor()
1161#else
1162static inline void Wave_TND_ClockMinor(void);
1163static inline void Wave_TND_ClockMinor()
1164#endif
1165{
1166 if(mWave_TND.bNoiseLengthEnabled && mWave_TND.nNoiseLengthCount)
1167 mWave_TND.nNoiseLengthCount--;
1168
1169 if(mWave_TND.bTriLengthEnabled && mWave_TND.nTriLengthCount)
1170 mWave_TND.nTriLengthCount--;
1171}
1172
1173/*#undef this*/
1174
1175/****************** NSF Core ******************/
1176
1177/* start globals */
1178
1179/*
1180 * Memory
1181 */
1182/* RAM: 0x0000 - 0x07FF */
1183static uint8_t pRAM[0x800] IBSS_ATTR_NSF_LARGE_IRAM MEM_ALIGN_ATTR;
1184/* SRAM: 0x6000 - 0x7FFF (non-FDS only) */
1185static uint8_t pSRAM[0x2000] IBSS_ATTR_NSF_LARGE_IRAM MEM_ALIGN_ATTR;
1186/* ExRAM: 0x5C00 - 0x5FF5 (MMC5 only)
1187 * Also holds NSF player code (at 0x5000 - 0x500F) */
1188static uint8_t pExRAM[0x1000] IBSS_ATTR_NSF_LARGE_IRAM MEM_ALIGN_ATTR;
1189/* Full ROM buffer */
1190static uint8_t* pROM_Full IDATA_ATTR;
1191
1192static uint16_t main_nOutputTable_L[0x8000] MEM_ALIGN_ATTR;
1193
1194static uint8_t* pROM[10] IDATA_ATTR;/* ROM banks (point to areas in pROM_Full) */
1195 /* 0x8000 - 0xFFFF */
1196 /* also includes 0x6000 - 0x7FFF (FDS only) */
1197static uint8_t* pStack; /* the stack (points to areas in pRAM) */
1198 /* 0x0100 - 0x01FF */
1199
1200static int32_t nROMSize; /* size of this ROM file in bytes */
1201static int32_t nROMBankCount; /* max number of 4k banks */
1202static int32_t nROMMaxSize; /* size of allocated pROM_Full buffer */
1203
1204/*
1205 * Memory Proc Pointers
1206 */
1207
1208typedef uint8_t ( *ReadProc)(uint16_t);
1209typedef void ( *WriteProc)(uint16_t,uint8_t);
1210static ReadProc ReadMemory[0x10] IDATA_ATTR MEM_ALIGN_ATTR;
1211static WriteProc WriteMemory[0x10] IDATA_ATTR MEM_ALIGN_ATTR;
1212
1213/*
1214 * 6502 Registers / Mode
1215 */
1216
1217static uint8_t regA IDATA_ATTR; /* Accumulator */
1218static uint8_t regX IDATA_ATTR; /* X-Index */
1219static uint8_t regY IDATA_ATTR; /* Y-Index */
1220static uint8_t regP IDATA_ATTR; /* Processor Status */
1221static uint8_t regSP IDATA_ATTR; /* Stack Pointer */
1222static uint16_t regPC IDATA_ATTR; /* Program Counter */
1223
1224static uint8_t bPALMode IDATA_ATTR;/* 1 if in PAL emulation mode, 0 if in NTSC */
1225static uint8_t bCPUJammed IDATA_ATTR; /* 0 = not jammed. 1 = really
1226 jammed. 2 = 'fake' jammed */
1227 /* fake jam caused by the NSF code to signal
1228 * the end of the play/init routine */
1229
1230/* Multiplication Register, for MMC5 chip only (5205+5206) */
1231static uint8_t nMultIn_Low;
1232static uint8_t nMultIn_High;
1233
1234/*
1235 * NSF Preparation Information
1236 */
1237
1238static uint8_t nBankswitchInitValues[10]; /* banks to swap to on tune init */
1239static uint16_t nPlayAddress; /* Play routine address */
1240static uint16_t nInitAddress; /* Init routine address */
1241
1242static uint8_t nExternalSound; /* external sound chips */
1243static uint8_t nCurTrack;
1244
1245static float fNSFPlaybackSpeed;
1246
1247/*
1248 * pAPU
1249 */
1250
1251static uint8_t nFrameCounter; /* Frame Sequence Counter */
1252static uint8_t nFrameCounterMax; /* Frame Sequence Counter Size
1253 (3 or 4 depending on $4017.7) */
1254static uint8_t bFrameIRQEnabled; /* TRUE if frame IRQs are enabled */
1255static uint8_t bFrameIRQPending; /* TRUE if the frame sequencer is
1256 holding down an IRQ */
1257
1258static uint8_t nFME07_Address;
1259
1260/*
1261 * Timing and Counters
1262 */
1263/* fixed point -15.16 */
1264
1265static int32_t nTicksUntilNextFrame;
1266static int32_t nTicksPerPlay;
1267static int32_t nTicksUntilNextPlay;
1268static int32_t nTicksPerSample;
1269static int32_t nTicksUntilNextSample;
1270
1271static uint32_t nCPUCycle IDATA_ATTR;
1272static uint32_t nAPUCycle IDATA_ATTR;
1273
1274
1275static uint32_t nTotalPlays; /* number of times the play subroutine has been
1276 called (for tracking output time) */
1277/*
1278 * Silence Tracker
1279 */
1280static int32_t nSilentSamples;
1281static int32_t nSilentSampleMax;
1282static int32_t nSilenceTrackMS;
1283static uint8_t bNoSilenceIfTime;
1284static uint8_t bTimeNotDefault;
1285
1286/*
1287 * Sound output options
1288 */
1289static const int32_t nSampleRate=44100;
1290
1291/*
1292 * Volume/fading/filter tracking
1293 */
1294
1295static uint32_t nStartFade; /* play call to start fading out */
1296static uint32_t nEndFade; /* play call to stop fading out (song is over) */
1297static uint8_t bFade; /* are we fading? */
1298static float fFadeVolume;
1299static float fFadeChange;
1300
1301/*
1302 * Designated Output Buffer
1303 */
1304static uint8_t* pOutput IDATA_ATTR;
1305
1306static const uint8_t bDMCPopReducer=1;
1307static uint8_t nDMCPop_Prev IDATA_ATTR = 0;
1308static uint8_t bDMCPop_Skip IDATA_ATTR = 0;
1309static uint8_t bDMCPop_SamePlay IDATA_ATTR = 0;
1310
1311static const uint8_t nForce4017Write=0;
1312static const uint8_t bN106PopReducer=0;
1313static const uint8_t bIgnore4011Writes=0;
1314
1315static const uint8_t bIgnoreBRK=0;
1316static const uint8_t bIgnoreIllegalOps=0;
1317static const uint8_t bNoWaitForReturn=0;
1318static const uint8_t bPALPreference=0;
1319static const uint8_t bCleanAXY=0;
1320static const uint8_t bResetDuty=0;
1321
1322/*
1323 * Sound Filter
1324 */
1325
1326static int64_t nFilterAccL IDATA_ATTR;
1327static int64_t nHighPass IDATA_ATTR;
1328
1329static int32_t nHighPassBase IDATA_ATTR;
1330
1331static uint8_t bHighPassEnabled IDATA_ATTR;
1332
1333/* end globals */
1334
1335#define CLOCK_MAJOR() { Wave_Squares_ClockMajor(); Wave_TND_ClockMajor(); }
1336#define CLOCK_MINOR() { Wave_Squares_ClockMinor(); Wave_TND_ClockMinor(); }
1337
1338#define EXTSOUND_VRC6 0x01
1339#define EXTSOUND_VRC7 0x02
1340#define EXTSOUND_FDS 0x04
1341#define EXTSOUND_MMC5 0x08
1342#define EXTSOUND_N106 0x10
1343#define EXTSOUND_FME07 0x20
1344
1345#define SILENCE_THRESHOLD 3
1346
1347/*
1348 * prototypes
1349 */
1350
1351static uint32_t Emulate6502(uint32_t runto) ICODE_ATTR;
1352static void EmulateAPU(uint8_t bBurnCPUCycles) ICODE_ATTR;
1353
1354static int NSFCore_Initialize(void); /* 1 = initialized ok,
1355 0 = couldn't initialize (memory allocation error) */
1356
1357/*
1358 * Song Loading
1359 */
1360static int LoadNSF(int32_t); /* grab data from an existing file
1361 1 = loaded ok, 0 = error loading */
1362
1363/*
1364 * Track Control
1365 */
1366static void SetTrack(uint8_t track); /* Change tracks */
1367
1368/*
1369 * Getting Samples
1370 */
1371/* fill a buffer with samples */
1372static int32_t GetSamples(uint8_t* buffer, int32_t buffersize);
1373
1374/*
1375 * Playback options
1376 */
1377/* Set desired playback options (0 = bad options couldn't be set) */
1378static int SetPlaybackOptions(int32_t samplerate);
1379/* Speed throttling (0 = uses NSF specified speed) */
1380static void SetPlaybackSpeed(float playspersec);
1381
1382static float GetPlaybackSpeed(void);
1383/* rockbox: not used
1384float GetMasterVolume(void); */
1385
1386/* rockbox: not used */
1387#if 0
1388/*
1389 * Seeking
1390 */
1391/* gets the number of 'play' routine calls executed */
1392float GetPlayCalls(void);
1393
1394/* gets the output time (based on the given play rate,
1395 if basedplayspersec is zero, current playback speed is used */
1396uint32_t GetWrittenTime(float basedplayspersec);
1397/* sets the number of 'plays' routines executed (for precise seeking) */
1398void SetPlayCalls(float plays);
1399/* sets the written time (approx. seeking) */
1400void SetWrittenTime(uint32_t ms,float basedplays);
1401#endif
1402
1403/*
1404 * Fading
1405 */
1406
1407/* rockbox: not used
1408void StopFade(void); */ /* stops all fading (plays indefinitely) */
1409static uint8_t SongCompleted(void); /* song has faded out (samples have
1410 stopped being generated) */
1411/* parameters are play calls */
1412static void SetFade(int32_t fadestart,int32_t fadestop,uint8_t bNotDefault);
1413static void SetFadeTime(uint32_t fadestart,uint32_t fadestop,
1414 float basedplays, uint8_t bNotDefault);
1415 /* parameters are in milliseconds */
1416
1417/*
1418 * Internal Functions
1419 */
1420static void RebuildOutputTables(void);
1421static void RecalculateFade(void); /* called when fade status is changed. */
1422static void RecalcFilter(void);
1423static void RecalcSilenceTracker(void);
1424
1425static void WriteMemory_VRC6(uint16_t a,uint8_t v) ICODE_ATTR;
1426static void WriteMemory_MMC5(uint16_t a,uint8_t v) ICODE_ATTR;
1427static void WriteMemory_N106(uint16_t a,uint8_t v) ICODE_ATTR;
1428static void WriteMemory_FME07(uint16_t a,uint8_t v) ICODE_ATTR;
1429
1430/*
1431 * Memory Read/Write routines
1432 */
1433
1434static uint8_t ReadMemory_RAM(uint16_t a) ICODE_ATTR;
1435static uint8_t ReadMemory_ExRAM(uint16_t a) ICODE_ATTR;
1436static uint8_t ReadMemory_SRAM(uint16_t a) ICODE_ATTR;
1437static uint8_t ReadMemory_pAPU(uint16_t a) ICODE_ATTR;
1438static uint8_t ReadMemory_ROM(uint16_t a) ICODE_ATTR;
1439static uint8_t ReadMemory_Default(uint16_t a) ICODE_ATTR;
1440
1441static uint8_t ReadMemory_N106(uint16_t a) ICODE_ATTR;
1442
1443static void WriteMemory_RAM(uint16_t a,uint8_t v) ICODE_ATTR;
1444static void WriteMemory_ExRAM(uint16_t a,uint8_t v) ICODE_ATTR;
1445static void WriteMemory_SRAM(uint16_t a,uint8_t v) ICODE_ATTR;
1446static void WriteMemory_pAPU(uint16_t a,uint8_t v) ICODE_ATTR;
1447static void WriteMemory_FDSRAM(uint16_t a,uint8_t v) ICODE_ATTR;
1448static void WriteMemory_Default(uint16_t a,uint8_t v) ICODE_ATTR;
1449
1450static uint8_t ReadMemory_RAM(uint16_t a) { return pRAM[a & 0x07FF]; }
1451static uint8_t ReadMemory_ExRAM(uint16_t a) { return pExRAM[a & 0x0FFF]; }
1452static uint8_t ReadMemory_SRAM(uint16_t a) { return pSRAM[a & 0x1FFF]; }
1453static uint8_t ReadMemory_ROM(uint16_t a)
1454 { return pROM[(a >> 12) - 6][a & 0x0FFF]; }
1455static uint8_t ReadMemory_Default(uint16_t a) { return (a >> 8); }
1456
1457static void WriteMemory_RAM(uint16_t a,uint8_t v)
1458 { pRAM[a & 0x07FF] = v; }
1459static void WriteMemory_ExRAM(uint16_t a,uint8_t v);
1460static void WriteMemory_SRAM(uint16_t a,uint8_t v)
1461 { pSRAM[a & 0x1FFF] = v; }
1462static void WriteMemory_FDSRAM(uint16_t a,uint8_t v)
1463 { pROM[(a >> 12) - 6][a & 0x0FFF] = v; }
1464static void WriteMemory_Default(uint16_t a,uint8_t v) { (void)a; (void)v; }
1465
1466
1467/* Read Memory Procs */
1468
1469static uint8_t ReadMemory_pAPU(uint16_t a)
1470{
1471 EmulateAPU(1);
1472
1473 if(a == 0x4015)
1474 {
1475 uint8_t ret = 0;
1476 if(mWave_Squares.nLengthCount[0]) ret |= 0x01;
1477 if(mWave_Squares.nLengthCount[1]) ret |= 0x02;
1478 if(mWave_TND.nTriLengthCount) ret |= 0x04;
1479 if(mWave_TND.nNoiseLengthCount) ret |= 0x08;
1480 if(mWave_TND.nDMCBytesRemaining) ret |= 0x10;
1481
1482 if(bFrameIRQPending) ret |= 0x40;
1483 if(mWave_TND.bDMCIRQPending) ret |= 0x80;
1484
1485 bFrameIRQPending = 0;
1486 return ret;
1487 }
1488
1489 if(!(nExternalSound & EXTSOUND_FDS)) return 0x40;
1490 if(bPALMode) return 0x40;
1491
1492 if((a >= 0x4040) && (a <= 0x407F))
1493 return mWave_FDS.nWaveTable[a & 0x3F] | 0x40;
1494 if(a == 0x4090)
1495 return (mWave_FDS.nVolEnv_Gain & 0x3F) | 0x40;
1496 if(a == 0x4092)
1497 return (mWave_FDS.nSweep_Gain & 0x3F) | 0x40;
1498
1499 return 0x40;
1500}
1501
1502static uint8_t ReadMemory_N106(uint16_t a)
1503{
1504 if(a != 0x4800)
1505 return ReadMemory_pAPU(a);
1506
1507 uint8_t ret = mWave_N106.nRAM[(mWave_N106.nCurrentAddress << 1)] |
1508 (mWave_N106.nRAM[(mWave_N106.nCurrentAddress << 1) + 1] << 4);
1509 if(mWave_N106.bAutoIncrement)
1510 mWave_N106.nCurrentAddress = (mWave_N106.nCurrentAddress + 1) & 0x7F;
1511
1512 return ret;
1513}
1514
1515 13
1516/* Write Memory Procs */ 14static int16_t samples[CHUNK_SIZE] IBSS_ATTR;
1517 15static struct Nsf_Emu nsf_emu IDATA_ATTR CACHEALIGN_ATTR;
1518static void WriteMemory_ExRAM(uint16_t a,uint8_t v)
1519{
1520 if(a < 0x5FF6) /* Invalid */
1521 return;
1522
1523 a -= 0x5FF6;
1524
1525 /* Swap out banks */
1526
1527 EmulateAPU(1);
1528 /* stop it from swapping to a bank that doesn't exist */
1529 if(v >= nROMBankCount)
1530 v = 0;
1531
1532 pROM[a] = pROM_Full + (v << 12);
1533
1534 /* Update the DMC's DMA pointer, as well */
1535 if(a >= 2)
1536 mWave_TND.pDMCDMAPtr[a - 2] = pROM[a];
1537}
1538
1539static void WriteMemory_pAPU(uint16_t a,uint8_t v)
1540{
1541 EmulateAPU(1);
1542 switch(a)
1543 {
1544 /* Square 1 */
1545 case 0x4000:
1546 mWave_Squares.nDutyCycle[0] = DUTY_CYCLE_TABLE[v >> 6];
1547 mWave_Squares.bLengthEnabled[0] =
1548 !(mWave_Squares.bDecayLoop[0] = (v & 0x20));
1549 mWave_Squares.bDecayEnable[0] = !(v & 0x10);
1550 mWave_Squares.nDecayTimer[0] = (v & 0x0F);
1551
1552 if(!mWave_Squares.bDecayEnable[0])
1553 mWave_Squares.nVolume[0] = mWave_Squares.nDecayTimer[0];
1554 break;
1555
1556 case 0x4001:
1557 mWave_Squares.bSweepEnable[0] = (v & 0x80);
1558 mWave_Squares.nSweepTimer[0] = (v & 0x70) >> 4;
1559 mWave_Squares.bSweepMode[0] = v & 0x08;
1560 mWave_Squares.nSweepShift[0] = v & 0x07;
1561 Wave_Squares_CheckSweepForcedSilence(0);
1562 break;
1563
1564 case 0x4002:
1565 mWave_Squares.nFreqTimer[0].B.l = v;
1566 Wave_Squares_CheckSweepForcedSilence(0);
1567 break;
1568
1569 case 0x4003:
1570 mWave_Squares.nFreqTimer[0].B.h = v & 0x07;
1571 Wave_Squares_CheckSweepForcedSilence(0);
1572
1573 mWave_Squares.nDecayVolume[0] = 0x0F;
1574
1575 if(mWave_Squares.bChannelEnabled[0])
1576 mWave_Squares.nLengthCount[0] = LENGTH_COUNTER_TABLE[v >> 3];
1577
1578 if(bResetDuty)
1579 mWave_Squares.nDutyCount[0] = 0;
1580 break;
1581
1582
1583 /* Square 2 */
1584 case 0x4004:
1585 mWave_Squares.nDutyCycle[1] = DUTY_CYCLE_TABLE[v >> 6];
1586 mWave_Squares.bLengthEnabled[1] =
1587 !(mWave_Squares.bDecayLoop[1] = (v & 0x20));
1588 mWave_Squares.bDecayEnable[1] = !(v & 0x10);
1589 mWave_Squares.nDecayTimer[1] = (v & 0x0F);
1590
1591 if(!mWave_Squares.bDecayEnable[1])
1592 mWave_Squares.nVolume[1] = mWave_Squares.nDecayTimer[1];
1593 break;
1594
1595 case 0x4005:
1596 mWave_Squares.bSweepEnable[1] = (v & 0x80);
1597 mWave_Squares.nSweepTimer[1] = (v & 0x70) >> 4;
1598 mWave_Squares.bSweepMode[1] = v & 0x08;
1599 mWave_Squares.nSweepShift[1] = v & 0x07;
1600 Wave_Squares_CheckSweepForcedSilence(1);
1601 break;
1602
1603 case 0x4006:
1604 mWave_Squares.nFreqTimer[1].B.l = v;
1605 Wave_Squares_CheckSweepForcedSilence(1);
1606 break;
1607
1608 case 0x4007:
1609 mWave_Squares.nFreqTimer[1].B.h = v & 0x07;
1610 Wave_Squares_CheckSweepForcedSilence(1);
1611
1612 mWave_Squares.nDecayVolume[1] = 0x0F;
1613
1614 if(mWave_Squares.bChannelEnabled[1])
1615 mWave_Squares.nLengthCount[1] = LENGTH_COUNTER_TABLE[v >> 3];
1616
1617 if(bResetDuty)
1618 mWave_Squares.nDutyCount[1] = 0;
1619 break;
1620
1621
1622 /* Triangle */
1623 case 0x4008:
1624 mWave_TND.nTriLinearLoad = v & 0x7F;
1625 mWave_TND.bTriLinearControl = v & 0x80;
1626 mWave_TND.bTriLengthEnabled = !(v & 0x80);
1627 break;
1628
1629 case 0x400A:
1630 mWave_TND.nTriFreqTimer.B.l = v;
1631 break;
1632
1633 case 0x400B:
1634 mWave_TND.nTriFreqTimer.B.h = v & 0x07;
1635 mWave_TND.bTriLinearHalt = 1;
1636
1637 if(mWave_TND.bTriChannelEnabled)
1638 mWave_TND.nTriLengthCount = LENGTH_COUNTER_TABLE[v >> 3];
1639 break;
1640
1641 /* Noise */
1642 case 0x400C:
1643 mWave_TND.bNoiseLengthEnabled =
1644 !(mWave_TND.bNoiseDecayLoop = (v & 0x20));
1645 mWave_TND.bNoiseDecayEnable = !(v & 0x10);
1646 mWave_TND.nNoiseDecayTimer = (v & 0x0F);
1647
1648 if(mWave_TND.bNoiseDecayEnable)
1649 mWave_TND.nNoiseVolume = mWave_TND.nNoiseDecayVolume;
1650 else
1651 mWave_TND.nNoiseVolume = mWave_TND.nNoiseDecayTimer;
1652 break;
1653
1654 case 0x400E:
1655 mWave_TND.nNoiseFreqTimer = NOISE_FREQ_TABLE[v & 0x0F];
1656 mWave_TND.bNoiseRandomMode = (v & 0x80) ? 6 : 1;
1657 break;
1658
1659 case 0x400F:
1660 if(mWave_TND.bNoiseChannelEnabled)
1661 mWave_TND.nNoiseLengthCount = LENGTH_COUNTER_TABLE[v >> 3];
1662
1663 mWave_TND.nNoiseDecayVolume = 0x0F;
1664 if(mWave_TND.bNoiseDecayEnable)
1665 mWave_TND.nNoiseVolume = 0x0F;
1666 break;
1667
1668 /* DMC */
1669 case 0x4010:
1670 mWave_TND.bDMCLoop = v & 0x40;
1671 mWave_TND.bDMCIRQEnabled = v & 0x80;
1672 /* IRQ can't be pending if disabled */
1673 if(!mWave_TND.bDMCIRQEnabled)
1674 mWave_TND.bDMCIRQPending = 0;
1675
1676 mWave_TND.nDMCFreqTimer = DMC_FREQ_TABLE[bPALMode][v & 0x0F];
1677 break;
1678
1679 case 0x4011:
1680 if(bIgnore4011Writes)
1681 break;
1682 v &= 0x7F;
1683 if(bDMCPopReducer)
1684 {
1685 if(bDMCPop_SamePlay)
1686 mWave_TND.nDMCOutput = v;
1687 else
1688 {
1689 if(bDMCPop_Skip)
1690 {
1691 bDMCPop_Skip = 0;
1692 break;
1693 }
1694 if(nDMCPop_Prev == v) break;
1695 if(mWave_TND.nDMCOutput == v) break;
1696 mWave_TND.nDMCOutput = nDMCPop_Prev;
1697 nDMCPop_Prev = v;
1698 bDMCPop_SamePlay = 1;
1699 }
1700 }
1701 else
1702 mWave_TND.nDMCOutput = v;
1703 break;
1704
1705 case 0x4012:
1706 mWave_TND.nDMCDMABank_Load = (v >> 6) | 0x04;
1707 mWave_TND.nDMCDMAAddr_Load = (v << 6) & 0x0FFF;
1708 break;
1709
1710 case 0x4013:
1711 mWave_TND.nDMCLength = (v << 4) + 1;
1712 break;
1713
1714 /* All / General Purpose */
1715 case 0x4015:
1716 mWave_TND.bDMCIRQPending = 0;
1717
1718 if(v & 0x01){ mWave_Squares.bChannelEnabled[0] = 1; }
1719 else { mWave_Squares.bChannelEnabled[0] =
1720 mWave_Squares.nLengthCount[0] = 0; }
1721 if(v & 0x02){ mWave_Squares.bChannelEnabled[1] = 1; }
1722 else { mWave_Squares.bChannelEnabled[1] =
1723 mWave_Squares.nLengthCount[1] = 0; }
1724 if(v & 0x04){ mWave_TND.bTriChannelEnabled = 1; }
1725 else { mWave_TND.bTriChannelEnabled =
1726 mWave_TND.nTriLengthCount = 0; }
1727 if(v & 0x08){ mWave_TND.bNoiseChannelEnabled = 1; }
1728 else { mWave_TND.bNoiseChannelEnabled =
1729 mWave_TND.nNoiseLengthCount = 0; }
1730
1731 if(v & 0x10)
1732 {
1733 if(!mWave_TND.nDMCBytesRemaining)
1734 {
1735 bDMCPop_Skip = 1;
1736 mWave_TND.nDMCDMAAddr = mWave_TND.nDMCDMAAddr_Load;
1737 mWave_TND.nDMCDMABank = mWave_TND.nDMCDMABank_Load;
1738 mWave_TND.nDMCBytesRemaining = mWave_TND.nDMCLength;
1739 mWave_TND.bDMCActive = 1;
1740 }
1741 }
1742 else
1743 mWave_TND.nDMCBytesRemaining = 0;
1744 break;
1745
1746 case 0x4017:
1747 bFrameIRQEnabled = !(v & 0x40);
1748 bFrameIRQPending = 0;
1749 nFrameCounter = 0;
1750 nFrameCounterMax = (v & 0x80) ? 4 : 3;
1751 nTicksUntilNextFrame =
1752 (bPALMode ? PAL_FRAME_COUNTER_FREQ : NTSC_FRAME_COUNTER_FREQ)
1753 * 0x10000;
1754
1755 CLOCK_MAJOR();
1756 if(v & 0x80) CLOCK_MINOR();
1757 break;
1758 }
1759
1760 if(!(nExternalSound & EXTSOUND_FDS)) return;
1761 if(bPALMode) return;
1762
1763 /* FDS Sound registers */
1764
1765 if(a < 0x4040) return;
1766
1767 /* wave table */
1768 if(a <= 0x407F)
1769 {
1770 if(mWave_FDS.bWaveWrite)
1771 mWave_FDS.nWaveTable[a - 0x4040] = v;
1772 }
1773 else
1774 {
1775 switch(a)
1776 {
1777 case 0x4080:
1778 mWave_FDS.nVolEnv_Mode = (v >> 6);
1779 if(v & 0x80)
1780 {
1781 mWave_FDS.nVolEnv_Gain = v & 0x3F;
1782 if(!mWave_FDS.nMainAddr)
1783 {
1784 if(mWave_FDS.nVolEnv_Gain < 0x20)
1785 mWave_FDS.nVolume = mWave_FDS.nVolEnv_Gain;
1786 else mWave_FDS.nVolume = 0x20;
1787 }
1788 }
1789 mWave_FDS.nVolEnv_Decay = v & 0x3F;
1790 mWave_FDS.nVolEnv_Timer =
1791 ((mWave_FDS.nVolEnv_Decay + 1) * mWave_FDS.nEnvelopeSpeed * 8);
1792
1793 mWave_FDS.bVolEnv_On = mWave_FDS.bEnvelopeEnable &&
1794 mWave_FDS.nEnvelopeSpeed && !(v & 0x80);
1795 break;
1796
1797 case 0x4082:
1798 mWave_FDS.nFreq.B.l = v;
1799 mWave_FDS.bMain_On = mWave_FDS.nFreq.W && mWave_FDS.bEnabled &&
1800 !mWave_FDS.bWaveWrite;
1801 break;
1802
1803 case 0x4083:
1804 mWave_FDS.bEnabled = !(v & 0x80);
1805 mWave_FDS.bEnvelopeEnable = !(v & 0x40);
1806 if(v & 0x80)
1807 {
1808 if(mWave_FDS.nVolEnv_Gain < 0x20)
1809 mWave_FDS.nVolume = mWave_FDS.nVolEnv_Gain;
1810 else mWave_FDS.nVolume = 0x20;
1811 }
1812 mWave_FDS.nFreq.B.h = v & 0x0F;
1813 mWave_FDS.bMain_On = mWave_FDS.nFreq.W && mWave_FDS.bEnabled &&
1814 !mWave_FDS.bWaveWrite;
1815
1816 mWave_FDS.bVolEnv_On = mWave_FDS.bEnvelopeEnable &&
1817 mWave_FDS.nEnvelopeSpeed && !(mWave_FDS.nVolEnv_Mode & 2);
1818 mWave_FDS.bSweepEnv_On = mWave_FDS.bEnvelopeEnable &&
1819 mWave_FDS.nEnvelopeSpeed && !(mWave_FDS.nSweep_Mode & 2);
1820 break;
1821
1822
1823 case 0x4084:
1824 mWave_FDS.nSweep_Mode = v >> 6;
1825 if(v & 0x80)
1826 mWave_FDS.nSweep_Gain = v & 0x3F;
1827 mWave_FDS.nSweep_Decay = v & 0x3F;
1828 mWave_FDS.nSweep_Timer =
1829 ((mWave_FDS.nSweep_Decay + 1) * mWave_FDS.nEnvelopeSpeed * 8);
1830 mWave_FDS.bSweepEnv_On =
1831 mWave_FDS.bEnvelopeEnable && mWave_FDS.nEnvelopeSpeed &&
1832 !(v & 0x80);
1833 break;
1834
1835
1836 case 0x4085:
1837 if(v & 0x40) mWave_FDS.nSweepBias = (v & 0x3F) - 0x40;
1838 else mWave_FDS.nSweepBias = v & 0x3F;
1839 mWave_FDS.nLFO_Addr = 0;
1840 break;
1841
1842
1843 case 0x4086:
1844 mWave_FDS.nLFO_Freq.B.l = v;
1845 mWave_FDS.bLFO_On =
1846 mWave_FDS.bLFO_Enabled && mWave_FDS.nLFO_Freq.W;
1847 if(mWave_FDS.nLFO_Freq.W)
1848 mWave_FDS.nLFO_Timer = (0x10000<<14) / mWave_FDS.nLFO_Freq.W;
1849 break;
1850
1851 case 0x4087:
1852 mWave_FDS.bLFO_Enabled = !(v & 0x80);
1853 mWave_FDS.nLFO_Freq.B.h = v & 0x0F;
1854 mWave_FDS.bLFO_On =
1855 mWave_FDS.bLFO_Enabled && mWave_FDS.nLFO_Freq.W;
1856 if(mWave_FDS.nLFO_Freq.W)
1857 mWave_FDS.nLFO_Timer = (0x10000<<14) / mWave_FDS.nLFO_Freq.W;
1858 break;
1859
1860 case 0x4088:
1861 if(mWave_FDS.bLFO_Enabled) break;
1862 register int32_t i;
1863 for(i = 0; i < 62; i++)
1864 mWave_FDS.nLFO_Table[i] = mWave_FDS.nLFO_Table[i + 2];
1865 mWave_FDS.nLFO_Table[62] = mWave_FDS.nLFO_Table[63] = v & 7;
1866 break;
1867
1868 case 0x4089:
1869 mWave_FDS.nMainVolume = v & 3;
1870 mWave_FDS.bWaveWrite = v & 0x80;
1871 mWave_FDS.bMain_On = mWave_FDS.nFreq.W && mWave_FDS.bEnabled &&
1872 !mWave_FDS.bWaveWrite;
1873 break;
1874
1875 case 0x408A:
1876 mWave_FDS.nEnvelopeSpeed = v;
1877 mWave_FDS.bVolEnv_On =
1878 mWave_FDS.bEnvelopeEnable &&
1879 mWave_FDS.nEnvelopeSpeed && !(mWave_FDS.nVolEnv_Mode & 2);
1880 mWave_FDS.bSweepEnv_On =
1881 mWave_FDS.bEnvelopeEnable &&
1882 mWave_FDS.nEnvelopeSpeed && !(mWave_FDS.nSweep_Mode & 2);
1883 break;
1884 }
1885 }
1886}
1887
1888static void WriteMemory_VRC6(uint16_t a,uint8_t v)
1889{
1890 EmulateAPU(1);
1891
1892 if((a < 0xA000) && (nExternalSound & EXTSOUND_VRC7)) return;
1893 else if(nExternalSound & EXTSOUND_FDS)
1894 WriteMemory_FDSRAM(a,v);
1895
1896 switch(a)
1897 {
1898 /* Pulse 1 */
1899 case 0x9000:
1900 mWave_VRC6Pulse[0].nVolume = v & 0x0F;
1901 mWave_VRC6Pulse[0].nDutyCycle = (v >> 4) & 0x07;
1902 mWave_VRC6Pulse[0].bDigitized = v & 0x80;
1903 if(mWave_VRC6Pulse[0].bDigitized)
1904 mWave_VRC6Pulse[0].nDutyCount = 0;
1905 break;
1906
1907 case 0x9001:
1908 mWave_VRC6Pulse[0].nFreqTimer.B.l = v;
1909 break;
1910
1911 case 0x9002:
1912 mWave_VRC6Pulse[0].nFreqTimer.B.h = v & 0x0F;
1913 mWave_VRC6Pulse[0].bChannelEnabled = v & 0x80;
1914 break;
1915
1916
1917 /* Pulse 2 */
1918 case 0xA000:
1919 mWave_VRC6Pulse[1].nVolume = v & 0x0F;
1920 mWave_VRC6Pulse[1].nDutyCycle = (v >> 4) & 0x07;
1921 mWave_VRC6Pulse[1].bDigitized = v & 0x80;
1922 if(mWave_VRC6Pulse[1].bDigitized)
1923 mWave_VRC6Pulse[1].nDutyCount = 0;
1924 break;
1925
1926 case 0xA001:
1927 mWave_VRC6Pulse[1].nFreqTimer.B.l = v;
1928 break;
1929
1930 case 0xA002:
1931 mWave_VRC6Pulse[1].nFreqTimer.B.h = v & 0x0F;
1932 mWave_VRC6Pulse[1].bChannelEnabled = v & 0x80;
1933 break;
1934
1935 /* Sawtooth */
1936 case 0xB000:
1937 mWave_VRC6Saw.nAccumRate = (v & 0x3F);
1938 break;
1939
1940 case 0xB001:
1941 mWave_VRC6Saw.nFreqTimer.B.l = v;
1942 break;
1943
1944 case 0xB002:
1945 mWave_VRC6Saw.nFreqTimer.B.h = v & 0x0F;
1946 mWave_VRC6Saw.bChannelEnabled = v & 0x80;
1947 break;
1948 }
1949}
1950
1951static void WriteMemory_MMC5(uint16_t a,uint8_t v)
1952{
1953 if((a <= 0x5015) && !bPALMode)
1954 {
1955 /* no audio emulation */
1956 return;
1957 }
1958
1959 if(a == 0x5205)
1960 {
1961 nMultIn_Low = v;
1962 goto multiply;
1963 }
1964 if(a == 0x5206)
1965 {
1966 nMultIn_High = v;
1967multiply:
1968 a = nMultIn_Low * nMultIn_High;
1969 pExRAM[0x205] = a & 0xFF;
1970 pExRAM[0x206] = a >> 8;
1971 return;
1972 }
1973
1974 if(a < 0x5C00) return;
1975
1976 pExRAM[a & 0x0FFF] = v;
1977 if(a >= 0x5FF6)
1978 WriteMemory_ExRAM(a,v);
1979}
1980
1981static void WriteMemory_N106(uint16_t a,uint8_t v)
1982{
1983 if(a < 0x4800)
1984 {
1985 WriteMemory_pAPU(a,v);
1986 return;
1987 }
1988
1989 if(a == 0xF800)
1990 {
1991 mWave_N106.nCurrentAddress = v & 0x7F;
1992 mWave_N106.bAutoIncrement = (v & 0x80);
1993 return;
1994 }
1995
1996 if(a == 0x4800)
1997 {
1998 EmulateAPU(1);
1999 mWave_N106.nRAM[mWave_N106.nCurrentAddress << 1] = v & 0x0F;
2000 mWave_N106.nRAM[(mWave_N106.nCurrentAddress << 1) + 1] = v >> 4;
2001 a = mWave_N106.nCurrentAddress;
2002 if(mWave_N106.bAutoIncrement)
2003 mWave_N106.nCurrentAddress =
2004 (mWave_N106.nCurrentAddress + 1) & 0x7F;
2005
2006#define N106REGWRITE(ch,r0,r1,r2,r3,r4) \
2007 case r0: if(mWave_N106.nFreqReg[ch].B.l == v) break; \
2008 mWave_N106.nFreqReg[ch].B.l = v; \
2009 mWave_N106.nFreqTimer[ch] = -1; \
2010 break; \
2011 case r1: if(mWave_N106.nFreqReg[ch].B.h == v) break; \
2012 mWave_N106.nFreqReg[ch].B.h = v; \
2013 mWave_N106.nFreqTimer[ch] = -1; \
2014 break; \
2015 case r2: if(mWave_N106.nFreqReg[ch].B.w != (v & 3)){ \
2016 mWave_N106.nFreqReg[ch].B.w = v & 0x03; \
2017 mWave_N106.nFreqTimer[ch] = -1;} \
2018 mWave_N106.nWaveSize[ch] = 0x20 - (v & 0x1C); \
2019 break; \
2020 case r3: mWave_N106.nWavePosStart[ch] = v; \
2021 break; \
2022 case r4: mWave_N106.nPreVolume[ch] = v & 0x0F; \
2023 if(!bN106PopReducer) \
2024 mWave_N106.nVolume[ch] = v & 0x0F
2025
2026 switch(a)
2027 {
2028 N106REGWRITE(0,0x40,0x42,0x44,0x46,0x47); break;
2029 N106REGWRITE(1,0x48,0x4A,0x4C,0x4E,0x4F); break;
2030 N106REGWRITE(2,0x50,0x52,0x54,0x56,0x57); break;
2031 N106REGWRITE(3,0x58,0x5A,0x5C,0x5E,0x5F); break;
2032 N106REGWRITE(4,0x60,0x62,0x64,0x66,0x67); break;
2033 N106REGWRITE(5,0x68,0x6A,0x6C,0x6E,0x6F); break;
2034 N106REGWRITE(6,0x70,0x72,0x74,0x76,0x77); break;
2035 N106REGWRITE(7,0x78,0x7A,0x7C,0x7E,0x7F);
2036 v = (v >> 4) & 7;
2037 if(mWave_N106.nActiveChannels == v) break;
2038 mWave_N106.nActiveChannels = v;
2039 mWave_N106.nFreqTimer[0] = -1;
2040 mWave_N106.nFreqTimer[1] = -1;
2041 mWave_N106.nFreqTimer[2] = -1;
2042 mWave_N106.nFreqTimer[3] = -1;
2043 mWave_N106.nFreqTimer[4] = -1;
2044 mWave_N106.nFreqTimer[5] = -1;
2045 mWave_N106.nFreqTimer[6] = -1;
2046 mWave_N106.nFreqTimer[7] = -1;
2047 break;
2048 }
2049#undef N106REGWRITE
2050 }
2051}
2052
2053static void WriteMemory_FME07(uint16_t a,uint8_t v)
2054{
2055 if((a < 0xD000) && (nExternalSound & EXTSOUND_FDS))
2056 WriteMemory_FDSRAM(a,v);
2057
2058 if(a == 0xC000)
2059 nFME07_Address = v;
2060 if(a == 0xE000)
2061 {
2062 switch(nFME07_Address)
2063 {
2064 case 0x00: mWave_FME07[0].nFreqTimer.B.l = v; break;
2065 case 0x01: mWave_FME07[0].nFreqTimer.B.h = v & 0x0F; break;
2066 case 0x02: mWave_FME07[1].nFreqTimer.B.l = v; break;
2067 case 0x03: mWave_FME07[1].nFreqTimer.B.h = v & 0x0F; break;
2068 case 0x04: mWave_FME07[2].nFreqTimer.B.l = v; break;
2069 case 0x05: mWave_FME07[2].nFreqTimer.B.h = v & 0x0F; break;
2070 case 0x07:
2071 mWave_FME07[0].bChannelEnabled = !(v & 0x01);
2072 mWave_FME07[1].bChannelEnabled = !(v & 0x02);
2073 mWave_FME07[2].bChannelEnabled = !(v & 0x03);
2074 break;
2075 case 0x08: mWave_FME07[0].nVolume = v & 0x0F; break;
2076 case 0x09: mWave_FME07[1].nVolume = v & 0x0F; break;
2077 case 0x0A: mWave_FME07[2].nVolume = v & 0x0F; break;
2078 }
2079 }
2080}
2081
2082/*
2083 * Emulate APU
2084 */
2085
2086static int32_t fulltick;
2087static void EmulateAPU(uint8_t bBurnCPUCycles)
2088{
2089 int32_t tick;
2090 int64_t diff;
2091
2092 int32_t tnd_out;
2093 int square_out1;
2094 int square_out2;
2095
2096 ENTER_TIMER(apu);
2097
2098 fulltick += (signed)(nCPUCycle - nAPUCycle);
2099
2100 int32_t burned;
2101 int32_t mixL;
2102
2103 if(bFade && nSilentSampleMax && (nSilentSamples >= nSilentSampleMax))
2104 fulltick = 0;
2105
2106 while(fulltick>0)
2107 {
2108 tick = (nTicksUntilNextSample+0xffff)>>16;
2109
2110 fulltick -= tick;
2111
2112 /*
2113 * Sample Generation
2114 */
2115
2116 ENTER_TIMER(squares);
2117 /* Square generation */
2118
2119 mWave_Squares.nFreqCount[0] -= tick;
2120 mWave_Squares.nFreqCount[1] -= tick;
2121
2122 if((mWave_Squares.nDutyCount[0] < mWave_Squares.nDutyCycle[0]) &&
2123 mWave_Squares.nLengthCount[0] &&
2124 !mWave_Squares.bSweepForceSilence[0])
2125 square_out1 = mWave_Squares.nVolume[0];
2126 else
2127 square_out1 = 0;
2128
2129 if((mWave_Squares.nDutyCount[1] < mWave_Squares.nDutyCycle[1]) &&
2130 mWave_Squares.nLengthCount[1] &&
2131 !mWave_Squares.bSweepForceSilence[1])
2132 square_out2 = mWave_Squares.nVolume[1];
2133 else
2134 square_out2 = 0;
2135
2136 mWave_Squares.nMixL = Squares_nOutputTable_L[square_out1][square_out2];
2137
2138 if(mWave_Squares.nFreqCount[0]<=0)
2139 {
2140 int cycles =
2141 (-mWave_Squares.nFreqCount[0])/
2142 (mWave_Squares.nFreqTimer[0].W + 1) + 1;
2143 mWave_Squares.nFreqCount[0] =
2144 (mWave_Squares.nFreqTimer[0].W + 1)-
2145 (-mWave_Squares.nFreqCount[0])%
2146 (mWave_Squares.nFreqTimer[0].W + 1);
2147 mWave_Squares.nDutyCount[0] =
2148 (mWave_Squares.nDutyCount[0]+cycles)%0x10;
2149 }
2150 if(mWave_Squares.nFreqCount[1]<=0)
2151 {
2152 int cycles =
2153 (-mWave_Squares.nFreqCount[1])/
2154 (mWave_Squares.nFreqTimer[1].W + 1) + 1;
2155 mWave_Squares.nFreqCount[1] =
2156 (mWave_Squares.nFreqTimer[1].W + 1)-
2157 (-mWave_Squares.nFreqCount[1])%
2158 (mWave_Squares.nFreqTimer[1].W + 1);
2159 mWave_Squares.nDutyCount[1] = (mWave_Squares.nDutyCount[1]+cycles)%
2160 0x10;
2161 }
2162 /* end of Square generation */
2163 EXIT_TIMER(squares);
2164 ENTER_TIMER(tnd);
2165
2166 ENTER_TIMER(tnd_enter);
2167
2168 burned=0;
2169
2170 /* TND generation */
2171
2172 if(mWave_TND.nNoiseFreqTimer) mWave_TND.nNoiseFreqCount -= tick;
2173
2174 if(mWave_TND.nTriFreqTimer.W > 8)
2175 mWave_TND.nTriFreqCount -= tick;
2176
2177 tnd_out = mWave_TND.nTriOutput << 11;
2178
2179 if(mWave_TND.bNoiseRandomOut && mWave_TND.nNoiseLengthCount)
2180 tnd_out |= mWave_TND.nNoiseVolume << 7;
2181
2182 tnd_out |= mWave_TND.nDMCOutput;
2183
2184 mWave_TND.nMixL = main_nOutputTable_L[tnd_out];
2185
2186 EXIT_TIMER(tnd_enter);
2187
2188 ENTER_TIMER(tnd_tri);
2189
2190 /* Tri */
2191
2192 if(mWave_TND.nTriFreqCount<=0)
2193 {
2194 if(mWave_TND.nTriLengthCount && mWave_TND.nTriLinearCount)
2195 {
2196 do mWave_TND.nTriStep++;
2197 while ((mWave_TND.nTriFreqCount +=
2198 mWave_TND.nTriFreqTimer.W + 1) <= 0);
2199 mWave_TND.nTriStep &= 0x1F;
2200
2201 if(mWave_TND.nTriStep & 0x10)
2202 mWave_TND.nTriOutput = mWave_TND.nTriStep ^ 0x1F;
2203 else mWave_TND.nTriOutput = mWave_TND.nTriStep;
2204 } else mWave_TND.nTriFreqCount=mWave_TND.nTriFreqTimer.W+1;
2205 }
2206
2207 EXIT_TIMER(tnd_tri);
2208
2209 ENTER_TIMER(tnd_noise);
2210
2211 /* Noise */
2212
2213 if(mWave_TND.nNoiseFreqTimer &&
2214 mWave_TND.nNoiseVolume && mWave_TND.nNoiseFreqCount<=0)
2215 {
2216 mWave_TND.nNoiseFreqCount = mWave_TND.nNoiseFreqTimer;
2217 mWave_TND.nNoiseRandomShift <<= 1;
2218 mWave_TND.bNoiseRandomOut = (((mWave_TND.nNoiseRandomShift <<
2219 mWave_TND.bNoiseRandomMode) ^
2220 mWave_TND.nNoiseRandomShift) & 0x8000 ) ? 1 : 0;
2221 if(mWave_TND.bNoiseRandomOut)
2222 mWave_TND.nNoiseRandomShift |= 0x01;
2223 }
2224
2225 EXIT_TIMER(tnd_noise);
2226
2227 ENTER_TIMER(tnd_dmc);
2228
2229 /* DMC */
2230 if(mWave_TND.bDMCActive)
2231 {
2232 mWave_TND.nDMCFreqCount -= tick;
2233 while (mWave_TND.nDMCFreqCount <= 0) {
2234 if (!mWave_TND.bDMCActive) {
2235 mWave_TND.nDMCFreqCount = mWave_TND.nDMCFreqTimer;
2236 break;
2237 }
2238
2239 mWave_TND.nDMCFreqCount += mWave_TND.nDMCFreqTimer;
2240
2241 if(mWave_TND.bDMCSampleBufferEmpty &&
2242 mWave_TND.nDMCBytesRemaining)
2243 {
2244 burned += 4; /* 4 cycle burn! */
2245 mWave_TND.nDMCSampleBuffer =
2246 mWave_TND.pDMCDMAPtr[mWave_TND.nDMCDMABank]
2247 [mWave_TND.nDMCDMAAddr];
2248 mWave_TND.nDMCDMAAddr++;
2249 if(mWave_TND.nDMCDMAAddr & 0x1000)
2250 {
2251 mWave_TND.nDMCDMAAddr &= 0x0FFF;
2252 mWave_TND.nDMCDMABank =
2253 (mWave_TND.nDMCDMABank + 1) & 0x07;
2254 }
2255
2256 mWave_TND.bDMCSampleBufferEmpty = 0;
2257 mWave_TND.nDMCBytesRemaining--;
2258 if(!mWave_TND.nDMCBytesRemaining)
2259 {
2260 if(mWave_TND.bDMCLoop)
2261 {
2262 mWave_TND.nDMCDMABank = mWave_TND.nDMCDMABank_Load;
2263 mWave_TND.nDMCDMAAddr = mWave_TND.nDMCDMAAddr_Load;
2264 mWave_TND.nDMCBytesRemaining =mWave_TND.nDMCLength;
2265 }
2266 else if(mWave_TND.bDMCIRQEnabled)
2267 mWave_TND.bDMCIRQPending = 1;
2268 }
2269 }
2270
2271 if(!mWave_TND.nDMCDeltaBit)
2272 {
2273 mWave_TND.nDMCDeltaBit = 8;
2274 mWave_TND.bDMCDeltaSilent =mWave_TND.bDMCSampleBufferEmpty;
2275 mWave_TND.nDMCDelta = mWave_TND.nDMCSampleBuffer;
2276 mWave_TND.bDMCSampleBufferEmpty = 1;
2277 }
2278
2279 if(mWave_TND.nDMCDeltaBit) {
2280 mWave_TND.nDMCDeltaBit--;
2281 if(!mWave_TND.bDMCDeltaSilent)
2282 {
2283 if(mWave_TND.nDMCDelta & 0x01)
2284 {
2285 if(mWave_TND.nDMCOutput < 0x7E)
2286 mWave_TND.nDMCOutput += 2;
2287 }
2288 else if(mWave_TND.nDMCOutput > 1)
2289 mWave_TND.nDMCOutput -= 2;
2290 }
2291 mWave_TND.nDMCDelta >>= 1;
2292 }
2293
2294 if(!mWave_TND.nDMCBytesRemaining &&
2295 mWave_TND.bDMCSampleBufferEmpty &&
2296 mWave_TND.bDMCDeltaSilent)
2297 mWave_TND.bDMCActive = mWave_TND.nDMCDeltaBit = 0;
2298 }
2299 }
2300
2301 EXIT_TIMER(tnd_dmc);
2302
2303 /* end of TND generation */
2304 EXIT_TIMER(tnd);
2305
2306 if(nExternalSound && !bPALMode)
2307 {
2308 if(nExternalSound & EXTSOUND_VRC6)
2309 Wave_VRC6_DoTicks(tick);
2310 if(nExternalSound & EXTSOUND_N106)
2311 Wave_N106_DoTicks(tick);
2312 if(nExternalSound & EXTSOUND_FME07)
2313 {
2314 if (mWave_FME07[0].bChannelEnabled &&
2315 mWave_FME07[0].nFreqTimer.W) {
2316 mWave_FME07[0].nFreqCount -= tick;
2317
2318 if(mWave_FME07[0].nDutyCount < 16)
2319 {
2320 mWave_FME07[0].nMixL =
2321 FME07_nOutputTable_L[mWave_FME07[0].nVolume];
2322 } else mWave_FME07[0].nMixL = 0;
2323 while(mWave_FME07[0].nFreqCount <= 0) {
2324 mWave_FME07[0].nFreqCount +=
2325 mWave_FME07[0].nFreqTimer.W;
2326
2327 mWave_FME07[0].nDutyCount=
2328 (mWave_FME07[0].nDutyCount+1)&0x1f;
2329 }
2330 }
2331
2332 if (mWave_FME07[1].bChannelEnabled &&
2333 mWave_FME07[1].nFreqTimer.W) {
2334 mWave_FME07[1].nFreqCount -= tick;
2335
2336 if(mWave_FME07[1].nDutyCount < 16)
2337 {
2338 mWave_FME07[1].nMixL =
2339 FME07_nOutputTable_L[mWave_FME07[1].nVolume];
2340 } else mWave_FME07[1].nMixL = 0;
2341 while(mWave_FME07[1].nFreqCount <= 0) {
2342 mWave_FME07[1].nFreqCount +=
2343 mWave_FME07[1].nFreqTimer.W;
2344
2345 mWave_FME07[1].nDutyCount=
2346 (mWave_FME07[1].nDutyCount+1)&0x1f;
2347 }
2348 }
2349
2350 if (mWave_FME07[2].bChannelEnabled &&
2351 mWave_FME07[2].nFreqTimer.W) {
2352 mWave_FME07[2].nFreqCount -= tick;
2353
2354 if(mWave_FME07[2].nDutyCount < 16)
2355 {
2356 mWave_FME07[2].nMixL =
2357 FME07_nOutputTable_L[mWave_FME07[2].nVolume];
2358 } else mWave_FME07[2].nMixL = 0;
2359 while(mWave_FME07[2].nFreqCount <= 0) {
2360 mWave_FME07[2].nFreqCount +=
2361 mWave_FME07[2].nFreqTimer.W;
2362
2363 mWave_FME07[2].nDutyCount=
2364 (mWave_FME07[2].nDutyCount+1)&0x1f;
2365 }
2366 }
2367
2368 } /* end FME07 */
2369 ENTER_TIMER(fds);
2370 if(nExternalSound & EXTSOUND_FDS) {
2371
2372 /* Volume Envelope Unit */
2373 if(mWave_FDS.bVolEnv_On)
2374 {
2375 mWave_FDS.nVolEnv_Count -= tick;
2376 while(mWave_FDS.nVolEnv_Count <= 0)
2377 {
2378 mWave_FDS.nVolEnv_Count += mWave_FDS.nVolEnv_Timer;
2379 if(mWave_FDS.nVolEnv_Mode) {
2380 if(mWave_FDS.nVolEnv_Gain < 0x20)
2381 mWave_FDS.nVolEnv_Gain++;
2382 }
2383 else {
2384 if(mWave_FDS.nVolEnv_Gain)
2385 mWave_FDS.nVolEnv_Gain--;
2386 }
2387 }
2388 }
2389
2390 /* Sweep Envelope Unit */
2391 if(mWave_FDS.bSweepEnv_On)
2392 {
2393 mWave_FDS.nSweep_Count -= tick;
2394 while(mWave_FDS.nSweep_Count <= 0)
2395 {
2396 mWave_FDS.nSweep_Count += mWave_FDS.nSweep_Timer;
2397 if(mWave_FDS.nSweep_Mode) {
2398 if(mWave_FDS.nSweep_Gain < 0x20)
2399 mWave_FDS.nSweep_Gain++;
2400 } else {
2401 if(mWave_FDS.nSweep_Gain) mWave_FDS.nSweep_Gain--;
2402 }
2403 }
2404 }
2405
2406 /* Effector / LFO */
2407 int32_t subfreq = 0;
2408 if(mWave_FDS.bLFO_On)
2409 {
2410 mWave_FDS.nLFO_Count -= tick<<14;
2411 while(mWave_FDS.nLFO_Count <= 0)
2412 {
2413 mWave_FDS.nLFO_Count += mWave_FDS.nLFO_Timer;
2414 if(mWave_FDS.nLFO_Table[mWave_FDS.nLFO_Addr] == 4)
2415 mWave_FDS.nSweepBias = 0;
2416 else
2417 mWave_FDS.nSweepBias +=
2418 ModulationTable[
2419 mWave_FDS.nLFO_Table[mWave_FDS.nLFO_Addr]
2420 ];
2421 mWave_FDS.nLFO_Addr = (mWave_FDS.nLFO_Addr + 1) & 0x3F;
2422 }
2423
2424 while(mWave_FDS.nSweepBias > 63)
2425 mWave_FDS.nSweepBias -= 128;
2426 while(mWave_FDS.nSweepBias < -64)
2427 mWave_FDS.nSweepBias += 128;
2428
2429 register int32_t temp =
2430 mWave_FDS.nSweepBias * mWave_FDS.nSweep_Gain;
2431 if(temp & 0x0F)
2432 {
2433 temp /= 16;
2434 if(mWave_FDS.nSweepBias < 0) temp--;
2435 else temp += 2;
2436 }
2437 else
2438 temp /= 16;
2439
2440 if(temp > 193) temp -= 258;
2441 if(temp < -64) temp += 256;
2442
2443 subfreq = mWave_FDS.nFreq.W * temp / 64;
2444 }
2445
2446 /* Main Unit */
2447 if(mWave_FDS.bMain_On)
2448 {
2449 mWave_FDS.nMixL =
2450 FDS_nOutputTable_L[mWave_FDS.nMainVolume]
2451 [mWave_FDS.nVolume]
2452 [mWave_FDS.nWaveTable[mWave_FDS.nMainAddr] ];
2453
2454 if((subfreq + mWave_FDS.nFreq.W) > 0)
2455 {
2456 int32_t freq = (0x10000<<14) / (subfreq + mWave_FDS.nFreq.W);
2457
2458 mWave_FDS.nFreqCount -= tick<<14;
2459 while(mWave_FDS.nFreqCount <= 0)
2460 {
2461 mWave_FDS.nFreqCount += freq;
2462
2463 mWave_FDS.nMainAddr =
2464 (mWave_FDS.nMainAddr + 1) & 0x3F;
2465 mWave_FDS.nPopOutput =
2466 mWave_FDS.nWaveTable[mWave_FDS.nMainAddr];
2467 if(!mWave_FDS.nMainAddr)
2468 {
2469 if(mWave_FDS.nVolEnv_Gain < 0x20)
2470 mWave_FDS.nVolume = mWave_FDS.nVolEnv_Gain;
2471 else mWave_FDS.nVolume = 0x20;
2472 }
2473 }
2474 }
2475 else
2476 mWave_FDS.nFreqCount = mWave_FDS.nLFO_Count;
2477 }
2478 else if(mWave_FDS.bPopReducer && mWave_FDS.nPopOutput)
2479 {
2480 mWave_FDS.nMixL = FDS_nOutputTable_L[mWave_FDS.nMainVolume]
2481 [mWave_FDS.nVolume]
2482 [mWave_FDS.nPopOutput];
2483
2484 mWave_FDS.nPopCount -= tick;
2485 while(mWave_FDS.nPopCount <= 0)
2486 {
2487 mWave_FDS.nPopCount += 500;
2488 mWave_FDS.nPopOutput--;
2489 if(!mWave_FDS.nPopOutput)
2490 mWave_FDS.nMainAddr = 0;
2491 }
2492 } /* end FDS */
2493 }
2494 EXIT_TIMER(fds);
2495 } /* end while fulltick */
2496
2497 if(bBurnCPUCycles)
2498 {
2499 nCPUCycle += burned;
2500 fulltick += burned;
2501 }
2502
2503 /* Frame Sequencer */
2504
2505 ENTER_TIMER(frame);
2506 nTicksUntilNextFrame -= tick<<16;
2507 while(nTicksUntilNextFrame <= 0)
2508 {
2509 nTicksUntilNextFrame +=
2510 (bPALMode ? PAL_FRAME_COUNTER_FREQ : NTSC_FRAME_COUNTER_FREQ) *
2511 0x10000;
2512 nFrameCounter++;
2513 if(nFrameCounter > nFrameCounterMax)
2514 nFrameCounter = 0;
2515
2516 if(nFrameCounterMax == 4)
2517 {
2518 if(nFrameCounter < 4)
2519 {
2520 CLOCK_MAJOR();
2521 if(!(nFrameCounter & 1))
2522 CLOCK_MINOR();
2523 }
2524 }
2525 else
2526 {
2527 CLOCK_MAJOR();
2528 if(nFrameCounter & 1)
2529 CLOCK_MINOR();
2530
2531 if((nFrameCounter == 3) && bFrameIRQEnabled)
2532 bFrameIRQPending = 1;
2533 }
2534 }
2535 EXIT_TIMER(frame);
2536
2537 ENTER_TIMER(mix);
2538 nTicksUntilNextSample -= tick<<16;
2539 if(nTicksUntilNextSample <= 0)
2540 {
2541 nTicksUntilNextSample += nTicksPerSample;
2542
2543 mixL = mWave_Squares.nMixL;
2544 mixL += mWave_TND.nMixL;
2545
2546 if(nExternalSound && !bPALMode)
2547 {
2548 if(nExternalSound & EXTSOUND_VRC6)
2549 {
2550 mixL += (mWave_VRC6Pulse[0].nMixL);
2551 mixL += (mWave_VRC6Pulse[1].nMixL);
2552 mixL += (mWave_VRC6Saw.nMixL);
2553 }
2554 if(nExternalSound & EXTSOUND_N106) {
2555 mixL += (mWave_N106.nMixL[0]);
2556 mixL += (mWave_N106.nMixL[1]);
2557 mixL += (mWave_N106.nMixL[2]);
2558 mixL += (mWave_N106.nMixL[3]);
2559 mixL += (mWave_N106.nMixL[4]);
2560 mixL += (mWave_N106.nMixL[5]);
2561 mixL += (mWave_N106.nMixL[6]);
2562 mixL += (mWave_N106.nMixL[7]);
2563 }
2564 if(nExternalSound & EXTSOUND_FME07)
2565 {
2566 mixL += (mWave_FME07[0].nMixL);
2567 mixL += (mWave_FME07[1].nMixL);
2568 mixL += (mWave_FME07[2].nMixL);
2569 }
2570 if(nExternalSound & EXTSOUND_FDS)
2571 mixL += mWave_FDS.nMixL;
2572 }
2573
2574 /* Filter */
2575 diff = ((int64_t)mixL << 25) - nFilterAccL;
2576 nFilterAccL += (diff * nHighPass) >> 16;
2577 mixL = (int32_t)(diff >> 23);
2578 /* End Filter */
2579
2580 if(bFade && (fFadeVolume < 1))
2581 mixL = (int32_t)(mixL * fFadeVolume);
2582
2583 if(mixL < -32768) mixL = -32768;
2584 if(mixL > 32767) mixL = 32767;
2585
2586 *((uint16_t*)pOutput) = (uint16_t)mixL;
2587 pOutput += 2;
2588 }
2589
2590 }
2591 EXIT_TIMER(mix);
2592
2593 nAPUCycle = nCPUCycle;
2594
2595 EXIT_TIMER(apu);
2596}
2597
2598
2599/*
2600 * Initialize
2601 *
2602 * Initializes Memory
2603 */
2604
2605static int NSFCore_Initialize()
2606{
2607 int32_t i;
2608 /* clear globals */
2609 /* why, yes, this was easier when they were in a struct */
2610
2611 /*
2612 * Memory
2613 */
2614
2615 ZEROMEMORY(pRAM,0x800);
2616 ZEROMEMORY(pSRAM,0x2000);
2617 ZEROMEMORY(pExRAM,0x1000);
2618 pROM_Full=0;
2619
2620 ZEROMEMORY(pROM,10);
2621 pStack=0;
2622
2623 nROMSize=0;
2624 nROMBankCount=0;
2625 nROMMaxSize=0;
2626
2627 /*
2628 * Memory Proc Pointers
2629 */
2630
2631 ZEROMEMORY(ReadMemory,sizeof(ReadProc)*0x10);
2632 ZEROMEMORY(WriteMemory,sizeof(WriteProc)*0x10);
2633
2634 /*
2635 * 6502 Registers / Mode
2636 */
2637
2638 regA=0;
2639 regX=0;
2640 regY=0;
2641 regP=0;
2642 regSP=0;
2643 regPC=0;
2644
2645 bPALMode=0;
2646 bCPUJammed=0;
2647
2648 nMultIn_Low=0;
2649 nMultIn_High=0;
2650
2651 /*
2652 * NSF Preparation Information
2653 */
2654
2655 ZEROMEMORY(nBankswitchInitValues,10);
2656 nPlayAddress=0;
2657 nInitAddress=0;
2658
2659 nExternalSound=0;
2660 nCurTrack=0;
2661
2662 fNSFPlaybackSpeed=0;
2663
2664 /*
2665 * pAPU
2666 */
2667
2668 nFrameCounter=0;
2669 nFrameCounterMax=0;
2670 bFrameIRQEnabled=0;
2671 bFrameIRQPending=0;
2672
2673 /*
2674 * Timing and Counters
2675 */
2676 nTicksUntilNextFrame=0;
2677
2678 nTicksPerPlay=0;
2679 nTicksUntilNextPlay=0;
2680
2681 nTicksPerSample=0;
2682 nTicksUntilNextSample=0;
2683
2684 nCPUCycle=0;
2685 nAPUCycle=0;
2686 nTotalPlays=0;
2687
2688 /*
2689 * Silence Tracker
2690 */
2691 nSilentSamples=0;
2692 nSilentSampleMax=0;
2693 nSilenceTrackMS=0;
2694 bNoSilenceIfTime=0;
2695 bTimeNotDefault=0;
2696
2697 /*
2698 * Volume/fading/filter tracking
2699 */
2700
2701 nStartFade=0;
2702 nEndFade=0;
2703 bFade=0;
2704 fFadeVolume=0;
2705 fFadeChange=0;
2706
2707 pOutput=0;
2708
2709 nDMCPop_Prev=0;
2710 bDMCPop_Skip=0;
2711 bDMCPop_SamePlay=0;
2712
2713 /*
2714 * Sound Filter
2715 */
2716
2717 nFilterAccL=0;
2718 nHighPass=0;
2719
2720 nHighPassBase=0;
2721
2722 bHighPassEnabled=0;
2723
2724 /* channels */
2725
2726 ZEROMEMORY(&mWave_Squares,sizeof(struct Wave_Squares));
2727 ZEROMEMORY(&mWave_TND,sizeof(struct Wave_TND));
2728 ZEROMEMORY(mWave_VRC6Pulse,sizeof(struct VRC6PulseWave)*2);
2729 ZEROMEMORY(&mWave_VRC6Saw,sizeof(struct VRC6SawWave));
2730 ZEROMEMORY(&mWave_N106,sizeof(struct N106Wave));
2731 ZEROMEMORY(mWave_FME07,sizeof(struct FME07Wave)*3);
2732 ZEROMEMORY(&mWave_FDS,sizeof(struct FDSWave));
2733
2734 /* end clear globals */
2735
2736 // Default filter bases
2737 nHighPassBase = 150;
2738
2739 bHighPassEnabled = 1;
2740
2741 mWave_TND.nNoiseRandomShift = 1;
2742 for(i = 0; i < 8; i++)
2743 mWave_TND.pDMCDMAPtr[i] = pROM[i + 2];
2744
2745
2746 SetPlaybackOptions(nSampleRate);
2747
2748 for(i = 0; i < 8; i++)
2749 mWave_N106.nFrequencyLookupTable[i] =
2750 ((((i + 1) * 45 * 0x40000) / (float)NES_FREQUENCY) *
2751 (float)NTSC_FREQUENCY) * 256.0;
2752
2753 ZEROMEMORY(pRAM,0x800);
2754 ZEROMEMORY(pSRAM,0x2000);
2755 ZEROMEMORY(pExRAM,0x1000);
2756 pStack = pRAM + 0x100;
2757 return 1;
2758}
2759
2760/*
2761 * LoadNSF
2762 */
2763
2764static int LoadNSF(int32_t datasize)
2765{
2766 if(!pDataBuffer) return 0;
2767
2768 int32_t i;
2769
2770 nExternalSound = nChipExtensions;
2771 if(nIsPal & 2)
2772 bPALMode = bPALPreference;
2773 else
2774 bPALMode = nIsPal & 1;
2775
2776 SetPlaybackOptions(nSampleRate);
2777
2778 int32_t neededsize = datasize + (nfileLoadAddress & 0x0FFF);
2779 if(neededsize & 0x0FFF) neededsize += 0x1000 - (neededsize & 0x0FFF);
2780 if(neededsize < 0x1000) neededsize = 0x1000;
2781
2782 uint8_t specialload = 0;
2783
2784 for(i = 0; (i < 8) && (!nBankswitch[i]); i++);
2785 if(i < 8) /* uses bankswitching */
2786 {
2787 memcpy(&nBankswitchInitValues[2],nBankswitch,8);
2788 nBankswitchInitValues[0] = nBankswitch[6];
2789 nBankswitchInitValues[1] = nBankswitch[7];
2790 if(nExternalSound & EXTSOUND_FDS)
2791 {
2792 if(!(nBankswitchInitValues[0] || nBankswitchInitValues[1]))
2793 {
2794 /*
2795 * FDS sound with '00' specified for both $6000 and $7000 banks.
2796 * point this to an area of fresh RAM (sort of hackish solution
2797 * for those FDS tunes that don't quite follow the nsf specs.
2798 */
2799 nBankswitchInitValues[0] = (uint8_t)(neededsize >> 12);
2800 nBankswitchInitValues[1] = (uint8_t)(neededsize >> 12) + 1;
2801 neededsize += 0x2000;
2802 }
2803 }
2804 }
2805 else /* doesn't use bankswitching */
2806 {
2807 if(nExternalSound & EXTSOUND_FDS)
2808 {
2809 /* bad load address */
2810 if(nfileLoadAddress < 0x6000) return 0;
2811
2812 if(neededsize < 0xA000)
2813 neededsize = 0xA000;
2814 specialload = 1;
2815 for(i = 0; i < 10; i++)
2816 nBankswitchInitValues[i] = (uint8_t)i;
2817 }
2818 else
2819 {
2820 /* bad load address */
2821 if(nfileLoadAddress < 0x8000) return 0;
2822
2823 int32_t j = (nfileLoadAddress >> 12) - 6;
2824 for(i = 0; i < j; i++)
2825 nBankswitchInitValues[i] = 0;
2826 for(j = 0; i < 10; i++, j++)
2827 nBankswitchInitValues[i] = (uint8_t)j;
2828 }
2829 }
2830
2831 nROMSize = neededsize;
2832 nROMBankCount = neededsize >> 12;
2833
2834 if(specialload)
2835 pROM_Full = pDataBuffer-(nfileLoadAddress-0x6000);
2836 else
2837 pROM_Full = pDataBuffer-(nfileLoadAddress&0x0FFF);
2838
2839 ZEROMEMORY(pRAM,0x0800);
2840 ZEROMEMORY(pExRAM,0x1000);
2841 ZEROMEMORY(pSRAM,0x2000);
2842
2843 nExternalSound = nChipExtensions;
2844 fNSFPlaybackSpeed = (bPALMode ? PAL_NMIRATE : NTSC_NMIRATE);
2845
2846 SetPlaybackSpeed(0);
2847
2848 nPlayAddress = nfilePlayAddress;
2849 nInitAddress = nfileInitAddress;
2850
2851 pExRAM[0x00] = 0x20; /* JSR */
2852 pExRAM[0x01] = nInitAddress&0xff; /* Init Address */
2853 pExRAM[0x02] = (nInitAddress>>8)&0xff;
2854 pExRAM[0x03] = 0xF2; /* JAM */
2855 pExRAM[0x04] = 0x20; /* JSR */
2856 pExRAM[0x05] = nPlayAddress&0xff; /* Play Address */
2857 pExRAM[0x06] = (nPlayAddress>>8)&0xff;
2858 pExRAM[0x07] = 0x4C; /* JMP */
2859 pExRAM[0x08] = 0x03;/* $5003 (JAM right before the JSR to play address) */
2860 pExRAM[0x09] = 0x50;
2861
2862 regA = regX = regY = 0;
2863 regP = 0x04; /* I_FLAG */
2864 regSP = 0xFF;
2865
2866 nFilterAccL = 0;
2867
2868 /* Reset Read/Write Procs */
2869
2870 ReadMemory[0] = ReadMemory[1] = ReadMemory_RAM;
2871 ReadMemory[2] = ReadMemory[3] = ReadMemory_Default;
2872 ReadMemory[4] = ReadMemory_pAPU;
2873 ReadMemory[5] = ReadMemory_ExRAM;
2874 ReadMemory[6] = ReadMemory[7] = ReadMemory_SRAM;
2875
2876 WriteMemory[0] = WriteMemory[1] = WriteMemory_RAM;
2877 WriteMemory[2] = WriteMemory[3] = WriteMemory_Default;
2878 WriteMemory[4] = WriteMemory_pAPU;
2879 WriteMemory[5] = WriteMemory_ExRAM;
2880 WriteMemory[6] = WriteMemory[7] = WriteMemory_SRAM;
2881
2882 for(i = 8; i < 16; i++)
2883 {
2884 ReadMemory[i] = ReadMemory_ROM;
2885 WriteMemory[i] = WriteMemory_Default;
2886 }
2887
2888 if(nExternalSound & EXTSOUND_FDS)
2889 {
2890 WriteMemory[0x06] = WriteMemory_FDSRAM;
2891 WriteMemory[0x07] = WriteMemory_FDSRAM;
2892 WriteMemory[0x08] = WriteMemory_FDSRAM;
2893 WriteMemory[0x09] = WriteMemory_FDSRAM;
2894 WriteMemory[0x0A] = WriteMemory_FDSRAM;
2895 WriteMemory[0x0B] = WriteMemory_FDSRAM;
2896 WriteMemory[0x0C] = WriteMemory_FDSRAM;
2897 WriteMemory[0x0D] = WriteMemory_FDSRAM;
2898 ReadMemory[0x06] = ReadMemory_ROM;
2899 ReadMemory[0x07] = ReadMemory_ROM;
2900 }
2901
2902 if(!bPALMode) /* no expansion sound available on a PAL system */
2903 {
2904 if(nExternalSound & EXTSOUND_VRC6)
2905 {
2906 /* if both VRC6+VRC7... it MUST go to WriteMemory_VRC6
2907 * or register writes will be lost (WriteMemory_VRC6 calls
2908 * WriteMemory_VRC7 if needed) */
2909 WriteMemory[0x09] = WriteMemory_VRC6;
2910 WriteMemory[0x0A] = WriteMemory_VRC6;
2911 WriteMemory[0x0B] = WriteMemory_VRC6;
2912 }
2913 if(nExternalSound & EXTSOUND_N106)
2914 {
2915 WriteMemory[0x04] = WriteMemory_N106;
2916 ReadMemory[0x04] = ReadMemory_N106;
2917 WriteMemory[0x0F] = WriteMemory_N106;
2918 }
2919 if(nExternalSound & EXTSOUND_FME07)
2920 {
2921 WriteMemory[0x0C] = WriteMemory_FME07;
2922 WriteMemory[0x0E] = WriteMemory_FME07;
2923 }
2924 }
2925
2926 /* MMC5 still has a multiplication reg that needs to be available on
2927 PAL tunes */
2928 if(nExternalSound & EXTSOUND_MMC5)
2929 WriteMemory[0x05] = WriteMemory_MMC5;
2930
2931 return 1;
2932}
2933
2934/*
2935 * SetTrack
2936 */
2937
2938static void SetTrack(uint8_t track)
2939{
2940 int32_t i;
2941
2942 nCurTrack = track;
2943
2944 regPC = 0x5000;
2945 regA = track;
2946 regX = bPALMode;
2947 regY = bCleanAXY ? 0 : 0xCD;
2948 regSP = 0xFF;
2949 if(bCleanAXY)
2950 regP = 0x04;
2951 bCPUJammed = 0;
2952
2953 nCPUCycle = nAPUCycle = 0;
2954 nDMCPop_Prev = 0;
2955 bDMCPop_Skip = 0;
2956
2957 for(i = 0x4000; i < 0x400F; i++)
2958 WriteMemory_pAPU(i,0);
2959 WriteMemory_pAPU(0x4010,0);
2960 WriteMemory_pAPU(0x4012,0);
2961 WriteMemory_pAPU(0x4013,0);
2962 WriteMemory_pAPU(0x4014,0);
2963 WriteMemory_pAPU(0x4015,0);
2964 WriteMemory_pAPU(0x4015,0x0F);
2965 WriteMemory_pAPU(0x4017,0);
2966
2967 for(i = 0; i < 10; i++)
2968 WriteMemory_ExRAM(0x5FF6 + i,nBankswitchInitValues[i]);
2969
2970 ZEROMEMORY(pRAM,0x0800);
2971 ZEROMEMORY(pSRAM,0x2000);
2972 ZEROMEMORY(&pExRAM[0x10],0x0FF0);
2973 bFade = 0;
2974
2975
2976 nTicksUntilNextSample = nTicksPerSample;
2977 nTicksUntilNextFrame =
2978 (bPALMode ? PAL_FRAME_COUNTER_FREQ : NTSC_FRAME_COUNTER_FREQ)*0x10000;
2979 nTicksUntilNextPlay = nTicksPerPlay;
2980 nTotalPlays = 0;
2981
2982 /* Clear mixing vals */
2983 mWave_Squares.nMixL = 0;
2984 mWave_TND.nMixL = 0;
2985 mWave_VRC6Pulse[0].nMixL = 0;
2986 mWave_VRC6Pulse[1].nMixL = 0;
2987 mWave_VRC6Saw.nMixL = 0;
2988
2989 /* Reset Tri/Noise/DMC */
2990 mWave_TND.nTriStep = mWave_TND.nTriOutput = 0;
2991 mWave_TND.nDMCOutput = 0;
2992 mWave_TND.bNoiseRandomOut = 0;
2993 mWave_Squares.nDutyCount[0] = mWave_Squares.nDutyCount[1] = 0;
2994 mWave_TND.bDMCActive = 0;
2995 mWave_TND.nDMCBytesRemaining = 0;
2996 mWave_TND.bDMCSampleBufferEmpty = 1;
2997 mWave_TND.bDMCDeltaSilent = 1;
2998
2999 /* Reset VRC6 */
3000 mWave_VRC6Pulse[0].nVolume = 0;
3001 mWave_VRC6Pulse[1].nVolume = 0;
3002 mWave_VRC6Saw.nAccumRate = 0;
3003
3004 /* Reset N106 */
3005 ZEROMEMORY(mWave_N106.nRAM,0x100);
3006 ZEROMEMORY(mWave_N106.nVolume,8);
3007 ZEROMEMORY(mWave_N106.nOutput,8);
3008 ZEROMEMORY(mWave_N106.nMixL,32);
3009
3010 /* Reset FME-07 */
3011 mWave_FME07[0].nVolume = 0;
3012 mWave_FME07[1].nVolume = 0;
3013 mWave_FME07[2].nVolume = 0;
3014
3015 /* Clear FDS crap */
3016
3017 mWave_FDS.bEnvelopeEnable = 0;
3018 mWave_FDS.nEnvelopeSpeed = 0xFF;
3019 mWave_FDS.nVolEnv_Mode = 2;
3020 mWave_FDS.nVolEnv_Decay = 0;
3021 mWave_FDS.nVolEnv_Gain = 0;
3022 mWave_FDS.nVolume = 0;
3023 mWave_FDS.bVolEnv_On = 0;
3024 mWave_FDS.nSweep_Mode = 2;
3025 mWave_FDS.nSweep_Decay = 0;
3026 mWave_FDS.nSweep_Gain = 0;
3027 mWave_FDS.bSweepEnv_On = 0;
3028 mWave_FDS.nSweepBias = 0;
3029 mWave_FDS.bLFO_Enabled = 0;
3030 mWave_FDS.nLFO_Freq.W = 0;
3031/* mWave_FDS.fLFO_Timer = 0;
3032 mWave_FDS.fLFO_Count = 0;*/
3033 mWave_FDS.nLFO_Timer = 0;
3034 mWave_FDS.nLFO_Count = 0;
3035 mWave_FDS.nLFO_Addr = 0;
3036 mWave_FDS.bLFO_On = 0;
3037 mWave_FDS.nMainVolume = 0;
3038 mWave_FDS.bEnabled = 0;
3039 mWave_FDS.nFreq.W = 0;
3040/* mWave_FDS.fFreqCount = 0;*/
3041 mWave_FDS.nFreqCount = 0;
3042 mWave_FDS.nMainAddr = 0;
3043 mWave_FDS.bWaveWrite = 0;
3044 mWave_FDS.bMain_On = 0;
3045 mWave_FDS.nMixL = 0;
3046 ZEROMEMORY(mWave_FDS.nWaveTable,0x40);
3047 ZEROMEMORY(mWave_FDS.nLFO_Table,0x40);
3048
3049 mWave_FDS.nSweep_Count = mWave_FDS.nSweep_Timer =
3050 ((mWave_FDS.nSweep_Decay + 1) * mWave_FDS.nEnvelopeSpeed * 8);
3051 mWave_FDS.nVolEnv_Count = mWave_FDS.nVolEnv_Timer =
3052 ((mWave_FDS.nVolEnv_Decay + 1) * mWave_FDS.nEnvelopeSpeed * 8);
3053
3054 nSilentSamples = 0;
3055
3056 nFilterAccL = 0;
3057
3058 nSilentSamples = 0;
3059
3060 fulltick=0;
3061}
3062
3063/*
3064 * SetPlaybackOptions
3065 */
3066
3067static int SetPlaybackOptions(int32_t samplerate)
3068{
3069 if(samplerate < 2000) return 0;
3070 if(samplerate > 96000) return 0;
3071
3072 nTicksPerSample =
3073 (bPALMode ? PAL_FREQUENCY : NTSC_FREQUENCY) / samplerate * 0x10000;
3074 nTicksUntilNextSample = nTicksPerSample;
3075
3076 RecalcFilter();
3077 RecalcSilenceTracker();
3078
3079 return 1;
3080}
3081
3082/*
3083 * SetPlaybackSpeed
3084 */
3085
3086static void SetPlaybackSpeed(float playspersec)
3087{
3088 if(playspersec < 1)
3089 {
3090 playspersec = fNSFPlaybackSpeed;
3091 }
3092
3093 nTicksPerPlay = nTicksUntilNextPlay =
3094 (bPALMode ? PAL_FREQUENCY : NTSC_FREQUENCY) / playspersec * 0x10000;
3095}
3096
3097/*
3098* GetPlaybackSpeed
3099*/
3100
3101static float GetPlaybackSpeed()
3102{
3103 if(nTicksPerPlay <= 0) return 0;
3104 return ((bPALMode ? PAL_FREQUENCY : NTSC_FREQUENCY) / (nTicksPerPlay>>16));
3105}
3106
3107/*
3108 * RecalcFilter
3109 */
3110
3111static void RecalcFilter()
3112{
3113 if(!nSampleRate) return;
3114
3115 nHighPass = ((int64_t)nHighPassBase << 16) / nSampleRate;
3116
3117 if(nHighPass > (1<<16)) nHighPass = 1<<16;
3118}
3119
3120/*
3121 * RecalcSilenceTracker
3122 */
3123
3124static void RecalcSilenceTracker()
3125{
3126 if(nSilenceTrackMS <= 0 || !nSampleRate ||
3127 (bNoSilenceIfTime && bTimeNotDefault))
3128 {
3129 nSilentSampleMax = 0;
3130 return;
3131 }
3132
3133 nSilentSampleMax = nSilenceTrackMS * nSampleRate / 500;
3134 nSilentSampleMax /= 2;
3135}
3136
3137static void RebuildOutputTables(void) {
3138 int32_t i,j;
3139 float l[3];
3140 int32_t temp;
3141 float ftemp;
3142
3143 /* tnd */
3144 for(i = 0; i < 3; i++)
3145 {
3146 l[i] = 255;
3147 }
3148
3149 for(i = 0; i < 0x8000; i++)
3150 {
3151 ftemp = (l[0] * (i >> 11)) / 2097885;
3152 ftemp += (l[1] * ((i >> 7) & 0x0F)) / 3121455;
3153 ftemp += (l[2] * (i & 0x7F)) / 5772690;
3154
3155 if(!ftemp)
3156 main_nOutputTable_L[i] = 0;
3157 else
3158 main_nOutputTable_L[i] =
3159 (int16_t)(2396850 / ((1.0f / ftemp) + 100));
3160 }
3161
3162 /* squares */
3163 for(i = 0; i < 2; i++)
3164 {
3165 l[i] = 255;
3166 }
3167
3168 for(j = 0; j < 0x10; j++)
3169 {
3170 for(i = 0; i < 0x10; i++)
3171 {
3172 temp = (int32_t)(l[0] * j);
3173 temp += (int32_t)(l[1] * i);
3174
3175 if(!temp)
3176 Squares_nOutputTable_L[j][i] = 0;
3177 else
3178 Squares_nOutputTable_L[j][i] = 1438200 / ((2072640 / temp) + 100);
3179 }
3180 }
3181
3182 /* VRC6 Pulse 1,2 */
3183 for(i = 0; i < 0x10; i++)
3184 {
3185 VRC6Pulse_nOutputTable_L[i] =
3186 1875 * i / 0x0F;
3187 }
3188 /* VRC6 Saw */
3189 for(i = 0; i < 0x20; i++)
3190 {
3191 VRC6Saw_nOutputTable_L[i] = 3750 * i / 0x1F;
3192 }
3193
3194 /* N106 channels */
3195 /* this amplitude is just a guess */
3196
3197 for(i = 0; i < 0x10; i++)
3198 {
3199 for(j = 0; j < 0x10; j++)
3200 {
3201 N106_nOutputTable_L[i][j] = (3000 * i * j) / 0xE1;
3202 }
3203 }
3204
3205 /* FME-07 Square A,B,C */
3206 FME07_nOutputTable_L[15] = 3000;
3207 FME07_nOutputTable_L[0] = 0;
3208 for(i = 14; i > 0; i--)
3209 {
3210 FME07_nOutputTable_L[i] = FME07_nOutputTable_L[i + 1] * 80 / 100;
3211 }
3212
3213 /*
3214 * FDS
3215 */
3216 /* this base volume (4000) is just a guess to what sounds right.
3217 * Given the number of steps available in an FDS wave... it seems like
3218 * it should be much much more... but then it's TOO loud.
3219 */
3220 for(i = 0; i < 0x21; i++)
3221 {
3222 for(j = 0; j < 0x40; j++)
3223 {
3224 FDS_nOutputTable_L[0][i][j] =
3225 (4000 * i * j * 30) / (0x21 * 0x40 * 30);
3226 FDS_nOutputTable_L[1][i][j] =
3227 (4000 * i * j * 20) / (0x21 * 0x40 * 30);
3228 FDS_nOutputTable_L[2][i][j] =
3229 (4000 * i * j * 15) / (0x21 * 0x40 * 30);
3230 FDS_nOutputTable_L[3][i][j] =
3231 (4000 * i * j * 12) / (0x21 * 0x40 * 30);
3232 }
3233 }
3234}
3235
3236/* rockbox: not used */
3237#if 0
3238/*
3239 * GetPlayCalls
3240 */
3241
3242float GetPlayCalls()
3243{
3244 if(!nTicksPerPlay) return 0;
3245
3246 return ((float)nTotalPlays) +
3247 (1.0f - (nTicksUntilNextPlay*1.0f / nTicksPerPlay));
3248}
3249
3250/*
3251 * GetWrittenTime
3252 */
3253uint32_t GetWrittenTime(float basedplayspersec /* = 0 */)
3254{
3255 if(basedplayspersec <= 0)
3256 basedplayspersec = GetPlaybackSpeed();
3257
3258 if(basedplayspersec <= 0)
3259 return 0;
3260
3261 return (uint32_t)((GetPlayCalls() * 1000) / basedplayspersec);
3262}
3263
3264/*
3265 * StopFade
3266 */
3267void StopFade()
3268{
3269 bFade = 0;
3270 fFadeVolume = 1;
3271}
3272#endif
3273
3274/*
3275 * SongCompleted
3276 */
3277
3278static uint8_t SongCompleted()
3279{
3280 if(!bFade) return 0;
3281 if(nTotalPlays >= nEndFade) return 1;
3282 if(nSilentSampleMax) return (nSilentSamples >= nSilentSampleMax);
3283
3284 return 0;
3285}
3286
3287/*
3288 * SetFade
3289 */
3290
3291static void SetFade(int32_t fadestart,int32_t fadestop,
3292 uint8_t bNotDefault) /* play routine calls */
3293{
3294 if(fadestart < 0) fadestart = 0;
3295 if(fadestop < fadestart) fadestop = fadestart;
3296
3297 nStartFade = (uint32_t)fadestart;
3298 nEndFade = (uint32_t)fadestop;
3299 bFade = 1;
3300 bTimeNotDefault = bNotDefault;
3301
3302 RecalcSilenceTracker();
3303 RecalculateFade();
3304}
3305
3306/*
3307 * SetFadeTime
3308 */
3309
3310static void SetFadeTime(uint32_t fadestart,uint32_t fadestop,float basedplays,
3311 uint8_t bNotDefault) /* time in MS */
3312{
3313 if(basedplays <= 0)
3314 basedplays = GetPlaybackSpeed();
3315 if(basedplays <= 0)
3316 return;
3317
3318 SetFade((int32_t)(fadestart * basedplays / 1000),
3319 (int32_t)(fadestop * basedplays / 1000),bNotDefault);
3320}
3321
3322/*
3323 * RecalculateFade
3324 */
3325
3326static void RecalculateFade()
3327{
3328 if(!bFade) return;
3329
3330 /* make it hit silence a little before the song ends...
3331 otherwise we're not really fading OUT, we're just fading umm...
3332 quieter =P */
3333 int32_t temp = (int32_t)(GetPlaybackSpeed() / 4);
3334
3335 if(nEndFade <= nStartFade)
3336 {
3337 nEndFade = nStartFade;
3338 fFadeChange = 1.0f;
3339 }
3340 else if((nEndFade - temp) <= nStartFade)
3341 fFadeChange = 1.0f;
3342 else
3343 fFadeChange = 1.0f / (nEndFade - nStartFade - temp);
3344
3345 if(nTotalPlays < nStartFade)
3346 fFadeVolume = 1.0f;
3347 else if(nTotalPlays >= nEndFade)
3348 fFadeVolume = 0.0f;
3349 else
3350 {
3351 fFadeVolume = 1.0f - ( (nTotalPlays - nStartFade + 1) * fFadeChange );
3352 if(fFadeVolume < 0)
3353 fFadeVolume = 0;
3354 }
3355
3356}
3357
3358static int32_t GetSamples(uint8_t* buffer,int32_t buffersize)
3359{
3360 if(!buffer) return 0;
3361 if(buffersize < 16) return 0;
3362 if(bFade && (nTotalPlays >= nEndFade)) return 0;
3363
3364 pOutput = buffer;
3365 uint32_t runtocycle =
3366 (uint32_t)((buffersize / 2) * nTicksPerSample / 0x10000);
3367 nCPUCycle = nAPUCycle = 0;
3368 uint32_t tick;
3369
3370 while(1)
3371 {
3372 /*tick = (uint32_t)ceil(fTicksUntilNextPlay);*/
3373 tick = (nTicksUntilNextPlay+0xffff)>>16;
3374 if((tick + nCPUCycle) > runtocycle)
3375 tick = runtocycle - nCPUCycle;
3376
3377 if(bCPUJammed)
3378 {
3379 nCPUCycle += tick;
3380 EmulateAPU(0);
3381 }
3382 else
3383 {
3384 tick = Emulate6502(tick + nCPUCycle);
3385 EmulateAPU(1);
3386 }
3387
3388 nTicksUntilNextPlay -= tick<<16;
3389 if(nTicksUntilNextPlay <= 0)
3390 {
3391 nTicksUntilNextPlay += nTicksPerPlay;
3392 if((bCPUJammed == 2) || bNoWaitForReturn)
3393 {
3394 regX = regY = regA = (bCleanAXY ? 0 : 0xCD);
3395 regPC = 0x5004;
3396 nTotalPlays++;
3397 bDMCPop_SamePlay = 0;
3398 bCPUJammed = 0;
3399 if(nForce4017Write == 1) WriteMemory_pAPU(0x4017,0x00);
3400 if(nForce4017Write == 2) WriteMemory_pAPU(0x4017,0x80);
3401 }
3402
3403 if(bFade && (nTotalPlays >= nStartFade))
3404 {
3405 fFadeVolume -= fFadeChange;
3406 if(fFadeVolume < 0)
3407 fFadeVolume = 0;
3408 if(nTotalPlays >= nEndFade)
3409 break;
3410 }
3411 }
3412
3413 if(nCPUCycle >= runtocycle)
3414 break;
3415 }
3416
3417 nCPUCycle = nAPUCycle = 0;
3418
3419 if(nSilentSampleMax && bFade)
3420 {
3421 int16_t* tempbuf = (int16_t*)buffer;
3422 while( ((uint8_t*)tempbuf) < pOutput)
3423 {
3424 if( (*tempbuf < -SILENCE_THRESHOLD) ||
3425 (*tempbuf > SILENCE_THRESHOLD) )
3426 nSilentSamples = 0;
3427 else
3428 {
3429 if(++nSilentSamples >= nSilentSampleMax)
3430 return (int32_t)( ((uint8_t*)tempbuf) - buffer);
3431 }
3432 tempbuf++;
3433 }
3434 }
3435
3436 return (int32_t)(pOutput - buffer);
3437}
3438
3439/****************** 6502 emulation ******************/
3440
3441/* Memory reading/writing and other defines */
3442
3443/* reads zero page memory */
3444#define Zp(a) pRAM[a]
3445/* reads zero page memory in word form */
3446#define ZpWord(a) (Zp(a) | (Zp((uint8_t)(a + 1)) << 8))
3447/* reads memory */
3448#define Rd(a) ((ReadMemory[((uint16_t)(a)) >> 12])(a))
3449/* reads memory in word form */
3450#define RdWord(a) (Rd(a) | (Rd(a + 1) << 8))
3451/* writes memory */
3452#define Wr(a,v) (WriteMemory[((uint16_t)(a)) >> 12])(a,v)
3453/* writes zero paged memory */
3454#define WrZ(a,v) pRAM[a] = v
3455/* pushes a value onto the stack */
3456#define PUSH(v) pStack[SP--] = v
3457/* pulls a value from the stack */
3458#define PULL(v) v = pStack[++SP]
3459
3460/* Addressing Modes */
3461
3462/* first set - gets the value that's being addressed */
3463/*Immediate*/
3464#define Ad_VlIm() val = Rd(PC.W); PC.W++
3465/*Zero Page*/
3466#define Ad_VlZp() final.W = Rd(PC.W); val = Zp(final.W); PC.W++
3467/*Zero Page, X*/
3468#define Ad_VlZx() front.W = final.W = Rd(PC.W); final.B.l += X; \
3469 val = Zp(final.B.l); PC.W++
3470/*Zero Page, Y*/
3471#define Ad_VlZy() front.W = final.W = Rd(PC.W); final.B.l += Y; \
3472 val = Zp(final.B.l); PC.W++
3473/*Absolute*/
3474#define Ad_VlAb() final.W = RdWord(PC.W); val = Rd(final.W); PC.W += 2
3475/*Absolute, X [uses extra cycle if crossed page]*/
3476#define Ad_VlAx() front.W = final.W = RdWord(PC.W); final.W += X; PC.W += 2;\
3477 if(front.B.h != final.B.h) nCPUCycle++; val = Rd(final.W)
3478/*Absolute, X [uses extra cycle if crossed page]*/
3479#define Ad_VlAy() front.W = final.W = RdWord(PC.W); final.W += Y; PC.W += 2;\
3480 if(front.B.h != final.B.h) nCPUCycle++; val = Rd(final.W)
3481/*(Indirect, X)*/
3482#define Ad_VlIx() front.W = final.W = Rd(PC.W); final.B.l += X; PC.W++; \
3483 final.W = ZpWord(final.B.l); val = Rd(final.W)
3484/*(Indirect), Y [uses extra cycle if crossed page]*/
3485#define Ad_VlIy() val = Rd(PC.W); front.W = final.W = ZpWord(val); PC.W++;\
3486 final.W += Y; if(final.B.h != front.B.h) nCPUCycle++; \
3487 front.W = val; val = Rd(final.W)
3488
3489/* second set - gets the ADDRESS that the mode is referring to (for operators
3490 * that write to memory) note that AbsoluteX, AbsoluteY, and
3491 * IndirectY modes do NOT check for page boundary crossing here
3492 * since that extra cycle isn't added for operators that write to
3493 * memory (it only applies to ones that only read from memory.. in
3494 * which case the 1st set should be used)
3495 */
3496/*Zero Page*/
3497#define Ad_AdZp() final.W = Rd(PC.W); PC.W++
3498/*Zero Page, X*/
3499#define Ad_AdZx() final.W = front.W = Rd(PC.W); final.B.l += X; PC.W++
3500/*Zero Page, Y*/
3501#define Ad_AdZy() final.W = front.W = Rd(PC.W); final.B.l += Y; PC.W++
3502/*Absolute*/
3503#define Ad_AdAb() final.W = RdWord(PC.W); PC.W += 2
3504/*Absolute, X*/
3505#define Ad_AdAx() front.W = final.W = RdWord(PC.W); PC.W += 2; \
3506 final.W += X
3507/*Absolute, Y*/
3508#define Ad_AdAy() front.W = final.W = RdWord(PC.W); PC.W += 2; \
3509 final.W += Y
3510/*(Indirect, X)*/
3511#define Ad_AdIx() front.W = final.W = Rd(PC.W); PC.W++; final.B.l += X; \
3512 final.W = ZpWord(final.B.l)
3513/*(Indirect), Y*/
3514#define Ad_AdIy() front.W = Rd(PC.W); final.W = ZpWord(front.W) + Y; \
3515 PC.W++
3516
3517/* third set - reads memory, performs the desired operation on the value, then
3518 * writes back to memory
3519 * used for operators that directly change memory (ASL, INC, DEC, etc)
3520 */
3521/*Zero Page*/
3522#define MRW_Zp(cmd) Ad_AdZp(); val = Zp(final.W); cmd(val); WrZ(final.W,val)
3523/*Zero Page, X*/
3524#define MRW_Zx(cmd) Ad_AdZx(); val = Zp(final.W); cmd(val); WrZ(final.W,val)
3525/*Zero Page, Y*/
3526#define MRW_Zy(cmd) Ad_AdZy(); val = Zp(final.W); cmd(val); WrZ(final.W,val)
3527/*Absolute*/
3528#define MRW_Ab(cmd) Ad_AdAb(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3529/*Absolute, X*/
3530#define MRW_Ax(cmd) Ad_AdAx(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3531/*Absolute, Y*/
3532#define MRW_Ay(cmd) Ad_AdAy(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3533/*(Indirect, X)*/
3534#define MRW_Ix(cmd) Ad_AdIx(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3535/*(Indirect), Y*/
3536#define MRW_Iy(cmd) Ad_AdIy(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3537
3538/* Relative modes are special in that they're only used by branch commands
3539 * this macro handles the jump, and should only be called if the branch
3540 * condition was true if the branch condition was false, the PC must be
3541 * incremented
3542 */
3543
3544#define RelJmp(cond) val = Rd(PC.W); PC.W++; final.W = PC.W + (int8_t)(val);\
3545 if(cond) {\
3546 nCPUCycle += ((final.B.h != PC.B.h) ? 2 : 1);\
3547 PC.W = final.W; }
3548
3549/* Status Flags */
3550
3551#define C_FLAG 0x01 /* carry flag */
3552#define Z_FLAG 0x02 /* zero flag */
3553#define I_FLAG 0x04 /* mask interrupt flag */
3554#define D_FLAG 0x08 /* decimal flag (decimal mode is unsupported on
3555 NES) */
3556#define B_FLAG 0x10 /* break flag (not really in the status register
3557 It's value in ST is never used. When ST is
3558 put in memory (by an interrupt or PHP), this
3559 flag is set only if BRK was called)
3560 ** also when PHP is called due to a bug */
3561#define R_FLAG 0x20 /* reserved flag (not really in the register.
3562 It's value is never used.
3563 Whenever ST is put in memory,
3564 this flag is always set) */
3565#define V_FLAG 0x40 /* overflow flag */
3566#define N_FLAG 0x80 /* sign flag */
3567
3568
3569/* Lookup Tables */
3570
3571/* the number of CPU cycles used for each instruction */
3572static const uint8_t CPU_Cycles[0x100] ICONST_ATTR_NSF_LARGE_IRAM = {
35737,6,0,8,3,3,5,5,3,2,2,2,4,4,6,6,
35742,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
35756,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,
35762,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
35776,6,0,8,3,3,5,5,3,2,2,2,3,4,6,6,
35782,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
35796,6,0,8,3,3,5,5,4,2,2,2,5,4,6,6,
35802,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
35812,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
35822,6,0,6,4,4,4,4,2,5,2,5,5,5,5,5,
35832,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
35842,5,0,5,4,4,4,4,2,4,2,4,4,4,4,4,
35852,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
35862,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
35872,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
35882,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 };
3589
3590/* the status of the NZ flags for the given value */
3591static const uint8_t NZTable[0x100] ICONST_ATTR_NSF_LARGE_IRAM = {
3592Z_FLAG,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
35930,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
35940,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
35950,0,0,0,0,0,0,0,0,0,0,
3596N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3597N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3598N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3599N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3600N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3601N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3602N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3603N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3604N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3605N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3606N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
3607N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG };
3608
3609/* A quick macro for working with the above table */
3610#define UpdateNZ(v) ST = (ST & ~(N_FLAG|Z_FLAG)) | NZTable[v]
3611
3612
3613/*
3614 * Opcodes
3615 *
3616 * These opcodes perform the action with the given value (changing that
3617 * value if necessary). Registers and flags associated with the operation
3618 * are changed accordingly. There are a few exceptions which will be noted
3619 * when they arise
3620 */
3621
3622
3623/* ADC
3624 Adds the value to the accumulator with carry
3625 Changes: A, NVZC
3626 - Decimal mode not supported on the NES
3627 - Due to a bug, NVZ flags are not altered if the Decimal flag is on
3628 --(taken out)-- */
3629#define ADC() \
3630 tw.W = A + val + (ST & C_FLAG); \
3631 ST = (ST & (I_FLAG|D_FLAG)) | tw.B.h | NZTable[tw.B.l] | \
3632 ( (0x80 & ~(A ^ val) & (A ^ tw.B.l)) ? V_FLAG : 0 ); \
3633 A = tw.B.l
3634
3635/* AND
3636 Combines the value with the accumulator using a bitwise AND operation
3637 Changes: A, NZ */
3638#define AND() \
3639 A &= val; \
3640 UpdateNZ(A)
3641
3642/* ASL
3643 Left shifts the value 1 bit. The bit that gets shifted out goes to
3644 the carry flag.
3645 Changes: value, NZC */
3646#define ASL(value) \
3647 tw.W = value << 1; \
3648 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | tw.B.h | NZTable[tw.B.l]; \
3649 value = tw.B.l
3650
3651/* BIT
3652 Compares memory with the accumulator with an AND operation, but changes
3653 neither.
3654 The two high bits of memory get transferred to the status reg
3655 Z is set if the AND operation yielded zero, otherwise it's cleared
3656 Changes: NVZ */
3657#define BIT() \
3658 ST = (ST & ~(N_FLAG|V_FLAG|Z_FLAG)) | (val & (N_FLAG|V_FLAG)) | \
3659 ((A & val) ? 0 : Z_FLAG)
3660
3661/* CMP, CPX, CPY
3662 Compares memory with the given register with a subtraction operation.
3663 Flags are set accordingly depending on the result:
3664 Reg < Memory: Z=0, C=0
3665 Reg = Memory: Z=1, C=1
3666 Reg > Memory: Z=0, C=1
3667 N is set according to the result of the subtraction operation
3668 Changes: NZC
3669
3670 NOTE -- CMP, CPX, CPY all share this same routine, so the desired
3671 register (A, X, or Y respectively) must be given when calling
3672 this macro... as well as the memory to compare it with. */
3673#define CMP(reg) \
3674 tw.W = reg - val; \
3675 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | (tw.B.h ? 0 : C_FLAG) | \
3676 NZTable[tw.B.l]
3677
3678/* DEC, DEX, DEY
3679 Decriments a value by one.
3680 Changes: value, NZ */
3681#define DEC(value) \
3682 value--; \
3683 UpdateNZ(value)
3684
3685/* EOR
3686 Combines a value with the accumulator using a bitwise exclusive-OR
3687 operation
3688 Changes: A, NZ */
3689#define EOR() \
3690 A ^= val; \
3691 UpdateNZ(A)
3692
3693/* INC, INX, INY
3694 Incriments a value by one.
3695 Changes: value, NZ */
3696#define INC(value) \
3697 value++; \
3698 UpdateNZ(value)
3699
3700/* LSR
3701 Shifts value one bit to the right. Bit that gets shifted out goes to
3702 the Carry flag.
3703 Changes: value, NZC */
3704#define LSR(value) \
3705 tw.W = value >> 1; \
3706 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[tw.B.l] | \
3707 (value & 0x01); \
3708 value = tw.B.l
3709
3710/* ORA
3711 Combines a value with the accumulator using a bitwise inclusive-OR
3712 operation
3713 Changes: A, NZ */
3714#define ORA() \
3715 A |= val; \
3716 UpdateNZ(A)
3717
3718/* ROL
3719 Rotates a value one bit to the left:
3720 C <- 7<-6<-5<-4<-3<-2<-1<-0 <- C
3721 Changes: value, NZC */
3722#define ROL(value) \
3723 tw.W = (value << 1) | (ST & 0x01); \
3724 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[tw.B.l] | tw.B.h; \
3725 value = tw.B.l
3726
3727/* ROR
3728 Rotates a value one bit to the right:
3729 C -> 7->6->5->4->3->2->1->0 -> C
3730 Changes: value, NZC */
3731#define ROR(value) \
3732 tw.W = (value >> 1) | (ST << 7); \
3733 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[tw.B.l] | \
3734 (value & 0x01); \
3735 value = tw.B.l
3736
3737/* SBC
3738 Subtracts a value from the accumulator with borrow (inverted carry)
3739 Changes: A, NVZC
3740 - Decimal mode not supported on the NES
3741 - Due to a bug, NVZ flags are not altered if the Decimal flag is on
3742 --(taken out)-- */
3743#define SBC() \
3744 tw.W = A - val - ((ST & C_FLAG) ? 0 : 1); \
3745 ST = (ST & (I_FLAG|D_FLAG)) | (tw.B.h ? 0 : C_FLAG) | NZTable[tw.B.l] | \
3746 (((A ^ val) & (A ^ tw.B.l) & 0x80) ? V_FLAG : 0); \
3747 A = tw.B.l
3748
3749/* Undocumented Opcodes
3750 *
3751 * These opcodes are not included in the official specifications. However,
3752 * some of the unused opcode values perform operations which have since been
3753 * documented.
3754 */
3755
3756
3757/* ASO
3758 Left shifts a value, then ORs the result with the accumulator
3759 Changes: value, A, NZC */
3760#define ASO(value) \
3761 tw.W = value << 1; \
3762 A |= tw.B.l; \
3763 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[A] | tw.B.h; \
3764 value = tw.B.l
3765
3766/* RLA
3767 Roll memory left 1 bit, then AND the result with the accumulator
3768 Changes: value, A, NZC */
3769#define RLA(value) \
3770 tw.W = (value << 1) | (ST & 0x01); \
3771 A &= tw.B.l; \
3772 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[A] | tw.B.h; \
3773 value = tw.B.l
3774
3775/* LSE
3776 Right shifts a value one bit, then EORs the result with the accumulator
3777 Changes: value, A, NZC */
3778#define LSE(value) \
3779 tw.W = value >> 1; \
3780 A ^= tw.B.l; \
3781 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[A] | (value & 0x01); \
3782 value = tw.B.l
3783
3784/* RRA
3785 Roll memory right one bit, then ADC the result
3786 Changes: value, A, NVZC */
3787#define RRA(value) \
3788 tw.W = (value >> 1) | (ST << 7); \
3789 ST = (ST & ~C_FLAG) | (value & 0x01); \
3790 value = tw.B.l; \
3791 ADC()
3792
3793/* AXS
3794 ANDs the contents of the X and A registers and stores the result
3795 int memory.
3796 Changes: value [DOES NOT CHANGE X, A, or any flags] */
3797#define AXS(value) \
3798 value = A & X
3799
3800/* DCM
3801 Decriments a value and compares it with the A register.
3802 Changes: value, NZC */
3803#define DCM(value) \
3804 value--; \
3805 CMP(A)
3806
3807/* INS
3808 Incriments a value then SBCs it
3809 Changes: value, A, NVZC */
3810#define INS(value) \
3811 value++; \
3812 SBC()
3813
3814/* AXA */
3815#define AXA(value) \
3816 value = A & X & (Rd(PC.W - 1) + 1)
3817
3818
3819/* The 6502 emulation function! */
3820
3821static uint8_t val;
3822static uint8_t op;
3823
3824static uint32_t Emulate6502(uint32_t runto)
3825{
3826 /* If the CPU is jammed... don't bother */
3827 if(bCPUJammed == 1)
3828 return 0;
3829
3830 register union TWIN tw; /* used in calculations */
3831 register uint8_t ST = regP;
3832 register union TWIN PC;
3833 uint8_t SP = regSP;
3834 register uint8_t A = regA;
3835 register uint8_t X = regX;
3836 register uint8_t Y = regY;
3837 union TWIN front;
3838 union TWIN final;
3839 PC.W = regPC;
3840
3841 uint32_t ret = nCPUCycle;
3842
3843 ENTER_TIMER(cpu);
3844
3845 /* Start the loop */
3846
3847 while(nCPUCycle < runto)
3848 {
3849 op = Rd(PC.W);
3850 PC.W++;
3851
3852 nCPUCycle += CPU_Cycles[op];
3853 switch(op)
3854 {
3855 /* Documented Opcodes first */
3856
3857 /* Flag setting/clearing */
3858 case 0x18: ST &= ~C_FLAG; break; /* CLC */
3859 case 0x38: ST |= C_FLAG; break; /* SEC */
3860 case 0x58: ST &= ~I_FLAG; break; /* CLI */
3861 case 0x78: ST |= I_FLAG; break; /* SEI */
3862 case 0xB8: ST &= ~V_FLAG; break; /* CLV */
3863 case 0xD8: ST &= ~D_FLAG; break; /* CLD */
3864 case 0xF8: ST |= D_FLAG; break; /* SED */
3865
3866 /* Branch commands */
3867 case 0x10: RelJmp(!(ST & N_FLAG)); break; /* BPL */
3868 case 0x30: RelJmp( (ST & N_FLAG)); break; /* BMI */
3869 case 0x50: RelJmp(!(ST & V_FLAG)); break; /* BVC */
3870 case 0x70: RelJmp( (ST & V_FLAG)); break; /* BVS */
3871 case 0x90: RelJmp(!(ST & C_FLAG)); break; /* BCC */
3872 case 0xB0: RelJmp( (ST & C_FLAG)); break; /* BCS */
3873 case 0xD0: RelJmp(!(ST & Z_FLAG)); break; /* BNE */
3874 case 0xF0: RelJmp( (ST & Z_FLAG)); break; /* BEQ */
3875
3876 /* Direct stack alteration commands (push/pull commands) */
3877 case 0x08: PUSH(ST | R_FLAG | B_FLAG); break; /* PHP */
3878 case 0x28: PULL(ST); break; /* PLP */
3879 case 0x48: PUSH(A); break; /* PHA */
3880 case 0x68: PULL(A); UpdateNZ(A); break; /* PLA */
3881
3882 /* Register Transfers */
3883 case 0x8A: A = X; UpdateNZ(A); break; /* TXA */
3884 case 0x98: A = Y; UpdateNZ(A); break; /* TYA */
3885 case 0x9A: SP = X; break; /* TXS */
3886 case 0xA8: Y = A; UpdateNZ(A); break; /* TAY */
3887 case 0xAA: X = A; UpdateNZ(A); break; /* TAX */
3888 case 0xBA: X = SP; UpdateNZ(X); break; /* TSX */
3889
3890 /* Other commands */
3891
3892 /* ADC */
3893 case 0x61: Ad_VlIx(); ADC(); break;
3894 case 0x65: Ad_VlZp(); ADC(); break;
3895 case 0x69: Ad_VlIm(); ADC(); break;
3896 case 0x6D: Ad_VlAb(); ADC(); break;
3897 case 0x71: Ad_VlIy(); ADC(); break;
3898 case 0x75: Ad_VlZx(); ADC(); break;
3899 case 0x79: Ad_VlAy(); ADC(); break;
3900 case 0x7D: Ad_VlAx(); ADC(); break;
3901
3902 /* AND */
3903 case 0x21: Ad_VlIx(); AND(); break;
3904 case 0x25: Ad_VlZp(); AND(); break;
3905 case 0x29: Ad_VlIm(); AND(); break;
3906 case 0x2D: Ad_VlAb(); AND(); break;
3907 case 0x31: Ad_VlIy(); AND(); break;
3908 case 0x35: Ad_VlZx(); AND(); break;
3909 case 0x39: Ad_VlAy(); AND(); break;
3910 case 0x3D: Ad_VlAx(); AND(); break;
3911
3912 /* ASL */
3913 case 0x0A: ASL(A); break;
3914 case 0x06: MRW_Zp(ASL); break;
3915 case 0x0E: MRW_Ab(ASL); break;
3916 case 0x16: MRW_Zx(ASL); break;
3917 case 0x1E: MRW_Ax(ASL); break;
3918
3919 /* BIT */
3920 case 0x24: Ad_VlZp(); BIT(); break;
3921 case 0x2C: Ad_VlAb(); BIT(); break;
3922
3923 /* BRK */
3924 case 0x00:
3925 if(bIgnoreBRK)
3926 break;
3927 PC.W++; /*BRK has a padding byte*/
3928 PUSH(PC.B.h); /*push high byte of the return address*/
3929 PUSH(PC.B.l); /*push low byte of return address*/
3930 PUSH(ST | R_FLAG | B_FLAG); /*push processor status with R|B flags*/
3931 ST |= I_FLAG; /*mask interrupts*/
3932 PC.W = RdWord(0xFFFE); /*read the IRQ vector and jump to it*/
3933
3934 /* extra check to make sure we didn't hit an infinite BRK loop */
3935 if(!Rd(PC.W)) /* next command will be BRK */
3936 {
3937 /* the CPU will endlessly loop...
3938 just jam it to ease processing power */
3939 bCPUJammed = 1;
3940 goto jammed;
3941 }
3942 break;
3943
3944 /* CMP */
3945 case 0xC1: Ad_VlIx(); CMP(A); break;
3946 case 0xC5: Ad_VlZp(); CMP(A); break;
3947 case 0xC9: Ad_VlIm(); CMP(A); break;
3948 case 0xCD: Ad_VlAb(); CMP(A); break;
3949 case 0xD1: Ad_VlIy(); CMP(A); break;
3950 case 0xD5: Ad_VlZx(); CMP(A); break;
3951 case 0xD9: Ad_VlAy(); CMP(A); break;
3952 case 0xDD: Ad_VlAx(); CMP(A); break;
3953
3954 /* CPX */
3955 case 0xE0: Ad_VlIm(); CMP(X); break;
3956 case 0xE4: Ad_VlZp(); CMP(X); break;
3957 case 0xEC: Ad_VlAb(); CMP(X); break;
3958
3959 /* CPY */
3960 case 0xC0: Ad_VlIm(); CMP(Y); break;
3961 case 0xC4: Ad_VlZp(); CMP(Y); break;
3962 case 0xCC: Ad_VlAb(); CMP(Y); break;
3963
3964 /* DEC */
3965 case 0xCA: DEC(X); break; /* DEX */
3966 case 0x88: DEC(Y); break; /* DEY */
3967 case 0xC6: MRW_Zp(DEC); break;
3968 case 0xCE: MRW_Ab(DEC); break;
3969 case 0xD6: MRW_Zx(DEC); break;
3970 case 0xDE: MRW_Ax(DEC); break;
3971
3972 /* EOR */
3973 case 0x41: Ad_VlIx(); EOR(); break;
3974 case 0x45: Ad_VlZp(); EOR(); break;
3975 case 0x49: Ad_VlIm(); EOR(); break;
3976 case 0x4D: Ad_VlAb(); EOR(); break;
3977 case 0x51: Ad_VlIy(); EOR(); break;
3978 case 0x55: Ad_VlZx(); EOR(); break;
3979 case 0x59: Ad_VlAy(); EOR(); break;
3980 case 0x5D: Ad_VlAx(); EOR(); break;
3981
3982 /* INC */
3983 case 0xE8: INC(X); break; /* INX */
3984 case 0xC8: INC(Y); break; /* INY */
3985 case 0xE6: MRW_Zp(INC); break;
3986 case 0xEE: MRW_Ab(INC); break;
3987 case 0xF6: MRW_Zx(INC); break;
3988 case 0xFE: MRW_Ax(INC); break;
3989
3990 /* JMP */
3991 /* Absolute JMP */
3992 case 0x4C: final.W = RdWord(PC.W); PC.W = final.W; val = 0; break;
3993 /* Indirect JMP -- must take caution:
3994 Indirection at 01FF will read from 01FF and 0100 (not 0200) */
3995 case 0x6C: front.W = final.W = RdWord(PC.W);
3996 PC.B.l = Rd(final.W); final.B.l++;
3997 PC.B.h = Rd(final.W); final.W = PC.W;
3998 break;
3999 /* JSR */
4000 case 0x20:
4001 val = 0;
4002 final.W = RdWord(PC.W);
4003 PC.W++; /* JSR only increments the return address by one.
4004 It's incremented again upon RTS */
4005 PUSH(PC.B.h); /* push high byte of return address */
4006 PUSH(PC.B.l); /* push low byte of return address */
4007 PC.W = final.W;
4008 break;
4009
4010 /* LDA */
4011 case 0xA1: Ad_VlIx(); A = val; UpdateNZ(A); break;
4012 case 0xA5: Ad_VlZp(); A = val; UpdateNZ(A); break;
4013 case 0xA9: Ad_VlIm(); A = val; UpdateNZ(A); break;
4014 case 0xAD: Ad_VlAb(); A = val; UpdateNZ(A); break;
4015 case 0xB1: Ad_VlIy(); A = val; UpdateNZ(A); break;
4016 case 0xB5: Ad_VlZx(); A = val; UpdateNZ(A); break;
4017 case 0xB9: Ad_VlAy(); A = val; UpdateNZ(A); break;
4018 case 0xBD: Ad_VlAx(); A = val; UpdateNZ(A); break;
4019
4020 /* LDX */
4021 case 0xA2: Ad_VlIm(); X = val; UpdateNZ(X); break;
4022 case 0xA6: Ad_VlZp(); X = val; UpdateNZ(X); break;
4023 case 0xAE: Ad_VlAb(); X = val; UpdateNZ(X); break;
4024 case 0xB6: Ad_VlZy(); X = val; UpdateNZ(X); break;
4025 case 0xBE: Ad_VlAy(); X = val; UpdateNZ(X); break;
4026
4027 /* LDY */
4028 case 0xA0: Ad_VlIm(); Y = val; UpdateNZ(Y); break;
4029 case 0xA4: Ad_VlZp(); Y = val; UpdateNZ(Y); break;
4030 case 0xAC: Ad_VlAb(); Y = val; UpdateNZ(Y); break;
4031 case 0xB4: Ad_VlZx(); Y = val; UpdateNZ(Y); break;
4032 case 0xBC: Ad_VlAx(); Y = val; UpdateNZ(Y); break;
4033
4034 /* LSR */
4035 case 0x4A: LSR(A); break;
4036 case 0x46: MRW_Zp(LSR); break;
4037 case 0x4E: MRW_Ab(LSR); break;
4038 case 0x56: MRW_Zx(LSR); break;
4039 case 0x5E: MRW_Ax(LSR); break;
4040
4041 /* NOP */
4042 case 0xEA:
4043
4044 /* --- Undocumented ---
4045 These opcodes perform the same action as NOP */
4046 case 0x1A: case 0x3A: case 0x5A:
4047 case 0x7A: case 0xDA: case 0xFA: break;
4048
4049 /* ORA */
4050 case 0x01: Ad_VlIx(); ORA(); break;
4051 case 0x05: Ad_VlZp(); ORA(); break;
4052 case 0x09: Ad_VlIm(); ORA(); break;
4053 case 0x0D: Ad_VlAb(); ORA(); break;
4054 case 0x11: Ad_VlIy(); ORA(); break;
4055 case 0x15: Ad_VlZx(); ORA(); break;
4056 case 0x19: Ad_VlAy(); ORA(); break;
4057 case 0x1D: Ad_VlAx(); ORA(); break;
4058
4059 /* ROL */
4060 case 0x2A: ROL(A); break;
4061 case 0x26: MRW_Zp(ROL); break;
4062 case 0x2E: MRW_Ab(ROL); break;
4063 case 0x36: MRW_Zx(ROL); break;
4064 case 0x3E: MRW_Ax(ROL); break;
4065
4066 /* ROR */
4067 case 0x6A: ROR(A); break;
4068 case 0x66: MRW_Zp(ROR); break;
4069 case 0x6E: MRW_Ab(ROR); break;
4070 case 0x76: MRW_Zx(ROR); break;
4071 case 0x7E: MRW_Ax(ROR); break;
4072
4073 /* RTI */
4074 case 0x40:
4075 PULL(ST); /*pull processor status*/
4076 PULL(PC.B.l); /*pull low byte of return address*/
4077 PULL(PC.B.h); /*pull high byte of return address*/
4078 break;
4079
4080 /* RTS */
4081 case 0x60:
4082 PULL(PC.B.l);
4083 PULL(PC.B.h);
4084 PC.W++; /* the return address is one less of what it needs */
4085 break;
4086
4087 /* SBC */
4088 case 0xE1: Ad_VlIx(); SBC(); break;
4089 case 0xE5: Ad_VlZp(); SBC(); break;
4090 /* - Undocumented - EB performs the same operation as SBC immediate */
4091 case 0xEB:
4092 case 0xE9: Ad_VlIm(); SBC(); break;
4093 case 0xED: Ad_VlAb(); SBC(); break;
4094 case 0xF1: Ad_VlIy(); SBC(); break;
4095 case 0xF5: Ad_VlZx(); SBC(); break;
4096 case 0xF9: Ad_VlAy(); SBC(); break;
4097 case 0xFD: Ad_VlAx(); SBC(); break;
4098
4099 /* STA */
4100 case 0x81: Ad_AdIx(); val = A; Wr(final.W,A); break;
4101 case 0x85: Ad_AdZp(); val = A; WrZ(final.W,A); break;
4102 case 0x8D: Ad_AdAb(); val = A; Wr(final.W,A); break;
4103 case 0x91: Ad_AdIy(); val = A; Wr(final.W,A); break;
4104 case 0x95: Ad_AdZx(); val = A; WrZ(final.W,A); break;
4105 case 0x99: Ad_AdAy(); val = A; Wr(final.W,A); break;
4106 case 0x9D: Ad_AdAx(); val = A; Wr(final.W,A); break;
4107
4108 /* STX */
4109 case 0x86: Ad_AdZp(); val = X; WrZ(final.W,X); break;
4110 case 0x8E: Ad_AdAb(); val = X; Wr(final.W,X); break;
4111 case 0x96: Ad_AdZy(); val = X; WrZ(final.W,X); break;
4112
4113 /* STY */
4114 case 0x84: Ad_AdZp(); val = Y; WrZ(final.W,Y); break;
4115 case 0x8C: Ad_AdAb(); val = Y; Wr(final.W,Y); break;
4116 case 0x94: Ad_AdZx(); val = Y; WrZ(final.W,Y); break;
4117
4118 /* Undocumented Opcodes */
4119 /* ASO */
4120 case 0x03: if(bIgnoreIllegalOps) break; MRW_Ix(ASO); break;
4121 case 0x07: if(bIgnoreIllegalOps) break; MRW_Zp(ASO); break;
4122 case 0x0F: if(bIgnoreIllegalOps) break; MRW_Ab(ASO); break;
4123 case 0x13: if(bIgnoreIllegalOps) break; MRW_Iy(ASO); break;
4124 case 0x17: if(bIgnoreIllegalOps) break; MRW_Zx(ASO); break;
4125 case 0x1B: if(bIgnoreIllegalOps) break; MRW_Ay(ASO); break;
4126 case 0x1F: if(bIgnoreIllegalOps) break; MRW_Ax(ASO); break;
4127
4128 /* RLA */
4129 case 0x23: if(bIgnoreIllegalOps) break; MRW_Ix(RLA); break;
4130 case 0x27: if(bIgnoreIllegalOps) break; MRW_Zp(RLA); break;
4131 case 0x2F: if(bIgnoreIllegalOps) break; MRW_Ab(RLA); break;
4132 case 0x33: if(bIgnoreIllegalOps) break; MRW_Iy(RLA); break;
4133 case 0x37: if(bIgnoreIllegalOps) break; MRW_Zx(RLA); break;
4134 case 0x3B: if(bIgnoreIllegalOps) break; MRW_Ay(RLA); break;
4135 case 0x3F: if(bIgnoreIllegalOps) break; MRW_Ax(RLA); break;
4136
4137 /* LSE */
4138 case 0x43: if(bIgnoreIllegalOps) break; MRW_Ix(LSE); break;
4139 case 0x47: if(bIgnoreIllegalOps) break; MRW_Zp(LSE); break;
4140 case 0x4F: if(bIgnoreIllegalOps) break; MRW_Ab(LSE); break;
4141 case 0x53: if(bIgnoreIllegalOps) break; MRW_Iy(LSE); break;
4142 case 0x57: if(bIgnoreIllegalOps) break; MRW_Zx(LSE); break;
4143 case 0x5B: if(bIgnoreIllegalOps) break; MRW_Ay(LSE); break;
4144 case 0x5F: if(bIgnoreIllegalOps) break; MRW_Ax(LSE); break;
4145
4146 /* RRA */
4147 case 0x63: if(bIgnoreIllegalOps) break; MRW_Ix(RRA); break;
4148 case 0x67: if(bIgnoreIllegalOps) break; MRW_Zp(RRA); break;
4149 case 0x6F: if(bIgnoreIllegalOps) break; MRW_Ab(RRA); break;
4150 case 0x73: if(bIgnoreIllegalOps) break; MRW_Iy(RRA); break;
4151 case 0x77: if(bIgnoreIllegalOps) break; MRW_Zx(RRA); break;
4152 case 0x7B: if(bIgnoreIllegalOps) break; MRW_Ay(RRA); break;
4153 case 0x7F: if(bIgnoreIllegalOps) break; MRW_Ax(RRA); break;
4154
4155 /* AXS */
4156 case 0x83: if(bIgnoreIllegalOps) break; MRW_Ix(AXS); break;
4157 case 0x87: if(bIgnoreIllegalOps) break; MRW_Zp(AXS); break;
4158 case 0x8F: if(bIgnoreIllegalOps) break; MRW_Ab(AXS); break;
4159 case 0x97: if(bIgnoreIllegalOps) break; MRW_Zy(AXS); break;
4160
4161 /* LAX */
4162 case 0xA3: if(bIgnoreIllegalOps) break;
4163 Ad_VlIx(); X = A = val; UpdateNZ(A); break;
4164 case 0xA7: if(bIgnoreIllegalOps) break;
4165 Ad_VlZp(); X = A = val; UpdateNZ(A); break;
4166 case 0xAF: if(bIgnoreIllegalOps) break;
4167 Ad_VlAb(); X = A = val; UpdateNZ(A); break;
4168 case 0xB3: if(bIgnoreIllegalOps) break;
4169 Ad_VlIy(); X = A = val; UpdateNZ(A); break;
4170 case 0xB7: if(bIgnoreIllegalOps) break;
4171 Ad_VlZy(); X = A = val; UpdateNZ(A); break;
4172 case 0xBF: if(bIgnoreIllegalOps) break;
4173 Ad_VlAy(); X = A = val; UpdateNZ(A); break;
4174
4175 /* DCM */
4176 case 0xC3: if(bIgnoreIllegalOps) break; MRW_Ix(DCM); break;
4177 case 0xC7: if(bIgnoreIllegalOps) break; MRW_Zp(DCM); break;
4178 case 0xCF: if(bIgnoreIllegalOps) break; MRW_Ab(DCM); break;
4179 case 0xD3: if(bIgnoreIllegalOps) break; MRW_Iy(DCM); break;
4180 case 0xD7: if(bIgnoreIllegalOps) break; MRW_Zx(DCM); break;
4181 case 0xDB: if(bIgnoreIllegalOps) break; MRW_Ay(DCM); break;
4182 case 0xDF: if(bIgnoreIllegalOps) break; MRW_Ax(DCM); break;
4183
4184 /* INS */
4185 case 0xE3: if(bIgnoreIllegalOps) break; MRW_Ix(INS); break;
4186 case 0xE7: if(bIgnoreIllegalOps) break; MRW_Zp(INS); break;
4187 case 0xEF: if(bIgnoreIllegalOps) break; MRW_Ab(INS); break;
4188 case 0xF3: if(bIgnoreIllegalOps) break; MRW_Iy(INS); break;
4189 case 0xF7: if(bIgnoreIllegalOps) break; MRW_Zx(INS); break;
4190 case 0xFB: if(bIgnoreIllegalOps) break; MRW_Ay(INS); break;
4191 case 0xFF: if(bIgnoreIllegalOps) break; MRW_Ax(INS); break;
4192
4193 /* ALR
4194 AND Accumulator with memory and LSR the result */
4195 case 0x4B: if(bIgnoreIllegalOps) break;
4196 Ad_VlIm(); A &= val; LSR(A); break;
4197
4198 /* ARR
4199 ANDs memory with the Accumulator and RORs the result */
4200 case 0x6B: if(bIgnoreIllegalOps) break;
4201 Ad_VlIm(); A &= val; ROR(A); break;
4202
4203 /* XAA
4204 Transfers X -> A, then ANDs A with memory */
4205 case 0x8B: if(bIgnoreIllegalOps) break;
4206 Ad_VlIm(); A = X & val; UpdateNZ(A); break;
4207
4208 /* OAL
4209 OR the Accumulator with #EE, AND Accumulator with Memory,
4210 Transfer A -> X */
4211 case 0xAB: if(bIgnoreIllegalOps) break;
4212 Ad_VlIm(); X = (A &= (val | 0xEE));
4213 UpdateNZ(A); break;
4214
4215 /* SAX
4216 ANDs A and X registers (does not change A), subtracts memory
4217 from result (CMP style, not SBC style) result is stored in X */
4218 case 0xCB: if(bIgnoreIllegalOps) break;
4219 Ad_VlIm(); tw.W = (X & A) - val; X = tw.B.l;
4220 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[X] |
4221 (tw.B.h ? C_FLAG : 0); break;
4222 /* SKB
4223 Skip Byte... or DOP - Double No-Op
4224 These bytes do nothing, but take a parameter (which can be
4225 ignored) */
4226 case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64:
4227 case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2:
4228 case 0xF4:
4229 if(bIgnoreIllegalOps) break;
4230 PC.W++; /* skip unused byte */
4231 break;
4232
4233 /* SKW
4234 Swip Word... or TOP - Tripple No-Op
4235 These bytes are the same as SKB, only they take a 2 byte parameter.
4236 This can be ignored in some cases, but the read needs to be
4237 performed in a some cases because an extra clock cycle may be used
4238 in the process */
4239 /* Absolute address... no need for operator */
4240 case 0x0C:
4241 if(bIgnoreIllegalOps) break;
4242 PC.W += 2; break;
4243 /* Absolute X address... may cross page, have to perform the read */
4244 case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC:
4245 if(bIgnoreIllegalOps) break;
4246 Ad_VlAx(); break;
4247
4248 /* HLT / JAM
4249 Jams up CPU operation */
4250 case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52:
4251 case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2:
4252 /*it's not -really- jammed... only the NSF code has ended*/
4253 if(PC.W == 0x5004) bCPUJammed = 2;
4254 else
4255 {
4256 if(bIgnoreIllegalOps) break;
4257 bCPUJammed = 1;
4258 }
4259 goto jammed;
4260
4261 /* TAS */
4262 case 0x9B:
4263 if(bIgnoreIllegalOps) break;
4264 Ad_AdAy();
4265 SP = A & X & (Rd(PC.W - 1) + 1);
4266 Wr(final.W,SP);
4267 break;
4268
4269 /* SAY */
4270 case 0x9C:
4271 if(bIgnoreIllegalOps) break;
4272 Ad_AdAx();
4273 Y &= (Rd(PC.W - 1) + 1);
4274 Wr(final.W,Y);
4275 break;
4276
4277 /* XAS */
4278 case 0x9E:
4279 if(bIgnoreIllegalOps) break;
4280 Ad_AdAy();
4281 X &= (Rd(PC.W - 1) + 1);
4282 Wr(final.W,X);
4283 break;
4284
4285 /* AXA */
4286 case 0x93: if(bIgnoreIllegalOps) break; MRW_Iy(AXA); break;
4287 case 0x9F: if(bIgnoreIllegalOps) break; MRW_Ay(AXA); break;
4288
4289 /* ANC */
4290 case 0x0B: case 0x2B:
4291 if(bIgnoreIllegalOps) break;
4292 Ad_VlIm();
4293 A &= val;
4294 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) |
4295 NZTable[A] | ((A & 0x80) ? C_FLAG : 0);
4296 break;
4297
4298 /* LAS */
4299 case 0xBB:
4300 if(bIgnoreIllegalOps) break;
4301 Ad_VlAy();
4302 X = A = (SP &= val);
4303 UpdateNZ(A);
4304 break;
4305 }
4306 }
4307
4308jammed:
4309 regPC = PC.W;
4310 regA = A;
4311 regX = X;
4312 regY = Y;
4313 regSP = SP;
4314 regP = ST;
4315
4316 EXIT_TIMER(cpu);
4317
4318 return (nCPUCycle - ret);
4319}
4320 16
4321/****************** rockbox interface ******************/ 17/****************** rockbox interface ******************/
4322 18
4323/** Operational info **/ 19static void set_codec_track(int t, int multitrack) {
4324static int track = 0; 20 Nsf_start_track(&nsf_emu, t);
4325static char last_path[MAX_PATH];
4326static int dontresettrack = 0;
4327static bool repeat_one = false;
4328
4329static void set_codec_track(int t, int d) {
4330 int track,fade,def=0;
4331 SetTrack(t);
4332 21
4333 /* for REPEAT_ONE we disable track limits */ 22 /* for REPEAT_ONE we disable track limits */
4334 if (!repeat_one) { 23 if (ci->global_settings->repeat_mode != REPEAT_ONE) {
4335 if (!bIsExtended || nTrackTime[t]==-1) {track=60*2*1000; def=1;} 24 Track_set_fade(&nsf_emu, Track_length( &nsf_emu, t ) - 4000, 4000);
4336 else track=nTrackTime[t];
4337 if (!bIsExtended || nTrackFade[t]==-1) fade=5*1000;
4338 else fade=nTrackFade[t];
4339 nSilenceTrackMS=5000;
4340 SetFadeTime(track,track+fade, fNSFPlaybackSpeed,def);
4341 } 25 }
4342 ci->set_elapsed(d*1000); /* d is track no to display */ 26 if (multitrack) ci->set_elapsed(t*1000); /* t is track no to display */
27 else ci->set_elapsed(0);
4343} 28}
4344 29
4345/* this is the codec entry point */ 30/* this is the codec entry point */
4346enum codec_status codec_main(enum codec_entry_call_reason reason) 31enum codec_status codec_main(enum codec_entry_call_reason reason)
4347{ 32{
4348 if (reason == CODEC_LOAD) { 33 if (reason == CODEC_LOAD) {
4349 /* we only render 16 bits, 44.1KHz, Mono */ 34 /* we only render 16 bits */
4350 ci->configure(DSP_SET_SAMPLE_DEPTH, 16); 35 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
36
37 /* 44 Khz, Interleaved stereo */
4351 ci->configure(DSP_SET_FREQUENCY, 44100); 38 ci->configure(DSP_SET_FREQUENCY, 44100);
4352 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); 39 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
4353 40
4354 RebuildOutputTables(); 41 Nsf_init(&nsf_emu);
42 Nsf_set_sample_rate(&nsf_emu, 44100);
4355 } 43 }
4356 44
4357 return CODEC_OK; 45 return CODEC_OK;
4358} 46}
4359 47
4360/* this is called for each file to process */ 48/* this is called for each file to process */
4361enum codec_status codec_run(void) 49enum codec_status codec_run(void)
4362{ 50{
4363 int written; 51 blargg_err_t err;
4364 uint8_t *buf; 52 uint8_t *buf;
4365 size_t n; 53 size_t n;
4366 int endofstream; /* end of stream flag */ 54 int track, is_multitrack;
4367 int usingplaylist = 0; 55 uint32_t elapsed_time;
4368 intptr_t param; 56 intptr_t param;
4369 57
58 track = is_multitrack = 0;
59 elapsed_time = 0;
60
4370 DEBUGF("NSF: next_track\n"); 61 DEBUGF("NSF: next_track\n");
4371 if (codec_init()) { 62 if (codec_init()) {
4372 return CODEC_ERROR; 63 return CODEC_ERROR;
4373 } 64 }
4374 DEBUGF("NSF: after init\n"); 65
4375
4376 codec_set_replaygain(ci->id3); 66 codec_set_replaygain(ci->id3);
4377 67
4378 /* Read the entire file */ 68 /* Read the entire file */
@@ -4383,100 +73,63 @@ enum codec_status codec_run(void)
4383 DEBUGF("NSF: file load failed\n"); 73 DEBUGF("NSF: file load failed\n");
4384 return CODEC_ERROR; 74 return CODEC_ERROR;
4385 } 75 }
76
77 if ((err = Nsf_load(&nsf_emu, buf, ci->filesize))) {
78 DEBUGF("NSF: Nsf_load failed (%s)\n", err);
79 return CODEC_ERROR;
80 }
4386 81
4387 repeat_one = ci->global_settings->repeat_mode == REPEAT_ONE; 82 /* Update internal track count */
4388 83 if (nsf_emu.m3u.size > 0)
4389init_nsf: 84 nsf_emu.track_count = nsf_emu.m3u.size;
4390 if(!NSFCore_Initialize()) {
4391 DEBUGF("NSF: NSFCore_Initialize failed\n"); return CODEC_ERROR;}
4392 85
4393 if(LoadFile(buf,ci->filesize)) { 86 if (nsf_emu.track_count > 1) is_multitrack = 1;
4394 DEBUGF("NSF: LoadFile failed\n"); return CODEC_ERROR;}
4395 if(!SetPlaybackOptions(44100)) {
4396 DEBUGF("NSF: SetPlaybackOptions failed\n"); return CODEC_ERROR;}
4397 if(!LoadNSF(nDataBufferSize)) {
4398 DEBUGF("NSF: LoadNSF failed\n"); return CODEC_ERROR;}
4399 87
4400 if (!dontresettrack||strcmp(ci->id3->path,last_path)) { 88next_track:
4401 /* if this is the first time we're seeing this file, or if we haven't 89 set_codec_track(track, is_multitrack);
4402 been asked to preserve the track number, default to the proper
4403 initial track */
4404 if (bIsExtended && !repeat_one && nPlaylistSize>0) {
4405 /* decide to use the playlist */
4406 usingplaylist=1;
4407 track=0;
4408 set_codec_track(nPlaylist[0],0);
4409 } else {
4410 /* simply use the initial track */
4411 track=nInitialTrack;
4412 set_codec_track(track,track);
4413 }
4414 } else {
4415 /* if we've already been running this file assume track is set
4416 already */
4417 if (usingplaylist) set_codec_track(nPlaylist[track],track);
4418 else set_codec_track(track,track);
4419 }
4420 strcpy(last_path,ci->id3->path);
4421 90
4422 /* The main decoder loop */ 91 /* The main decoder loop */
4423 92 while (1) {
4424 endofstream = 0;
4425
4426 reset_profile_timers();
4427
4428 while (!endofstream) {
4429 enum codec_command_action action = ci->get_command(&param); 93 enum codec_command_action action = ci->get_command(&param);
4430 94
4431 if (action == CODEC_ACTION_HALT) 95 if (action == CODEC_ACTION_HALT)
4432 break; 96 break;
4433 97
4434 if (action == CODEC_ACTION_SEEK_TIME) { 98 if (action == CODEC_ACTION_SEEK_TIME) {
4435 track=param/1000; 99 if (is_multitrack) {
4436 if (usingplaylist) { 100 track = param/1000;
4437 if (track>=nPlaylistSize) break; 101 ci->seek_complete();
4438 } else { 102 if (track >= nsf_emu.track_count) break;
4439 if (track>=nTrackCount) break; 103 goto next_track;
4440 } 104 }
4441 dontresettrack=1; 105
106 ci->set_elapsed(param);
107 elapsed_time = param;
108 Track_seek(&nsf_emu, param);
4442 ci->seek_complete(); 109 ci->seek_complete();
4443 goto init_nsf; 110
111 /* Set fade again */
112 if (ci->global_settings->repeat_mode != REPEAT_ONE) {
113 Track_set_fade(&nsf_emu, Track_length( &nsf_emu, track ), 4000);
114 }
4444 } 115 }
4445 116
4446 ENTER_TIMER(total); 117 /* Generate audio buffer */
4447 written=GetSamples((uint8_t*)samples,WAV_CHUNK_SIZE/2); 118 err = Nsf_play(&nsf_emu, CHUNK_SIZE, samples);
4448 EXIT_TIMER(total); 119 if (err || nsf_emu.track_ended) {
4449
4450 if (!written || SongCompleted()) {
4451 print_timers(last_path,track);
4452 reset_profile_timers();
4453
4454 track++; 120 track++;
4455 if (usingplaylist) { 121 if (track >= nsf_emu.track_count) break;
4456 if (track>=nPlaylistSize) break; 122 goto next_track;
4457 } else {
4458 if (track>=nTrackCount) break;
4459 }
4460 dontresettrack=1;
4461 goto init_nsf;
4462 } 123 }
4463 124
4464 ci->pcmbuf_insert(samples, NULL, written >> 1); 125 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE >> 1);
4465 }
4466
4467 print_timers(last_path,track);
4468 126
4469 if (repeat_one) { 127 /* Set elapsed time for one track files */
4470 /* in repeat one mode just advance to the next track */ 128 if (is_multitrack == 0) {
4471 track++; 129 elapsed_time += (CHUNK_SIZE / 2) / 44.1;
4472 if (track>=nTrackCount) track=0; 130 ci->set_elapsed(elapsed_time);
4473 dontresettrack=1; 131 }
4474 /* at this point we can't tell if another file has been selected */
4475 } else {
4476 /* otherwise do a proper load of the next file */
4477 dontresettrack=0;
4478 last_path[0]='\0';
4479 } 132 }
4480 133
4481 return CODEC_OK; 134 return CODEC_OK;
4482} 135}
diff --git a/apps/codecs/sgc.c b/apps/codecs/sgc.c
new file mode 100644
index 0000000000..e5f0299980
--- /dev/null
+++ b/apps/codecs/sgc.c
@@ -0,0 +1,123 @@
1
2/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
3
4#include <codecs/lib/codeclib.h>
5#include "libgme/sgc_emu.h"
6
7CODEC_HEADER
8
9/* Maximum number of bytes to process in one iteration */
10#define CHUNK_SIZE (1024*2)
11
12static int16_t samples[CHUNK_SIZE] IBSS_ATTR;
13static struct Sgc_Emu sgc_emu IDATA_ATTR CACHEALIGN_ATTR;
14
15/* Coleco Bios */
16/* Colecovision not supported yet
17static char coleco_bios[0x2000];
18*/
19
20/****************** rockbox interface ******************/
21
22static void set_codec_track(int t) {
23 Sgc_start_track(&sgc_emu, t);
24
25 /* for REPEAT_ONE we disable track limits */
26 if (ci->global_settings->repeat_mode != REPEAT_ONE) {
27 Track_set_fade(&sgc_emu, Track_get_length( &sgc_emu, t ), 4000);
28 }
29 ci->set_elapsed(t*1000); /* t is track no to display */
30}
31
32/* this is the codec entry point */
33enum codec_status codec_main(enum codec_entry_call_reason reason)
34{
35 if (reason == CODEC_LOAD) {
36 /* we only render 16 bits */
37 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
38
39 /* 44 Khz, Interleaved stereo */
40 ci->configure(DSP_SET_FREQUENCY, 44100);
41 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
42
43 Sgc_init(&sgc_emu);
44 Sgc_set_sample_rate(&sgc_emu, 44100);
45
46 /* set coleco bios, should be named coleco_bios.rom */
47 /* Colecovision not supported yet
48 int fd = ci->open("/coleco_bios.rom", O_RDONLY);
49 if ( fd >= 0 ) {
50 ci->read(fd, coleco_bios, 0x2000);
51 ci->close(fd);
52 set_coleco_bios( &sgc_emu, coleco_bios );
53 }
54 */
55 }
56
57 return CODEC_OK;
58}
59
60/* this is called for each file to process */
61enum codec_status codec_run(void)
62{
63 blargg_err_t err;
64 uint8_t *buf;
65 size_t n;
66 intptr_t param;
67 int track = 0;
68
69 DEBUGF("SGC: next_track\n");
70 if (codec_init()) {
71 return CODEC_ERROR;
72 }
73
74 codec_set_replaygain(ci->id3);
75
76 /* Read the entire file */
77 DEBUGF("SGC: request file\n");
78 ci->seek_buffer(0);
79 buf = ci->request_buffer(&n, ci->filesize);
80 if (!buf || n < (size_t)ci->filesize) {
81 DEBUGF("SGC: file load failed\n");
82 return CODEC_ERROR;
83 }
84
85 if ((err = Sgc_load_mem(&sgc_emu, buf, ci->filesize))) {
86 DEBUGF("SGC: Sgc_load failed (%s)\n", err);
87 return CODEC_ERROR;
88 }
89
90 /* Update internal track count */
91 if (sgc_emu.m3u.size > 0)
92 sgc_emu.track_count = sgc_emu.m3u.size;
93
94next_track:
95 set_codec_track(track);
96
97 /* The main decoder loop */
98 while (1) {
99 enum codec_command_action action = ci->get_command(&param);
100
101 if (action == CODEC_ACTION_HALT)
102 break;
103
104 if (action == CODEC_ACTION_SEEK_TIME) {
105 track = param/1000;
106 ci->seek_complete();
107 if (track >= sgc_emu.track_count) break;
108 goto next_track;
109 }
110
111 /* Generate audio buffer */
112 err = Sgc_play(&sgc_emu, CHUNK_SIZE, samples);
113 if (err || sgc_emu.track_ended) {
114 track++;
115 if (track >= sgc_emu.track_count) break;
116 goto next_track;
117 }
118
119 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE >> 1);
120 }
121
122 return CODEC_OK;
123}
diff --git a/apps/codecs/vgm.c b/apps/codecs/vgm.c
new file mode 100644
index 0000000000..89bfd1937b
--- /dev/null
+++ b/apps/codecs/vgm.c
@@ -0,0 +1,142 @@
1
2/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
3/* Inflate code taken from WikiViewer plugin by Adam Gashlin */
4
5#include <codecs/lib/codeclib.h>
6
7#include "libgme/blargg_endian.h"
8#include "libgme/vgm_emu.h"
9#include "libgme/inflate/mallocer.h"
10#include "libgme/inflate/inflate.h"
11
12CODEC_HEADER
13
14/* Maximum number of bytes to process in one iteration */
15#define CHUNK_SIZE (1024*4)
16#define MAINMEMBUF 0
17
18static int16_t samples[CHUNK_SIZE] IBSS_ATTR;
19static struct Vgm_Emu vgm_emu IDATA_ATTR CACHEALIGN_ATTR;
20
21static void *inflatebuf; /* heap for gunzip */
22static char *songbuf; /* destination for uncompressed song */
23static uint32_t songbuflen=0; /* size of the song buffer */
24static uint32_t songlen=0; /* used size of the song buffer */
25
26/****************** rockbox interface ******************/
27
28/* this is the codec entry point */
29enum codec_status codec_main(enum codec_entry_call_reason reason)
30{
31 if (reason == CODEC_LOAD) {
32 /* we only render 16 bits */
33 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
34
35 /* 32 Khz, Interleaved stereo */
36 ci->configure(DSP_SET_FREQUENCY, 44100);
37 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
38
39 Vgm_init(&vgm_emu);
40 Vgm_set_sample_rate(&vgm_emu, 44100);
41 }
42
43 return CODEC_OK;
44}
45
46/* this is called for each file to process */
47enum codec_status codec_run(void)
48{
49 blargg_err_t err;
50 uint8_t *buf;
51 size_t n;
52 intptr_t param;
53
54 uint32_t elapsed_time = 0;
55
56 DEBUGF("VGM: next_track\n");
57 if (codec_init()) {
58 return CODEC_ERROR;
59 }
60
61 codec_set_replaygain(ci->id3);
62
63 /* Read the entire file */
64 DEBUGF("VGM: request file\n");
65 ci->seek_buffer(0);
66 buf = ci->request_buffer(&n, ci->filesize);
67 if (!buf) {
68 DEBUGF("VGM: file load failed\n");
69 return CODEC_ERROR;
70 }
71
72 /* If couldn't get the whole buffer
73 will trim file and put and 'end_command'
74 at the end*/
75 if (n < (size_t)ci->filesize) {
76 DEBUGF("VGM: file was trimmed\n");
77 }
78
79 /* If is gzipped decompress it */
80 if ( get_le16( buf ) == 0x8b1f ) {
81 wpw_init_mempool(MAINMEMBUF);
82 inflatebuf=wpw_malloc(MAINMEMBUF,0x13500);
83
84 /* Will use available remaining memory
85 as output buffer */
86 songbuflen=wpw_available(MAINMEMBUF);
87 songbuf=wpw_malloc(MAINMEMBUF,songbuflen);
88
89 songlen=decompress(buf,n,songbuf,songbuflen,0,inflatebuf);
90
91 if ((err = Vgm_load_mem(&vgm_emu, songbuf, songlen, true))) {
92 DEBUGF("VGM: Vgm_load_mem failed (%s)\n", err);
93 return CODEC_ERROR;
94 }
95
96 /* Since metadata parser doesn't support VGZ
97 will set song length here */
98 ci->id3->length = Track_get_length( &vgm_emu );
99 }
100 else if ((err = Vgm_load_mem(&vgm_emu, buf, n, false))) {
101 DEBUGF("VGM: Vgm_load failed_mem (%s)\n", err);
102 return CODEC_ERROR;
103 }
104
105 Vgm_start_track(&vgm_emu);
106
107 /* for REPEAT_ONE we disable track limits */
108 if (ci->global_settings->repeat_mode != REPEAT_ONE) {
109 Track_set_fade(&vgm_emu, ci->id3->length - 4000, 4000);
110 }
111
112 ci->set_elapsed(0);
113
114 /* The main decoder loop */
115 while (1) {
116 enum codec_command_action action = ci->get_command(&param);
117
118 if (action == CODEC_ACTION_HALT)
119 break;
120
121 if (action == CODEC_ACTION_SEEK_TIME) {
122 ci->set_elapsed(param);
123 elapsed_time = param;
124 Track_seek(&vgm_emu, param);
125 ci->seek_complete();
126
127 /* Set fade again in case we seek to start of song */
128 Track_set_fade(&vgm_emu, ci->id3->length - 4000, 4000);
129 }
130
131 /* Generate audio buffer */
132 err = Vgm_play(&vgm_emu, CHUNK_SIZE, samples);
133 if (err || vgm_emu.track_ended) break;
134
135 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE >> 1);
136
137 elapsed_time += (CHUNK_SIZE / 2) / 44.1;
138 ci->set_elapsed(elapsed_time);
139 }
140
141 return CODEC_OK;
142}
diff --git a/apps/filetypes.c b/apps/filetypes.c
index 779337e0ca..17a16db4ec 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -112,6 +112,13 @@ static const struct filetype inbuilt_filetypes[] = {
112 { "vox", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 112 { "vox", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
113 { "w64", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 113 { "w64", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
114 { "tta", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 114 { "tta", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
115 { "ay", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
116 { "gbs", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
117 { "hes", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
118 { "sgc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
119 { "vgm", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
120 { "vgz", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
121 { "kss", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
115#endif 122#endif
116 { "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, 123 { "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
117 { "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, 124 { "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
diff --git a/apps/metadata.c b/apps/metadata.c
index cbb5b42795..8b1101eaa5 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -216,6 +216,24 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
216 /* Advanced Audio Coding High Efficiency in M4A container */ 216 /* Advanced Audio Coding High Efficiency in M4A container */
217 [AFMT_MP4_AAC_HE] = 217 [AFMT_MP4_AAC_HE] =
218 AFMT_ENTRY("AAC-HE","aac", NULL, get_mp4_metadata, "mp4\0"), 218 AFMT_ENTRY("AAC-HE","aac", NULL, get_mp4_metadata, "mp4\0"),
219 /* AY (ZX Spectrum, Amstrad CPC Sound Format) */
220 [AFMT_AY] =
221 AFMT_ENTRY("AY", "ay", NULL, get_ay_metadata, "ay\0"),
222 /* GBS (Game Boy Sound Format) */
223 [AFMT_GBS] =
224 AFMT_ENTRY("GBS", "gbs", NULL, get_gbs_metadata, "gbs\0"),
225 /* HES (Hudson Entertainment System Sound Format) */
226 [AFMT_HES] =
227 AFMT_ENTRY("HES", "hes", NULL, get_hes_metadata, "hes\0"),
228 /* SGC (Sega Master System, Game Gear, Coleco Vision Sound Format) */
229 [AFMT_SGC] =
230 AFMT_ENTRY("SGC", "sgc", NULL, get_sgc_metadata, "sgc\0"),
231 /* VGM (Video Game Music Format) */
232 [AFMT_VGM] =
233 AFMT_ENTRY("VGM", "vgm", NULL, get_vgm_metadata, "vgm\0vgz\0"),
234 /* KSS (MSX computer KSS Music File) */
235 [AFMT_KSS] =
236 AFMT_ENTRY("KSS", "kss", NULL, get_kss_metadata, "kss\0"),
219#endif 237#endif
220}; 238};
221 239
@@ -299,6 +317,12 @@ enum data_type get_audio_base_data_type(int afmt)
299 case AFMT_SID: 317 case AFMT_SID:
300 case AFMT_MOD: 318 case AFMT_MOD:
301 case AFMT_SAP: 319 case AFMT_SAP:
320 case AFMT_AY:
321 case AFMT_GBS:
322 case AFMT_HES:
323 case AFMT_SGC:
324 case AFMT_VGM:
325 case AFMT_KSS:
302 /* Type must be allocated and loaded in its entirety onto 326 /* Type must be allocated and loaded in its entirety onto
303 the buffer */ 327 the buffer */
304 return TYPE_ATOMIC_AUDIO; 328 return TYPE_ATOMIC_AUDIO;
diff --git a/apps/metadata.h b/apps/metadata.h
index d016359d2a..3c5efb7532 100644
--- a/apps/metadata.h
+++ b/apps/metadata.h
@@ -87,6 +87,12 @@ enum
87 AFMT_WMAVOICE, /* WMA Voice in ASF */ 87 AFMT_WMAVOICE, /* WMA Voice in ASF */
88 AFMT_MPC_SV8, /* Musepack SV8 */ 88 AFMT_MPC_SV8, /* Musepack SV8 */
89 AFMT_MP4_AAC_HE, /* Advanced Audio Coding (AAC-HE) in M4A container */ 89 AFMT_MP4_AAC_HE, /* Advanced Audio Coding (AAC-HE) in M4A container */
90 AFMT_AY, /* AY (ZX Spectrum, Amstrad CPC Sound Format) */
91 AFMT_GBS, /* GBS (Game Boy Sound Format) */
92 AFMT_HES, /* HES (Hudson Entertainment System Sound Format) */
93 AFMT_SGC, /* SGC (Sega Master System, Game Gear, Coleco Vision Sound Format) */
94 AFMT_VGM, /* VGM (Video Game Music Format) */
95 AFMT_KSS, /* KSS (MSX computer KSS Music File) */
90#endif 96#endif
91 97
92 /* add new formats at any index above this line to have a sensible order - 98 /* add new formats at any index above this line to have a sensible order -
diff --git a/apps/metadata/ay.c b/apps/metadata/ay.c
new file mode 100644
index 0000000000..8b737a7eba
--- /dev/null
+++ b/apps/metadata/ay.c
@@ -0,0 +1,148 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13/* Taken from blargg's Game_Music_Emu library */
14
15typedef unsigned char byte;
16
17/* AY file header */
18enum { header_size = 0x14 };
19struct header_t
20{
21 byte tag[8];
22 byte vers;
23 byte player;
24 byte unused[2];
25 byte author[2];
26 byte comment[2];
27 byte max_track;
28 byte first_track;
29 byte track_info[2];
30};
31
32struct file_t {
33 struct header_t const* header;
34 byte const* tracks;
35 byte const* end; /* end of file data */
36};
37
38static int get_be16( const void *a )
39{
40 return get_short_be( (void*) a );
41}
42
43/* Given pointer to 2-byte offset of data, returns pointer to data, or NULL if
44 * offset is 0 or there is less than min_size bytes of data available. */
45static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size )
46{
47 int offset = (int16_t) get_be16( ptr );
48 int pos = ptr - (byte const*) file->header;
49 int size = file->end - (byte const*) file->header;
50 int limit = size - min_size;
51 if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit )
52 return NULL;
53 return ptr + offset;
54}
55
56static const char *parse_header( byte const in [], int size, struct file_t* out )
57{
58 if ( size < header_size )
59 return "wrong file type";
60
61 out->header = (struct header_t const*) in;
62 out->end = in + size;
63 struct header_t const* h = (struct header_t const*) in;
64 if ( memcmp( h->tag, "ZXAYEMUL", 8 ) )
65 return "wrong file type";
66
67 out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 );
68 if ( !out->tracks )
69 return "missing track data";
70
71 return 0;
72}
73
74static void copy_ay_fields( struct file_t const* file, struct mp3entry* id3, int track )
75{
76 int track_count = file->header->max_track + 1;
77
78 /* calculate track length based on number of subtracks */
79 if (track_count > 1) {
80 id3->length = file->header->max_track * 1000;
81 } else {
82 byte const* track_info = get_data( file, file->tracks + track * 4 + 2, 6 );
83 if (track_info)
84 id3->length = get_be16( track_info + 4 ) * (1000 / 50); /* frames to msec */
85 else id3->length = 120 * 1000;
86 }
87
88 if ( id3->length <= 0 )
89 id3->length = 120 * 1000; /* 2 minutes */
90
91 /* If meta info was found in the m3u skip next step */
92 if (id3->title && id3->title[0]) return;
93
94 /* If file has more than one track will
95 use file name as title */
96 char * tmp;
97 if (track_count <= 1) {
98 tmp = (char *) get_data( file, file->tracks + track * 4, 1 );
99 if ( tmp ) id3->title = tmp;
100 }
101
102 /* Author */
103 tmp = (char *) get_data( file, file->header->author, 1 );
104 if (tmp) id3->artist = tmp;
105
106 /* Comment */
107 tmp = (char *) get_data( file, file->header->comment, 1 );
108 if (tmp) id3->comment = tmp;
109}
110
111bool parse_ay_header(int fd, struct mp3entry *id3)
112{
113 /* Use the trackname part of the id3 structure as a temporary buffer */
114 unsigned char* buf = (unsigned char *)id3->id3v2buf;
115 struct file_t file;
116 int read_bytes;
117
118 lseek(fd, 0, SEEK_SET);
119 if ((read_bytes = read(fd, buf, ID3V2_BUF_SIZE)) < header_size)
120 return false;
121
122 buf [ID3V2_BUF_SIZE] = '\0';
123 if ( parse_header( buf, read_bytes, &file ) )
124 return false;
125
126 copy_ay_fields( &file, id3, 0 );
127 return true;
128}
129
130bool get_ay_metadata(int fd, struct mp3entry* id3)
131{
132 char ay_type[8];
133 if ((lseek(fd, 0, SEEK_SET) < 0) ||
134 read(fd, ay_type, 8) < 8)
135 return false;
136
137 id3->vbr = false;
138 id3->filesize = filesize(fd);
139
140 id3->bitrate = 706;
141 id3->frequency = 44100;
142
143 /* Make sure this is a ZX Ay file */
144 if (memcmp( ay_type, "ZXAYEMUL", 8 ) != 0)
145 return false;
146
147 return parse_ay_header(fd, id3);
148}
diff --git a/apps/metadata/gbs.c b/apps/metadata/gbs.c
new file mode 100644
index 0000000000..796db5932f
--- /dev/null
+++ b/apps/metadata/gbs.c
@@ -0,0 +1,65 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13bool parse_gbs_header(int fd, struct mp3entry* id3)
14{
15 /* Use the trackname part of the id3 structure as a temporary buffer */
16 unsigned char* buf = (unsigned char *)id3->path;
17 lseek(fd, 0, SEEK_SET);
18 if (read(fd, buf, 112) < 112)
19 return false;
20
21 /* Calculate track length with number of subtracks */
22 id3->length = buf[4] * 1000;
23
24 /* If meta info was found in the m3u skip next step */
25 if (id3->title && id3->title[0]) return true;
26
27 char *p = id3->id3v2buf;
28
29 /* Some metadata entries have 32 bytes length */
30 /* Game */
31 memcpy(p, &buf[16], 32); *(p + 33) = '\0';
32 id3->title = p;
33 p += strlen(p)+1;
34
35 /* Artist */
36 memcpy(p, &buf[48], 32); *(p + 33) = '\0';
37 id3->artist = p;
38 p += strlen(p)+1;
39
40 /* Copyright */
41 memcpy(p, &buf[80], 32); *(p + 33) = '\0';
42 id3->album = p;
43
44 return true;
45}
46
47bool get_gbs_metadata(int fd, struct mp3entry* id3)
48{
49 char gbs_type[3];
50 if ((lseek(fd, 0, SEEK_SET) < 0) ||
51 (read(fd, gbs_type, 3) < 3))
52 return false;
53
54 id3->vbr = false;
55 id3->filesize = filesize(fd);
56 /* we only render 16 bits, 44.1KHz, Stereo */
57 id3->bitrate = 706;
58 id3->frequency = 44100;
59
60 /* Check for GBS magic */
61 if (memcmp( gbs_type, "GBS", 3 ) != 0)
62 return false;
63
64 return parse_gbs_header(fd, id3);
65}
diff --git a/apps/metadata/hes.c b/apps/metadata/hes.c
new file mode 100644
index 0000000000..6d99d523cb
--- /dev/null
+++ b/apps/metadata/hes.c
@@ -0,0 +1,39 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12#include "plugin.h"
13
14bool get_hes_metadata(int fd, struct mp3entry* id3)
15{
16 /* Use the id3v2 buffer part of the id3 structure as a temporary buffer */
17 unsigned char* buf = (unsigned char *)id3->id3v2buf;
18 int read_bytes;
19
20 if ((lseek(fd, 0, SEEK_SET) < 0)
21 || ((read_bytes = read(fd, buf, 4)) < 4))
22 return false;
23
24 /* Verify this is a HES file */
25 if (memcmp(buf,"HESM",4) != 0)
26 return false;
27
28 id3->vbr = false;
29 id3->filesize = filesize(fd);
30 /* we only render 16 bits, 44.1KHz, Stereo */
31 id3->bitrate = 706;
32 id3->frequency = 44100;
33
34 /* Set default track count (length)*/
35 id3->length = 255 * 1000;
36
37 return true;
38}
39
diff --git a/apps/metadata/kss.c b/apps/metadata/kss.c
new file mode 100644
index 0000000000..ecb59b8353
--- /dev/null
+++ b/apps/metadata/kss.c
@@ -0,0 +1,53 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13bool parse_kss_header(int fd, struct mp3entry* id3)
14{
15 /* Use the trackname part of the id3 structure as a temporary buffer */
16 unsigned char* buf = (unsigned char *)id3->path;
17
18 lseek(fd, 0, SEEK_SET);
19 if (read(fd, buf, 0x20) < 0x20)
20 return false;
21
22 /* calculate track length with number of tracks */
23 id3->length = 0;
24 if (buf[14] == 0x10) {
25 id3->length = (get_short_le((void *)(buf + 26)) + 1) * 1000;
26 }
27
28 if (id3->length <= 0)
29 id3->length = 255 * 1000; /* 255 tracks */
30
31 return true;
32}
33
34
35bool get_kss_metadata(int fd, struct mp3entry* id3)
36{
37 uint32_t kss_type;
38 if ((lseek(fd, 0, SEEK_SET) < 0) ||
39 read_uint32be(fd, &kss_type) != (int)sizeof(kss_type))
40 return false;
41
42 id3->vbr = false;
43 id3->filesize = filesize(fd);
44 /* we only render 16 bits, 44.1KHz, Stereo */
45 id3->bitrate = 706;
46 id3->frequency = 44100;
47
48 /* Make sure this is an SGC file */
49 if (kss_type != FOURCC('K','S','C','C') && kss_type != FOURCC('K','S','S','X'))
50 return false;
51
52 return parse_kss_header(fd, id3);
53}
diff --git a/apps/metadata/metadata_common.c b/apps/metadata/metadata_common.c
index 6c420d921f..1ad89d1b7a 100644
--- a/apps/metadata/metadata_common.c
+++ b/apps/metadata/metadata_common.c
@@ -178,6 +178,14 @@ unsigned long get_long_be(void* buf)
178 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 178 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
179} 179}
180 180
181/* Read an unaligned 16-bit little endian short from buffer. */
182unsigned short get_short_be(void* buf)
183{
184 unsigned char* p = (unsigned char*) buf;
185
186 return (p[0] << 8) | p[1];
187}
188
181/* Read an unaligned 32-bit little endian long from buffer. */ 189/* Read an unaligned 32-bit little endian long from buffer. */
182long get_slong(void* buf) 190long get_slong(void* buf)
183{ 191{
diff --git a/apps/metadata/metadata_common.h b/apps/metadata/metadata_common.h
index b2c76afb45..a48c2a4e89 100644
--- a/apps/metadata/metadata_common.h
+++ b/apps/metadata/metadata_common.h
@@ -62,6 +62,7 @@ uint64_t get_uint64_le(void* buf);
62unsigned long get_long_le(void* buf); 62unsigned long get_long_le(void* buf);
63unsigned short get_short_le(void* buf); 63unsigned short get_short_le(void* buf);
64unsigned long get_long_be(void* buf); 64unsigned long get_long_be(void* buf);
65unsigned short get_short_be(void* buf);
65long get_slong(void* buf); 66long get_slong(void* buf);
66unsigned long get_itunes_int32(char* value, int count); 67unsigned long get_itunes_int32(char* value, int count);
67long parse_tag(const char* name, char* value, struct mp3entry* id3, 68long parse_tag(const char* name, char* value, struct mp3entry* id3,
diff --git a/apps/metadata/metadata_parsers.h b/apps/metadata/metadata_parsers.h
index 7797b47094..adb7a82cd5 100644
--- a/apps/metadata/metadata_parsers.h
+++ b/apps/metadata/metadata_parsers.h
@@ -47,3 +47,9 @@ bool get_au_metadata(int fd, struct mp3entry* id3);
47bool get_vox_metadata(int fd, struct mp3entry* id3); 47bool get_vox_metadata(int fd, struct mp3entry* id3);
48bool get_wave64_metadata(int fd, struct mp3entry* id3); 48bool get_wave64_metadata(int fd, struct mp3entry* id3);
49bool get_tta_metadata(int fd, struct mp3entry* id3); 49bool get_tta_metadata(int fd, struct mp3entry* id3);
50bool get_ay_metadata(int fd, struct mp3entry* id3);
51bool get_gbs_metadata(int fd, struct mp3entry* id3);
52bool get_hes_metadata(int fd, struct mp3entry* id3);
53bool get_sgc_metadata(int fd, struct mp3entry* id3);
54bool get_vgm_metadata(int fd, struct mp3entry* id3);
55bool get_kss_metadata(int fd, struct mp3entry* id3);
diff --git a/apps/metadata/nsf.c b/apps/metadata/nsf.c
index 29fd8475bb..2fa6f36b12 100644
--- a/apps/metadata/nsf.c
+++ b/apps/metadata/nsf.c
@@ -11,6 +11,9 @@
11#include "rbunicode.h" 11#include "rbunicode.h"
12#include "string-extra.h" 12#include "string-extra.h"
13 13
14/* NOTE: This file was modified to work properly with the new nsf codec based
15 on Game_Music_Emu */
16
14struct NESM_HEADER 17struct NESM_HEADER
15{ 18{
16 uint32_t nHeader; 19 uint32_t nHeader;
@@ -66,7 +69,7 @@ static bool parse_nsfe(int fd, struct mp3entry *id3)
66 69
67 /* default values */ 70 /* default values */
68 info.nTrackCount = 1; 71 info.nTrackCount = 1;
69 id3->length = 2*1000*60; 72 id3->length = 150 * 1000;
70 73
71 /* begin reading chunks */ 74 /* begin reading chunks */
72 while (!(chunks_found & CHUNK_NEND)) 75 while (!(chunks_found & CHUNK_NEND))
@@ -210,6 +213,10 @@ static bool parse_nsfe(int fd, struct mp3entry *id3)
210 if (track_count | playlist_count) 213 if (track_count | playlist_count)
211 id3->length = MAX(track_count, playlist_count)*1000; 214 id3->length = MAX(track_count, playlist_count)*1000;
212 215
216 /* Single subtrack files will be treated differently
217 by gme's nsf codec */
218 if (id3->length <= 1000) id3->length = 150 * 1000;
219
213 /* 220 /*
214 * if we exited the while loop without a 'return', we must have hit an NEND 221 * if we exited the while loop without a 'return', we must have hit an NEND
215 * chunk if this is the case, the file was layed out as it was expected. 222 * chunk if this is the case, the file was layed out as it was expected.
@@ -230,7 +237,7 @@ static bool parse_nesm(int fd, struct mp3entry *id3)
230 return false; 237 return false;
231 238
232 /* Length */ 239 /* Length */
233 id3->length = hdr.nTrackCount*1000; 240 id3->length = (hdr.nTrackCount > 1 ? hdr.nTrackCount : 150) * 1000;
234 241
235 /* Title */ 242 /* Title */
236 id3->title = p; 243 id3->title = p;
@@ -250,7 +257,6 @@ static bool parse_nesm(int fd, struct mp3entry *id3)
250bool get_nsf_metadata(int fd, struct mp3entry* id3) 257bool get_nsf_metadata(int fd, struct mp3entry* id3)
251{ 258{
252 uint32_t nsf_type; 259 uint32_t nsf_type;
253
254 if (lseek(fd, 0, SEEK_SET) < 0 || 260 if (lseek(fd, 0, SEEK_SET) < 0 ||
255 read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type)) 261 read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type))
256 return false; 262 return false;
diff --git a/apps/metadata/sgc.c b/apps/metadata/sgc.c
new file mode 100644
index 0000000000..9e16de2c76
--- /dev/null
+++ b/apps/metadata/sgc.c
@@ -0,0 +1,67 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13bool parse_sgc_header(int fd, struct mp3entry* id3)
14{
15 /* Use the trackname part of the id3 structure as a temporary buffer */
16 unsigned char* buf = (unsigned char *)id3->path;
17
18 lseek(fd, 0, SEEK_SET);
19 if (read(fd, buf, 0xA0) < 0xA0)
20 return false;
21
22 /* calculate track length with number of tracks */
23 id3->length = buf[37] * 1000;
24
25 /* If meta info was found in the m3u skip next step */
26 if (id3->title && id3->title[0]) return true;
27
28 char *p = id3->id3v2buf;
29
30 /* Some metadata entries have 32 bytes length */
31 /* Game */
32 memcpy(p, &buf[64], 32); *(p + 33) = '\0';
33 id3->title = p;
34 p += strlen(p)+1;
35
36 /* Artist */
37 memcpy(p, &buf[96], 32); *(p + 33) = '\0';
38 id3->artist = p;
39 p += strlen(p)+1;
40
41 /* Copyright */
42 memcpy(p, &buf[128], 32); *(p + 33) = '\0';
43 id3->album = p;
44 p += strlen(p)+1;
45 return true;
46}
47
48
49bool get_sgc_metadata(int fd, struct mp3entry* id3)
50{
51 uint32_t sgc_type;
52 if ((lseek(fd, 0, SEEK_SET) < 0) ||
53 read_uint32be(fd, &sgc_type) != (int)sizeof(sgc_type))
54 return false;
55
56 id3->vbr = false;
57 id3->filesize = filesize(fd);
58 /* we only render 16 bits, 44.1KHz, Stereo */
59 id3->bitrate = 706;
60 id3->frequency = 44100;
61
62 /* Make sure this is an SGC file */
63 if (sgc_type != FOURCC('S','G','C',0x1A))
64 return false;
65
66 return parse_sgc_header(fd, id3);
67}
diff --git a/apps/metadata/vgm.c b/apps/metadata/vgm.c
new file mode 100644
index 0000000000..9ea95b3939
--- /dev/null
+++ b/apps/metadata/vgm.c
@@ -0,0 +1,195 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
14
15typedef unsigned char byte;
16
17enum { header_size = 0x40 };
18enum { max_field = 64 };
19
20struct header_t
21{
22 char tag [4];
23 byte data_size [4];
24 byte version [4];
25 byte psg_rate [4];
26 byte ym2413_rate [4];
27 byte gd3_offset [4];
28 byte track_duration [4];
29 byte loop_offset [4];
30 byte loop_duration [4];
31 byte frame_rate [4];
32 byte noise_feedback [2];
33 byte noise_width;
34 byte unused1;
35 byte ym2612_rate [4];
36 byte ym2151_rate [4];
37 byte data_offset [4];
38 byte unused2 [8];
39};
40
41static byte const* skip_gd3_str( byte const* in, byte const* end )
42{
43 while ( end - in >= 2 )
44 {
45 in += 2;
46 if ( !(in [-2] | in [-1]) )
47 break;
48 }
49 return in;
50}
51
52static byte const* get_gd3_str( byte const* in, byte const* end, char* field )
53{
54 byte const* mid = skip_gd3_str( in, end );
55 int len = (mid - in) / 2 - 1;
56 if ( field && len > 0 )
57 {
58 len = len < (int) max_field ? len : (int) max_field;
59
60 field [len] = 0;
61 /* Conver to utf8 */
62 utf16LEdecode( in, field, len );
63
64 /* Copy string back to id3v2buf */
65 strcpy( (char*) in, field );
66 }
67 return mid;
68}
69
70static byte const* get_gd3_pair( byte const* in, byte const* end, char* field )
71{
72 return skip_gd3_str( get_gd3_str( in, end, field ), end );
73}
74
75static void parse_gd3( byte const* in, byte const* end, struct mp3entry* id3 )
76{
77 char* p = id3->path;
78 id3->title = (char *) in;
79 in = get_gd3_pair( in, end, p ); /* Song */
80
81 id3->album = (char *) in;
82 in = get_gd3_pair( in, end, p ); /* Game */
83
84 in = get_gd3_pair( in, end, NULL ); /* System */
85
86 id3->artist = (char *) in;
87 in = get_gd3_pair( in, end, p ); /* Author */
88
89#if MEMORYSIZE > 2
90 in = get_gd3_str ( in, end, NULL ); /* Copyright */
91 in = get_gd3_pair( in, end, NULL ); /* Dumper */
92
93 id3->comment = (char *) in;
94 in = get_gd3_str ( in, end, p ); /* Comment */
95#endif
96}
97
98int const gd3_header_size = 12;
99
100static long check_gd3_header( byte* h, long remain )
101{
102 if ( remain < gd3_header_size ) return 0;
103 if ( memcmp( h, "Gd3 ", 4 ) ) return 0;
104 if ( get_long_le( h + 4 ) >= 0x200 ) return 0;
105
106 long gd3_size = get_long_le( h + 8 );
107 if ( gd3_size > remain - gd3_header_size )
108 gd3_size = remain - gd3_header_size;
109
110 return gd3_size;
111}
112
113static void get_vgm_length( struct header_t* h, struct mp3entry* id3 )
114{
115 long length = get_long_le( h->track_duration ) * 10 / 441;
116 if ( length > 0 )
117 {
118 long loop_length = 0, intro_length = 0;
119 long loop = get_long_le( h->loop_duration );
120 if ( loop > 0 && get_long_le( h->loop_offset ) )
121 {
122 loop_length = loop * 10 / 441;
123 intro_length = length - loop_length;
124 }
125 else
126 {
127 intro_length = length; /* make it clear that track is no longer than length */
128 loop_length = 0;
129 }
130
131 id3->length = intro_length + 2 * loop_length; /* intro + 2 loops */
132 return;
133 }
134
135 id3->length = 150 * 1000; /* 2.5 minutes */
136}
137
138bool get_vgm_metadata(int fd, struct mp3entry* id3)
139{
140 /* Use the id3v2 part of the id3 structure as a temporary buffer */
141 unsigned char* buf = (unsigned char *)id3->id3v2buf;
142 int read_bytes;
143
144 memset(buf, 0, ID3V2_BUF_SIZE);
145 if ((lseek(fd, 0, SEEK_SET) < 0)
146 || ((read_bytes = read(fd, buf, header_size)) < header_size))
147 {
148 return false;
149 }
150
151 id3->vbr = false;
152 id3->filesize = filesize(fd);
153
154 id3->bitrate = 706;
155 id3->frequency = 44100;
156
157 /* If file is gzipped, will get metadata later */
158 if (memcmp(buf, "Vgm ", 4))
159 {
160 /* We must set a default song length here because
161 the codec can't do it anymore */
162 id3->length = 150 * 1000; /* 2.5 minutes */
163 return true;
164 }
165
166 /* Get song length from header */
167 struct header_t* header = (struct header_t*) buf;
168 get_vgm_length( header, id3 );
169
170 long gd3_offset = get_long_le( header->gd3_offset ) - 0x2C;
171
172 /* No gd3 tag found */
173 if ( gd3_offset < 0 )
174 return true;
175
176 /* Seek to gd3 offset and read as
177 many bytes posible */
178 gd3_offset = id3->filesize - (header_size + gd3_offset);
179 if ((lseek(fd, -gd3_offset, SEEK_END) < 0)
180 || ((read_bytes = read(fd, buf, ID3V2_BUF_SIZE)) <= 0))
181 return true;
182
183 byte* gd3 = buf;
184 long gd3_size = check_gd3_header( gd3, read_bytes );
185
186 /* GD3 tag is zero */
187 if ( gd3_size == 0 )
188 return true;
189
190 /* Finally, parse gd3 tag */
191 if ( gd3 )
192 parse_gd3( gd3 + gd3_header_size, gd3 + read_bytes, id3 );
193
194 return true;
195}
diff --git a/docs/CREDITS b/docs/CREDITS
index 0156961fc9..d3825273ae 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -599,6 +599,7 @@ Sean Bartell
599Seheon Ryu 599Seheon Ryu
600Asier Arsuaga 600Asier Arsuaga
601Vencislav Atanasov 601Vencislav Atanasov
602Mauricio Garrido
602 603
603The libmad team 604The libmad team
604The wavpack team 605The wavpack team
diff --git a/manual/appendix/file_formats.tex b/manual/appendix/file_formats.tex
index 4e5d96aedf..66fe397c03 100644
--- a/manual/appendix/file_formats.tex
+++ b/manual/appendix/file_formats.tex
@@ -209,6 +209,29 @@
209 Synthetic music Mobile Application Format 209 Synthetic music Mobile Application Format
210 & \fname{.mmf} 210 & \fname{.mmf}
211 & PCM/ADPCM only \\ 211 & PCM/ADPCM only \\
212 Game Boy Sound Format
213 & \fname{.gbs}
214 & Progress bar and seek use subtracks instead of seconds.\\
215 AY Sound Chip Music
216 & \fname{.ay}
217 & Progress bar and seek use subtracks instead of seconds for
218 multitrack files.\\
219 Hudson Entertainment System Sound Format
220 & \fname{.hes}
221 & Progress bar and seek use subtracks instead of seconds.\\
222 MSX Konami Sound System
223 & \fname{.kss}
224 & Progress bar and seek use subtracks instead of seconds.\\
225 SMS/GG/CV Sound Format
226 & \fname{.sgc}
227 & Supports Sega Master System and Game Gear Sound Format.
228 Progress bar and seek use subtracks instead of seconds.\\
229 Video Game Music Format
230 & \fname{.vgm}
231 & \\
232 Gzipped Video Game Music Format
233 & \fname{.vgz}
234 & \\
212 MOD 235 MOD
213 & \fname{.mod} 236 & \fname{.mod}
214 & \\ 237 & \\
@@ -227,7 +250,7 @@
227 \end{rbtabular} 250 \end{rbtabular}
228 251
229 \subsection{Codec featureset} 252 \subsection{Codec featureset}
230 \begin{rbtabular}{.90\textwidth}{lXXX}% 253 \begin{rbtabular}{.95\textwidth}{lXXX}%
231 {\textbf{Format} & \textbf{Seek} & \textbf{Resume} & \textbf{Gapless}}{}{} 254 {\textbf{Format} & \textbf{Seek} & \textbf{Resume} & \textbf{Gapless}}{}{}
232 ATSC A/52 (AC3) & x & x & \\ 255 ATSC A/52 (AC3) & x & x & \\
233 ADX & x & & \\ 256 ADX & x & & \\
@@ -252,6 +275,13 @@
252 Wavpack & x & x & x \\ 275 Wavpack & x & x & x \\
253 Atari Sound Format & x & & \\ 276 Atari Sound Format & x & & \\
254 Synthetic music Mobile Application Format & x & x & \\ 277 Synthetic music Mobile Application Format & x & x & \\
278 Game Boy Sound Format & x & & \\
279 AY Sound Chip Music & x & & \\
280 Hudson Entertainment System Sound Format & x & & \\
281 MSX Konami Sound System & x & & \\
282 SMS/GG/CV Sound Format & x & & \\
283 Video Game Music Format & x & x & \\
284 Gzipped Video Game Music Format & x & x & \\
255 MOD & x & & \\ 285 MOD & x & & \\
256 NES Sound Format & x & & \\ 286 NES Sound Format & x & & \\
257 Atari SAP & x & & \\ 287 Atari SAP & x & & \\
@@ -259,8 +289,10 @@
259 SPC700 & x & & \\ 289 SPC700 & x & & \\
260 \end{rbtabular} 290 \end{rbtabular}
261 291
262 \note{The seek implementations of NES Sound Format and Sound Interface Device 292 \note{The seek implementations of NES Sound Format, Sound Interface Device,
263 use subtracks instead of seconds, whereas each subtrack equals a second.} 293 Game Boy Sound Format, AY Sound Chip Music, Hudson Entertainment System Sound,
294 Format, MSX Konami Sound System and SMS/GG/CV Sound Format use subtracks
295 instead of seconds, whereas each subtrack equals a second.}
264 296
265 \section{\label{ref:SupportedMetadata}Supported metadata tags} 297 \section{\label{ref:SupportedMetadata}Supported metadata tags}
266 Rockbox supports different metadata formats. In general those tag formats 298 Rockbox supports different metadata formats. In general those tag formats
@@ -281,13 +313,14 @@
281 MP4 & \fname{.m4a}, \fname{.m4b}, \fname{.mp4} \\ 313 MP4 & \fname{.m4a}, \fname{.m4b}, \fname{.mp4} \\
282 ASF & \fname{.wma}, \fname{.wmv}, \fname{.asf} \\ 314 ASF & \fname{.wma}, \fname{.wmv}, \fname{.asf} \\
283 Codec specific & \fname{.mmf}, \fname{.mod}, \fname{.nsf}, \fname{.nsfe}, 315 Codec specific & \fname{.mmf}, \fname{.mod}, \fname{.nsf}, \fname{.nsfe},
284 \fname{.sap}, \fname{.sid}, \fname{.spc} \\ 316 \fname{.sap}, \fname{.sid}, \fname{.spc}, \fname{.gbs},
317 \fname{.ay}, \fname{.kss}, \fname{.sgc}, \fname{.vgm} \\
285 None & \fname{.a52}, \fname{.ac3}, \fname{.adx}, \fname{.oma}, 318 None & \fname{.a52}, \fname{.ac3}, \fname{.adx}, \fname{.oma},
286 \fname{.aa3}, \fname{.aif}, \fname{.aiff}, \fname{.au}, 319 \fname{.aa3}, \fname{.aif}, \fname{.aiff}, \fname{.au},
287 \fname{.snd}, \fname{.shn}, \fname{.vox}, \fname{.w64}, 320 \fname{.snd}, \fname{.shn}, \fname{.vox}, \fname{.w64},
288 \fname{.wav}, \fname{.cmc}, \fname{.cm3}, \fname{.cmr}, 321 \fname{.wav}, \fname{.cmc}, \fname{.cm3}, \fname{.cmr},
289 \fname{.cms}, \fname{.dmc}, \fname{.dlt}, \fname{.mpt}, 322 \fname{.cms}, \fname{.dmc}, \fname{.dlt}, \fname{.mpt},
290 \fname{.mpd} \\ 323 \fname{.mpd}, \fname{.hes}, \fname{.vgz} \\
291 \end{rbtabular} 324 \end{rbtabular}
292 325
293 \subsection{Featureset for generic metadata tags} 326 \subsection{Featureset for generic metadata tags}
@@ -322,17 +355,21 @@
322 Replaygain & \fname{.mpc}\\ 355 Replaygain & \fname{.mpc}\\
323 Title & \fname{.tta}, \fname{.spc}, \fname{.mmf}, \fname{.sid}, 356 Title & \fname{.tta}, \fname{.spc}, \fname{.mmf}, \fname{.sid},
324 \fname{.rm}, \fname{.ra}, \fname{.rmvb}, \fname{.nsf}, 357 \fname{.rm}, \fname{.ra}, \fname{.rmvb}, \fname{.nsf},
325 \fname{.nsfe}, \fname{.mod}, \fname{.sap} \\ 358 \fname{.nsfe}, \fname{.mod}, \fname{.sap}, \fname{.gbs},
359 \fname{.ay}, \fname{.sgc}, \fname{.vgm} \\
326 Artist & \fname{.tta}, \fname{.spc}, \fname{.mmf}, \fname{.sid}, 360 Artist & \fname{.tta}, \fname{.spc}, \fname{.mmf}, \fname{.sid},
327 \fname{.rm}, \fname{.ra}, \fname{.rmvb}, \fname{.nsf}, 361 \fname{.rm}, \fname{.ra}, \fname{.rmvb}, \fname{.nsf},
328 \fname{.nsfe}, \fname{.sap} \\ 362 \fname{.nsfe}, \fname{.sap}, \fname{.gbs}, \fname{.ay},
329 Album & \fname{.spc}, \fname{.sid}, \fname{.nsf}, \fname{.nsfe} \\ 363 \fname{.sgc}, \fname{.vgm} \\
364 Album & \fname{.spc}, \fname{.sid}, \fname{.nsf}, \fname{.nsfe},
365 \fname{.gbs}, \fname{.ay}, \fname{.sgc}, \fname{.vgm} \\
330 Genre & \fname{.tta}, \fname{.spc}, \fname{.sap} \\ 366 Genre & \fname{.tta}, \fname{.spc}, \fname{.sap} \\
331 Disc & \fname{.tta} \\ 367 Disc & \fname{.tta} \\
332 Track & \fname{.tta} \\ 368 Track & \fname{.tta} \\
333 Year & \fname{.spc}, \fname{.sid}, \fname{.sap} \\ 369 Year & \fname{.spc}, \fname{.sid}, \fname{.sap} \\
334 Composer & \fname{.mmf} \\ 370 Composer & \fname{.mmf} \\
335 Comment & \fname{.spc}, \fname{.rm}, \fname{.ra}, \fname{.rmvb} \\ 371 Comment & \fname{.spc}, \fname{.rm}, \fname{.ra}, \fname{.rmvb},
372 \fname{.vgm} \\
336 Albumartist & None \\ 373 Albumartist & None \\
337 Grouping & None \\ 374 Grouping & None \\
338 \end{rbtabular} 375 \end{rbtabular}