diff options
Diffstat (limited to 'apps/codecs')
133 files changed, 32448 insertions, 4415 deletions
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 | |||
33 | wav64.c | 33 | wav64.c |
34 | tta.c | 34 | tta.c |
35 | wmapro.c | 35 | wmapro.c |
36 | ay.c | ||
37 | gbs.c | ||
38 | hes.c | ||
39 | sgc.c | ||
40 | vgm.c | ||
41 | kss.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 | |||
7 | CODEC_HEADER | ||
8 | |||
9 | /* Maximum number of bytes to process in one iteration */ | ||
10 | #define CHUNK_SIZE (1024*2) | ||
11 | |||
12 | static int16_t samples[CHUNK_SIZE] IBSS_ATTR; | ||
13 | static struct Ay_Emu ay_emu IDATA_ATTR CACHEALIGN_ATTR; | ||
14 | |||
15 | /****************** rockbox interface ******************/ | ||
16 | |||
17 | static 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 */ | ||
29 | enum 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 */ | ||
47 | enum 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 | |||
90 | next_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(¶m); | ||
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 | |||
43 | include $(APPSDIR)/codecs/libatrac/libatrac.make | 43 | include $(APPSDIR)/codecs/libatrac/libatrac.make |
44 | include $(APPSDIR)/codecs/libpcm/libpcm.make | 44 | include $(APPSDIR)/codecs/libpcm/libpcm.make |
45 | include $(APPSDIR)/codecs/libtta/libtta.make | 45 | include $(APPSDIR)/codecs/libtta/libtta.make |
46 | include $(APPSDIR)/codecs/libgme/libay.make | ||
47 | include $(APPSDIR)/codecs/libgme/libgbs.make | ||
48 | include $(APPSDIR)/codecs/libgme/libhes.make | ||
49 | include $(APPSDIR)/codecs/libgme/libnsf.make | ||
50 | include $(APPSDIR)/codecs/libgme/libsgc.make | ||
51 | include $(APPSDIR)/codecs/libgme/libvgm.make | ||
52 | include $(APPSDIR)/codecs/libgme/libkss.make | ||
46 | 53 | ||
47 | # compile flags for codecs | 54 | # compile flags for codecs |
48 | CODECFLAGS = $(CFLAGS) -fstrict-aliasing -I$(APPSDIR)/codecs \ | 55 | CODECFLAGS = $(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 | |||
7 | CODEC_HEADER | ||
8 | |||
9 | /* Maximum number of bytes to process in one iteration */ | ||
10 | #define CHUNK_SIZE (1024*2) | ||
11 | |||
12 | static int16_t samples[CHUNK_SIZE] IBSS_ATTR; | ||
13 | static struct Gbs_Emu gbs_emu IDATA_ATTR CACHEALIGN_ATTR; | ||
14 | |||
15 | /****************** rockbox interface ******************/ | ||
16 | |||
17 | static 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 */ | ||
28 | enum 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 */ | ||
46 | enum 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 | |||
79 | next_track: | ||
80 | set_codec_track(track); | ||
81 | |||
82 | /* The main decoder loop */ | ||
83 | while (1) { | ||
84 | enum codec_command_action action = ci->get_command(¶m); | ||
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 | |||
7 | CODEC_HEADER | ||
8 | |||
9 | /* Maximum number of bytes to process in one iteration */ | ||
10 | #define CHUNK_SIZE (1024*2) | ||
11 | |||
12 | static int16_t samples[CHUNK_SIZE] IBSS_ATTR; | ||
13 | static struct Hes_Emu hes_emu IDATA_ATTR CACHEALIGN_ATTR; | ||
14 | |||
15 | /****************** rockbox interface ******************/ | ||
16 | |||
17 | static 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 */ | ||
28 | enum 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 */ | ||
46 | enum 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 | |||
79 | next_track: | ||
80 | set_codec_track(track); | ||
81 | |||
82 | /* The main decoder loop */ | ||
83 | while ( 1 ) { | ||
84 | enum codec_command_action action = ci->get_command(¶m); | ||
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 | |||
7 | CODEC_HEADER | ||
8 | |||
9 | /* Maximum number of bytes to process in one iteration */ | ||
10 | #define CHUNK_SIZE (1024*2) | ||
11 | |||
12 | static int16_t samples[CHUNK_SIZE] IBSS_ATTR; | ||
13 | static struct Kss_Emu kss_emu IDATA_ATTR CACHEALIGN_ATTR; | ||
14 | |||
15 | /****************** rockbox interface ******************/ | ||
16 | |||
17 | static 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 */ | ||
28 | enum 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 */ | ||
46 | enum 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 | |||
84 | next_track: | ||
85 | set_codec_track(track); | ||
86 | |||
87 | /* The main decoder loop */ | ||
88 | while (1) { | ||
89 | enum codec_command_action action = ci->get_command(¶m); | ||
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 */ | ||
2 | 0x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
3 | 0x61,0x61,0x1e,0x17,0xf0,0x7f,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
4 | 0x13,0x41,0x16,0x0e,0xfd,0xf4,0x23,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
5 | 0x03,0x01,0x9a,0x04,0xf3,0xf3,0x13,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
6 | 0x11,0x61,0x0e,0x07,0xfa,0x64,0x70,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
7 | 0x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
8 | 0x21,0x22,0x16,0x05,0xf0,0x71,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
9 | 0x21,0x61,0x1d,0x07,0x82,0x80,0x17,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
10 | 0x23,0x21,0x2d,0x16,0x90,0x90,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
11 | 0x21,0x21,0x1b,0x06,0x64,0x65,0x10,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
12 | 0x21,0x21,0x0b,0x1a,0x85,0xa0,0x70,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
13 | 0x23,0x01,0x83,0x10,0xff,0xb4,0x10,0xf4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
14 | 0x97,0xc1,0x20,0x07,0xff,0xf4,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
15 | 0x61,0x00,0x0c,0x05,0xc2,0xf6,0x40,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
16 | 0x01,0x01,0x56,0x03,0x94,0xc2,0x03,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
17 | 0x21,0x01,0x89,0x03,0xf1,0xe4,0xf0,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
18 | 0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
19 | 0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
20 | 0x25,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 */ | ||
2 | 0x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
3 | 0x62,0x21,0x1a,0x07,0xf0,0x6f,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
4 | 0x00,0x10,0x44,0x02,0xf6,0xf4,0x54,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
5 | 0x03,0x01,0x97,0x04,0xf3,0xf3,0x13,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
6 | 0x01,0x61,0x0a,0x0f,0xfa,0x64,0x70,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
7 | 0x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
8 | 0x00,0x61,0x8a,0x0e,0xc0,0x61,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
9 | 0x21,0x61,0x1b,0x07,0x84,0x80,0x17,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
10 | 0x37,0x32,0xc9,0x01,0x66,0x64,0x40,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
11 | 0x01,0x21,0x06,0x03,0xa5,0x71,0x51,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
12 | 0x06,0x11,0x5e,0x07,0xf3,0xf2,0xf6,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
13 | 0x00,0x20,0x18,0x06,0xf5,0xf3,0x20,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
14 | 0x97,0x41,0x20,0x07,0xff,0xf4,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
15 | 0x65,0x61,0x15,0x00,0xf7,0xf3,0x16,0xf4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
16 | 0x01,0x31,0x0e,0x07,0xfa,0xf3,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
17 | 0x48,0x61,0x09,0x07,0xf1,0x94,0xf0,0xf5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
18 | 0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
19 | 0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
20 | 0x25,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 @@ | |||
1 | ay_apu.c | ||
2 | ay_cpu.c | ||
3 | ay_emu.c | ||
4 | blip_buffer.c | ||
5 | multi_buffer.c | ||
6 | z80_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 @@ | |||
1 | gb_apu.c | ||
2 | gb_cpu.c | ||
3 | gbs_cpu.c | ||
4 | gb_oscs.c | ||
5 | gbs_emu.c | ||
6 | blip_buffer.c | ||
7 | multi_buffer.c | ||
8 | rom_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 @@ | |||
1 | hes_apu.c | ||
2 | hes_apu_adpcm.c | ||
3 | hes_cpu.c | ||
4 | hes_emu.c | ||
5 | blip_buffer.c | ||
6 | multi_buffer.c | ||
7 | rom_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 @@ | |||
1 | ay_apu.c | ||
2 | kss_cpu.c | ||
3 | kss_emu.c | ||
4 | kss_scc_apu.c | ||
5 | opl_apu.c | ||
6 | sms_apu.c | ||
7 | ymdeltat.c | ||
8 | z80_cpu.c | ||
9 | blip_buffer.c | ||
10 | multi_buffer.c | ||
11 | rom_data.c | ||
12 | emu2413.c | ||
13 | emu8950.c | ||
14 | emuadpcm.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 @@ | |||
1 | nes_apu.c | ||
2 | nes_cpu.c | ||
3 | nes_fds_apu.c | ||
4 | nes_fme7_apu.c | ||
5 | nes_namco_apu.c | ||
6 | nes_oscs.c | ||
7 | nes_vrc6_apu.c | ||
8 | nes_vrc7_apu.c | ||
9 | nsf_cpu.c | ||
10 | nsf_emu.c | ||
11 | nsfe_info.c | ||
12 | blip_buffer.c | ||
13 | multi_buffer.c | ||
14 | rom_data.c | ||
15 | emu2413.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 @@ | |||
1 | sgc_cpu.c | ||
2 | sgc_emu.c | ||
3 | sms_apu.c | ||
4 | sms_fm_apu.c | ||
5 | ym2413_emu.c | ||
6 | z80_cpu.c | ||
7 | blip_buffer.c | ||
8 | multi_buffer.c | ||
9 | rom_data.c | ||
10 | emu2413.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 @@ | |||
1 | blip_buffer.c | ||
2 | multi_buffer.c | ||
3 | resampler.c | ||
4 | sms_apu.c | ||
5 | vgm_emu.c | ||
6 | emu2413.c | ||
7 | ym2413_emu.c | ||
8 | ym2612_emu.c | ||
9 | inflate/bbfuncs.c | ||
10 | inflate/inflate.c | ||
11 | inflate/mallocer.c | ||
12 | inflate/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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 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). | ||
25 | int const inaudible_freq = 16384; | ||
26 | |||
27 | int const period_factor = 16; | ||
28 | |||
29 | static 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 | |||
56 | static 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 | |||
70 | void 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 | |||
77 | void 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 | |||
107 | void 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 | |||
131 | int 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 | |||
140 | void 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 | |||
177 | int const noise_off = 0x08; | ||
178 | int const tone_off = 0x01; | ||
179 | |||
180 | void 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 | ||
12 | enum { ay_reg_count = 16 }; | ||
13 | enum { ay_osc_count = 3 }; | ||
14 | enum { ay_amp_range = 255 }; | ||
15 | |||
16 | struct 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 | |||
25 | struct 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 | |||
43 | void Ay_apu_init( struct Ay_Apu* this ); | ||
44 | |||
45 | // Writes to address register | ||
46 | static 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 | ||
49 | void run_until( struct Ay_Apu* this, blip_time_t final_end_time ) ICODE_ATTR;; | ||
50 | void write_data_( struct Ay_Apu* this, int addr, int data ) ICODE_ATTR; | ||
51 | static 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 | ||
54 | int Ay_apu_read( struct Ay_Apu* this ); | ||
55 | |||
56 | // Resets sound chip | ||
57 | void Ay_apu_reset( struct Ay_Apu* this ); | ||
58 | |||
59 | // Sets overall volume, where 1.0 is normal | ||
60 | static 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 | |||
62 | static 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. | ||
70 | static 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 | ||
9 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
10 | General Public License as published by the Free Software Foundation; either | ||
11 | version 2.1 of the License, or (at your option) any later version. This | ||
12 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
14 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
15 | details. You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this module; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
18 | |||
19 | #include "blargg_source.h" | ||
20 | |||
21 | void 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 \ | ||
50 | bool 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 | ||
8 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
9 | General Public License as published by the Free Software Foundation; either | ||
10 | version 2.1 of the License, or (at your option) any later version. This | ||
11 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
13 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
14 | details. You should have received a copy of the GNU Lesser General Public | ||
15 | License along with this module; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
17 | |||
18 | #include "blargg_source.h" | ||
19 | |||
20 | int const stereo = 2; // number of channels for stereo | ||
21 | int const silence_max = 6; // seconds | ||
22 | int const silence_threshold = 0x10; | ||
23 | long const fade_block_size = 512; | ||
24 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
25 | |||
26 | const 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 | |||
30 | int const spectrum_clock = 3546900; // 128K Spectrum | ||
31 | int const spectrum_period = 70908; | ||
32 | |||
33 | //int const spectrum_clock = 3500000; // 48K Spectrum | ||
34 | //int const spectrum_period = 69888; | ||
35 | |||
36 | int const cpc_clock = 2000000; | ||
37 | |||
38 | void 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 | |||
53 | void 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. | ||
80 | static 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 | |||
92 | static 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 | |||
110 | long 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 | |||
131 | void 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 | |||
137 | blargg_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 | |||
163 | void 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 | |||
172 | void 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 | |||
180 | blargg_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 | |||
244 | void 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 | |||
290 | enable_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 | |||
301 | blargg_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 | |||
314 | void 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 | |||
324 | void 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 | |||
346 | void 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 | |||
362 | void fill_buf( struct Ay_Emu *this ) ICODE_ATTR;; | ||
363 | blargg_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 | |||
524 | blargg_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 | |||
531 | long 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 | |||
538 | blargg_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 | |||
546 | blargg_err_t play_( struct Ay_Emu *this, long count, sample_t* out ) ICODE_ATTR; | ||
547 | blargg_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 | |||
576 | blargg_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 | |||
609 | void 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 ) | ||
616 | static 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 | |||
623 | void 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 | |||
647 | void 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 | ||
660 | static 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 | ||
671 | void 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 | |||
688 | blargg_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 | |||
760 | blargg_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 | |||
14 | typedef short sample_t; | ||
15 | |||
16 | // 64K memory to load code and data into before starting track. Caller | ||
17 | // must parse the AY file. | ||
18 | enum { mem_size = 0x10000 }; | ||
19 | enum { ram_addr = 0x4000 }; // where official RAM starts | ||
20 | enum { buf_size = 2048 }; | ||
21 | |||
22 | // AY file header | ||
23 | enum { header_size = 0x14 }; | ||
24 | struct 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 | |||
37 | struct file_t { | ||
38 | struct header_t const* header; | ||
39 | byte const* tracks; | ||
40 | byte const* end; // end of file data | ||
41 | }; | ||
42 | |||
43 | struct mem_t { | ||
44 | uint8_t padding1 [0x100]; | ||
45 | uint8_t ram [mem_size + 0x100]; | ||
46 | }; | ||
47 | |||
48 | struct 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) | ||
107 | void Ay_init( struct Ay_Emu* this ); | ||
108 | |||
109 | blargg_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. | ||
112 | blargg_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. | ||
115 | blargg_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. | ||
119 | blargg_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 | ||
125 | long Track_tell( struct Ay_Emu* this ); | ||
126 | |||
127 | // Seek to new time in track. Seeking backwards or far forward can take a while. | ||
128 | blargg_err_t Track_seek( struct Ay_Emu* this, long msec ); | ||
129 | |||
130 | // Skip n samples | ||
131 | blargg_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. | ||
135 | void Track_set_fade( struct Ay_Emu* this, long start_msec, long length_msec ); | ||
136 | |||
137 | // Get track length in milliseconds | ||
138 | long 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. | ||
144 | void Sound_set_tempo( struct Ay_Emu* this, double t ); | ||
145 | |||
146 | // Mute/unmute voice i, where voice 0 is first voice | ||
147 | void 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. | ||
151 | void 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(). | ||
155 | static 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) | ||
162 | void cpu_out( struct Ay_Emu* this, cpu_time_t, addr_t, int data ); | ||
163 | void cpu_out_( struct Ay_Emu* this, cpu_time_t, addr_t, int data ); | ||
164 | bool run_cpu( struct Ay_Emu* this, cpu_time_t end ); | ||
165 | |||
166 | static 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 | |||
54 | static 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 | |||
67 | static inline unsigned get_le16( void const* p ) { | ||
68 | return ((unsigned char const*) p) [1] * 0x100u + | ||
69 | ((unsigned char const*) p) [0]; | ||
70 | } | ||
71 | static inline unsigned get_be16( void const* p ) { | ||
72 | return ((unsigned char const*) p) [0] * 0x100u + | ||
73 | ((unsigned char const*) p) [1]; | ||
74 | } | ||
75 | static 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 | } | ||
81 | static 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 | } | ||
87 | static 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 | } | ||
91 | static 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 | } | ||
95 | static 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 | } | ||
101 | static 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 | ||
28 | static 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_ | ||
60 | typedef 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 | ||
12 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
13 | General Public License as published by the Free Software Foundation; either | ||
14 | version 2.1 of the License, or (at your option) any later version. This | ||
15 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
16 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
18 | details. You should have received a copy of the GNU Lesser General Public | ||
19 | License along with this module; if not, write to the Free Software Foundation, | ||
20 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
21 | |||
22 | #ifdef BLARGG_ENABLE_OPTIMIZER | ||
23 | #include BLARGG_ENABLE_OPTIMIZER | ||
24 | #endif | ||
25 | |||
26 | int const silent_buf_size = 1; // size used for Silent_Blip_Buffer | ||
27 | |||
28 | void 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 | |||
52 | void Blip_stop( struct Blip_Buffer* this ) | ||
53 | { | ||
54 | if ( this->buffer_size_ != silent_buf_size ) | ||
55 | free( this->buffer_ ); | ||
56 | } | ||
57 | |||
58 | void 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 | |||
70 | blargg_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) | ||
111 | double floor(double x) { | ||
112 | if ( x > 0 ) return (int)x; | ||
113 | return (int)(x-0.9999999999999999); | ||
114 | } | ||
115 | #endif | ||
116 | |||
117 | blip_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 | |||
125 | void 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 | |||
138 | void 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 | |||
144 | void 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 | |||
150 | long 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 | |||
157 | blip_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 | |||
171 | void 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 | |||
184 | long 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 | |||
227 | void 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 | |||
249 | void Blip_set_modified( struct Blip_Buffer* this ) | ||
250 | { | ||
251 | this->modified_ = 1; | ||
252 | } | ||
253 | |||
254 | int Blip_clear_modified( struct Blip_Buffer* this ) | ||
255 | { | ||
256 | int b = this->modified_; | ||
257 | this->modified_ = 0; | ||
258 | return b; | ||
259 | } | ||
260 | |||
261 | blip_resampled_time_t Blip_resampled_duration( struct Blip_Buffer* this, int t ) | ||
262 | { | ||
263 | return t * this->factor_; | ||
264 | } | ||
265 | |||
266 | blip_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 | |||
274 | void 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 | ||
282 | void 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 | ||
20 | typedef 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 | ||
36 | typedef short blip_sample_t; | ||
37 | enum { blip_sample_max = 32767 }; | ||
38 | enum { blip_widest_impulse_ = 16 }; | ||
39 | enum { blip_buffer_extra_ = blip_widest_impulse_ + 2 }; | ||
40 | enum { blip_res = 1 << BLIP_PHASE_BITS }; | ||
41 | enum { blip_max_length = 0 }; | ||
42 | enum { blip_default_length = 250 }; | ||
43 | |||
44 | // Maximun buffer size (48Khz, 50 ms) | ||
45 | enum { blip_buffer_max = 2466 }; | ||
46 | enum { blip_sample_bits = 30 }; | ||
47 | |||
48 | typedef blip_time_t buf_t_; | ||
49 | /* typedef const char* blargg_err_t; */ | ||
50 | typedef blip_ulong blip_resampled_time_t; | ||
51 | |||
52 | struct 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 | ||
68 | void Blip_set_modified( struct Blip_Buffer* this ) ICODE_ATTR; | ||
69 | int Blip_clear_modified( struct Blip_Buffer* this ) ICODE_ATTR; | ||
70 | void Blip_remove_silence( struct Blip_Buffer* this, long count ) ICODE_ATTR; | ||
71 | blip_resampled_time_t Blip_resampled_duration( struct Blip_Buffer* this, int t ) ICODE_ATTR; | ||
72 | blip_resampled_time_t Blip_resampled_time( struct Blip_Buffer* this, blip_time_t t ) ICODE_ATTR; | ||
73 | blip_resampled_time_t Blip_clock_rate_factor( struct Blip_Buffer* this, long clock_rate ) ICODE_ATTR; | ||
74 | |||
75 | // Initializes Blip_Buffer structure | ||
76 | void Blip_init( struct Blip_Buffer* this ); | ||
77 | |||
78 | // Stops (clear) Blip_Buffer structure | ||
79 | void 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. | ||
84 | blargg_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 | ||
87 | static 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. | ||
95 | void 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. | ||
101 | long 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 | ||
106 | static inline long Blip_sample_rate( struct Blip_Buffer* this ) | ||
107 | { | ||
108 | return this->sample_rate_; | ||
109 | } | ||
110 | |||
111 | // Length of buffer, in milliseconds | ||
112 | static inline int Blip_length( struct Blip_Buffer* this ) | ||
113 | { | ||
114 | return this->length_; | ||
115 | } | ||
116 | |||
117 | // Number of source time units per second | ||
118 | static 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 | ||
125 | void Blip_bass_freq( struct Blip_Buffer* this, int frequency ); | ||
126 | |||
127 | // Number of samples delay from synthesis to samples read out | ||
128 | static 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. | ||
135 | void Blip_clear( struct Blip_Buffer* this, int entire_buffer ); | ||
136 | |||
137 | // Number of samples available for reading with read_samples() | ||
138 | static 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 | ||
144 | void 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. | ||
151 | blip_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. | ||
154 | long Blip_count_samples( struct Blip_Buffer* this, blip_time_t duration ) ICODE_ATTR; | ||
155 | |||
156 | // Mix 'count' samples from 'buf' into buffer. | ||
157 | void 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 | |||
163 | struct Blip_Synth { | ||
164 | struct Blip_Buffer* buf; | ||
165 | int last_amp; | ||
166 | int delta_factor; | ||
167 | }; | ||
168 | |||
169 | // Initializes Blip_Synth structure | ||
170 | void Synth_init( struct Blip_Synth* this ); | ||
171 | |||
172 | // Set overall volume of waveform | ||
173 | void Synth_volume( struct Blip_Synth* this, double v ) ICODE_ATTR; | ||
174 | |||
175 | // Get/set Blip_Buffer used for output | ||
176 | const 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. | ||
187 | static 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. | ||
212 | static 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) | ||
222 | static 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 | ||
228 | static 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 | ||
66 | static 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 | ||
73 | static 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 */ | ||
173 | static e_uint32 clk = 844451141; | ||
174 | /* Sampling rate */ | ||
175 | static e_uint32 rate = 3354932; | ||
176 | |||
177 | /* WaveTable for each envelope amp */ | ||
178 | static e_uint16 fullsintable[PG_WIDTH]; | ||
179 | static e_uint16 halfsintable[PG_WIDTH]; | ||
180 | |||
181 | static e_uint16 *waveform[2] = { fullsintable, halfsintable }; | ||
182 | |||
183 | /* LFO Table */ | ||
184 | static e_int32 pmtable[PM_PG_WIDTH]; | ||
185 | static e_int32 amtable[AM_PG_WIDTH]; | ||
186 | |||
187 | /* Phase delta for LFO */ | ||
188 | static e_uint32 pm_dphase; | ||
189 | static e_uint32 am_dphase; | ||
190 | |||
191 | /* dB to Liner table */ | ||
192 | static e_int16 DB2LIN_TABLE[(DB_MUTE + DB_MUTE) * 2]; | ||
193 | |||
194 | /* Liner to Log curve conversion table (for Attack rate). */ | ||
195 | static e_uint16 AR_ADJUST_TABLE[1 << EG_BITS]; | ||
196 | |||
197 | /* Empty voice data */ | ||
198 | static OPLL_PATCH null_patch = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
199 | |||
200 | /* Basic voice Data */ | ||
201 | static OPLL_PATCH default_patch[OPLL_TONE_NUM][(16 + 3) * 2]; | ||
202 | |||
203 | /* Definition of envelope mode */ | ||
204 | enum OPLL_EG_STATE | ||
205 | { READY, ATTACK, DECAY, SUSHOLD, SUSTINE, RELEASE, SETTLE, FINISH }; | ||
206 | |||
207 | /* Phase incr table for Attack */ | ||
208 | static e_uint32 dphaseARTable[16][16]; | ||
209 | /* Phase incr table for Decay and Release */ | ||
210 | static e_uint32 dphaseDRTable[16][16]; | ||
211 | |||
212 | /* KSL + TL Table */ | ||
213 | static e_uint32 tllTable[16][8][1 << TL_BITS][4]; | ||
214 | static 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 */ | ||
219 | static e_uint32 dphaseTable[512][8][16]; | ||
220 | #endif | ||
221 | |||
222 | /*************************************************** | ||
223 | |||
224 | Create tables | ||
225 | |||
226 | ****************************************************/ | ||
227 | INLINE static e_int32 | ||
228 | Min (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. */ | ||
237 | static void | ||
238 | makeAdjustTable (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) */ | ||
253 | static void | ||
254 | makeDB2LinTable (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) */ | ||
271 | static e_int32 | ||
272 | lin2db (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 */ | ||
282 | static void | ||
283 | makeSinTable (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 | |||
310 | static 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 */ | ||
321 | static void | ||
322 | makePmTable (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 */ | ||
336 | static void | ||
337 | makeAmTable (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 */ | ||
348 | static void | ||
349 | makeDphaseTable (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 | |||
362 | static void | ||
363 | makeTllTable (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 | ||
396 | static 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 | |||
415 | static 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 */ | ||
436 | static void | ||
437 | makeDphaseARTable (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 */ | ||
484 | static void | ||
485 | makeDphaseDRTable (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 | |||
523 | static void | ||
524 | makeRksTable (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 | |||
540 | void | ||
541 | OPLL_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 | |||
569 | void | ||
570 | OPLL_getDefaultPatch (e_int32 type, e_int32 num, OPLL_PATCH * patch) | ||
571 | { | ||
572 | OPLL_dump2patch (default_inst[type] + num * 16, patch); | ||
573 | } | ||
574 | |||
575 | static void | ||
576 | makeDefaultPatch ( 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 | |||
586 | void | ||
587 | OPLL_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 | |||
600 | void | ||
601 | OPLL_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 | |||
627 | INLINE static e_uint32 | ||
628 | calc_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) | ||
678 | INLINE static void | ||
679 | UPDATE_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 */ | ||
706 | INLINE static void | ||
707 | slotOn (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 */ | ||
716 | INLINE static void | ||
717 | slotOn2 (OPLL_SLOT * slot) | ||
718 | { | ||
719 | slot->eg_mode = ATTACK; | ||
720 | slot->eg_phase = 0; | ||
721 | UPDATE_EG(slot); | ||
722 | } | ||
723 | |||
724 | /* Slot key off */ | ||
725 | INLINE static void | ||
726 | slotOff (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 */ | ||
735 | INLINE static void | ||
736 | keyOn (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 */ | ||
746 | INLINE static void | ||
747 | keyOff (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 | |||
754 | INLINE static void | ||
755 | keyOn_BD (OPLL * opll) | ||
756 | { | ||
757 | keyOn (opll, 6); | ||
758 | } | ||
759 | INLINE static void | ||
760 | keyOn_SD (OPLL * opll) | ||
761 | { | ||
762 | if (!opll->slot_on_flag[SLOT_SD]) | ||
763 | slotOn (CAR(opll,7)); | ||
764 | } | ||
765 | INLINE static void | ||
766 | keyOn_TOM (OPLL * opll) | ||
767 | { | ||
768 | if (!opll->slot_on_flag[SLOT_TOM]) | ||
769 | slotOn (MOD(opll,8)); | ||
770 | } | ||
771 | INLINE static void | ||
772 | keyOn_HH (OPLL * opll) | ||
773 | { | ||
774 | if (!opll->slot_on_flag[SLOT_HH]) | ||
775 | slotOn2 (MOD(opll,7)); | ||
776 | } | ||
777 | INLINE static void | ||
778 | keyOn_CYM (OPLL * opll) | ||
779 | { | ||
780 | if (!opll->slot_on_flag[SLOT_CYM]) | ||
781 | slotOn2 (CAR(opll,8)); | ||
782 | } | ||
783 | |||
784 | /* Drum key off */ | ||
785 | INLINE static void | ||
786 | keyOff_BD (OPLL * opll) | ||
787 | { | ||
788 | keyOff (opll, 6); | ||
789 | } | ||
790 | INLINE static void | ||
791 | keyOff_SD (OPLL * opll) | ||
792 | { | ||
793 | if (opll->slot_on_flag[SLOT_SD]) | ||
794 | slotOff (CAR(opll,7)); | ||
795 | } | ||
796 | INLINE static void | ||
797 | keyOff_TOM (OPLL * opll) | ||
798 | { | ||
799 | if (opll->slot_on_flag[SLOT_TOM]) | ||
800 | slotOff (MOD(opll,8)); | ||
801 | } | ||
802 | INLINE static void | ||
803 | keyOff_HH (OPLL * opll) | ||
804 | { | ||
805 | if (opll->slot_on_flag[SLOT_HH]) | ||
806 | slotOff (MOD(opll,7)); | ||
807 | } | ||
808 | INLINE static void | ||
809 | keyOff_CYM (OPLL * opll) | ||
810 | { | ||
811 | if (opll->slot_on_flag[SLOT_CYM]) | ||
812 | slotOff (CAR(opll,8)); | ||
813 | } | ||
814 | |||
815 | /* Change a voice */ | ||
816 | INLINE static void | ||
817 | setPatch (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 */ | ||
825 | INLINE static void | ||
826 | setSlotPatch (OPLL_SLOT * slot, OPLL_PATCH * patch) | ||
827 | { | ||
828 | slot->patch = patch; | ||
829 | } | ||
830 | |||
831 | /* Set sustine parameter */ | ||
832 | INLINE static void | ||
833 | setSustine (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 ) */ | ||
841 | INLINE static void | ||
842 | setVolume (OPLL * opll, e_int32 c, e_int32 volume) | ||
843 | { | ||
844 | CAR(opll,c)->volume = volume; | ||
845 | } | ||
846 | |||
847 | INLINE static void | ||
848 | setSlotVolume (OPLL_SLOT * slot, e_int32 volume) | ||
849 | { | ||
850 | slot->volume = volume; | ||
851 | } | ||
852 | |||
853 | /* Set F-Number ( fnum : 9bit ) */ | ||
854 | INLINE static void | ||
855 | setFnumber (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 ) */ | ||
862 | INLINE static void | ||
863 | setBlock (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 */ | ||
870 | INLINE static void | ||
871 | update_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 | |||
932 | INLINE static void | ||
933 | update_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 | |||
951 | void | ||
952 | OPLL_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 | |||
963 | static void | ||
964 | OPLL_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 | |||
987 | static void | ||
988 | internal_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 | |||
999 | static void | ||
1000 | maketables (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 | |||
1022 | void | ||
1023 | OPLL_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 | |||
1040 | void | ||
1041 | OPLL_delete (OPLL * opll) | ||
1042 | { | ||
1043 | (void) opll; | ||
1044 | } | ||
1045 | |||
1046 | |||
1047 | /* Reset patch datas by system default. */ | ||
1048 | void | ||
1049 | OPLL_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. */ | ||
1058 | void | ||
1059 | OPLL_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). */ | ||
1099 | void | ||
1100 | OPLL_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 | |||
1120 | void | ||
1121 | OPLL_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 | |||
1132 | void | ||
1133 | OPLL_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 */ | ||
1170 | static void | ||
1171 | update_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 */ | ||
1180 | INLINE static void | ||
1181 | calc_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 */ | ||
1194 | static void | ||
1195 | update_noise (OPLL * opll) | ||
1196 | { | ||
1197 | if(opll->noise_seed&1) opll->noise_seed ^= 0x8003020; | ||
1198 | opll->noise_seed >>= 1; | ||
1199 | } | ||
1200 | |||
1201 | /* EG */ | ||
1202 | static void | ||
1203 | calc_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 */ | ||
1300 | INLINE static e_int32 | ||
1301 | calc_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 */ | ||
1317 | INLINE static e_int32 | ||
1318 | calc_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 */ | ||
1345 | INLINE static e_int32 | ||
1346 | calc_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 */ | ||
1356 | INLINE static e_int32 | ||
1357 | calc_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 | */ | ||
1371 | INLINE static e_int32 | ||
1372 | calc_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 | */ | ||
1394 | INLINE static e_int32 | ||
1395 | calc_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 | |||
1424 | static e_int16 | ||
1425 | calc (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 | |||
1486 | void | ||
1487 | OPLL_set_internal_mute(OPLL * opll, e_uint32 mute) | ||
1488 | { | ||
1489 | opll->internal_mute = mute; | ||
1490 | } | ||
1491 | |||
1492 | e_uint32 | ||
1493 | OPLL_is_internal_muted(OPLL * opll) | ||
1494 | { | ||
1495 | return opll->internal_mute; | ||
1496 | } | ||
1497 | |||
1498 | e_uint32 | ||
1499 | check_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 | |||
1527 | void | ||
1528 | check_mute(OPLL * opll) | ||
1529 | { | ||
1530 | OPLL_set_internal_mute (opll, check_mute_helper (opll)); | ||
1531 | } | ||
1532 | |||
1533 | EMU2413_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 | ||
1545 | e_int16 | ||
1546 | OPLL_calc (OPLL * opll) | ||
1547 | { | ||
1548 | return calc (opll); | ||
1549 | } | ||
1550 | #else | ||
1551 | e_int16 | ||
1552 | OPLL_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 | |||
1572 | e_uint32 | ||
1573 | OPLL_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 | |||
1587 | e_uint32 | ||
1588 | OPLL_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 | |||
1608 | void | ||
1609 | OPLL_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 | |||
1845 | void | ||
1846 | OPLL_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 | |||
1854 | e_uint32 | ||
1855 | OPLL_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) */ | ||
1867 | void | ||
1868 | OPLL_set_pan (OPLL * opll, e_uint32 ch, e_uint32 pan) | ||
1869 | { | ||
1870 | opll->pan[ch & 15] = pan & 3; | ||
1871 | } | ||
1872 | |||
1873 | static void | ||
1874 | calc_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 | |||
1935 | void | ||
1936 | OPLL_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 | ||
16 | extern "C" { | ||
17 | #endif | ||
18 | |||
19 | #define AUDIO_MONO_BUFFER_SIZE 1024 | ||
20 | |||
21 | #define PI 3.14159265358979323846 | ||
22 | |||
23 | enum OPLL_TONE_ENUM {OPLL_2413_TONE=0, OPLL_VRC7_TONE=1, OPLL_281B_TONE=2} ; | ||
24 | |||
25 | /* voice data */ | ||
26 | typedef 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 */ | ||
31 | typedef 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 */ | ||
71 | typedef 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 */ | ||
122 | EMU2413_API void OPLL_new(OPLL *, e_uint32 clk, e_uint32 rate) ; | ||
123 | EMU2413_API void OPLL_delete(OPLL *) ; | ||
124 | |||
125 | /* Setup */ | ||
126 | EMU2413_API void OPLL_reset(OPLL *) ; | ||
127 | EMU2413_API void OPLL_reset_patch(OPLL *, e_int32) ; | ||
128 | EMU2413_API void OPLL_set_rate(OPLL *opll, e_uint32 r) ; | ||
129 | EMU2413_API void OPLL_set_quality(OPLL *opll, e_uint32 q) ; | ||
130 | EMU2413_API void OPLL_set_pan(OPLL *, e_uint32 ch, e_uint32 pan); | ||
131 | EMU2413_API void OPLL_set_internal_mute(OPLL *, e_uint32 mute); | ||
132 | EMU2413_API e_uint32 OPLL_is_internal_muted(OPLL *); | ||
133 | |||
134 | /* Port/Register access */ | ||
135 | EMU2413_API void OPLL_writeIO(OPLL *, e_uint32 reg, e_uint32 val); ICODE_ATTR | ||
136 | EMU2413_API void OPLL_writeReg(OPLL *, e_uint32 reg, e_uint32 val); ICODE_ATTR | ||
137 | EMU2413_API e_uint32 OPLL_read(OPLL *, e_uint32 port); | ||
138 | |||
139 | /* Synthsize */ | ||
140 | EMU2413_API e_int16 OPLL_calc(OPLL *) ; ICODE_ATTR | ||
141 | EMU2413_API void OPLL_calc_stereo(OPLL *, e_int32 out[2]) ; ICODE_ATTR | ||
142 | EMU2413_API e_int16 *OPLL_update_buffer(OPLL *, e_uint32 length) ; ICODE_ATTR | ||
143 | |||
144 | /* Misc */ | ||
145 | EMU2413_API void OPLL_setPatch(OPLL *, const e_uint8 *dump) ; | ||
146 | EMU2413_API void OPLL_copyPatch(OPLL *, e_int32, OPLL_PATCH *) ; | ||
147 | EMU2413_API void OPLL_forceRefresh(OPLL *) ; | ||
148 | /* Utility */ | ||
149 | EMU2413_API void OPLL_dump2patch(const e_uint8 *dump, OPLL_PATCH *patch) ; | ||
150 | EMU2413_API void OPLL_patch2dump(const OPLL_PATCH *patch, e_uint8 *dump) ; | ||
151 | EMU2413_API void OPLL_getDefaultPatch(e_int32 type, e_int32 num, OPLL_PATCH *) ; | ||
152 | |||
153 | /* Channel Mask */ | ||
154 | EMU2413_API e_uint32 OPLL_setMask(OPLL *, e_uint32 mask) ; | ||
155 | EMU2413_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 | ||
25 | static short dB2LinTab[(2*DB_MUTE)*2]; | ||
26 | // Dynamic range | ||
27 | static unsigned int dphaseNoiseTable[1024][8]; | ||
28 | // LFO Table | ||
29 | int pmtable[2][PM_PG_WIDTH]; | ||
30 | int amtable[2][AM_PG_WIDTH]; | ||
31 | |||
32 | /** WaveTable for each envelope amp. */ | ||
33 | static int sintable[PG_WIDTH]; | ||
34 | /** Phase incr table for Attack. */ | ||
35 | static unsigned int dphaseARTable[16][16]; | ||
36 | /** Phase incr table for Decay and Release. */ | ||
37 | static unsigned int dphaseDRTable[16][16]; | ||
38 | /** KSL + TL Table. */ | ||
39 | static int tllTable[16][8][1<<TL_BITS][4]; | ||
40 | static 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. */ | ||
45 | static unsigned int dphaseTable[1024][8][16]; | ||
46 | #endif | ||
47 | |||
48 | /** Liner to Log curve conversion table (for Attack rate). */ | ||
49 | static 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 | |||
59 | inline static int DB_POS(int x) | ||
60 | { | ||
61 | return (int)(x/DB_STEP); | ||
62 | } | ||
63 | |||
64 | inline 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 | ||
70 | inline static int HIGHBITS(int c, int b) | ||
71 | { | ||
72 | return c >> b; | ||
73 | } | ||
74 | // Leave the lower b bits | ||
75 | inline 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 | ||
80 | inline 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. | ||
92 | static 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) | ||
105 | static 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 | ||
121 | static 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 | |||
136 | void 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 | ||
144 | void 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 | ||
162 | void 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 | ||
181 | static 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 | |||
196 | static 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 | ||
225 | static 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 | ||
248 | static 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 | |||
267 | static 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 | |||
286 | void 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 | |||
301 | static 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 | |||
314 | static inline void slotUpdateTLL(struct Slot* slot) | ||
315 | { | ||
316 | slot->tll = tllTable[slot->fnum>>6][slot->block][slot->patch.TL][slot->patch.KL]; | ||
317 | } | ||
318 | |||
319 | static inline void slotUpdateRKS(struct Slot* slot) | ||
320 | { | ||
321 | slot->rks = rksTable[slot->fnum>>9][slot->block][slot->patch.KR]; | ||
322 | } | ||
323 | |||
324 | static 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 | |||
348 | static 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 | |||
356 | void 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 | ||
378 | static 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 | ||
389 | static 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 | |||
407 | void 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 ) | ||
415 | static 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 ) | ||
422 | static void channelSetBlock(struct OPLChannel* ch, int block) | ||
423 | { | ||
424 | ch->car.block = block; | ||
425 | ch->mod.block = block; | ||
426 | } | ||
427 | |||
428 | // OPLChannel key on | ||
429 | static void keyOn(struct OPLChannel* ch) | ||
430 | { | ||
431 | slotOn(&ch->mod); | ||
432 | slotOn(&ch->car); | ||
433 | } | ||
434 | |||
435 | // OPLChannel key off | ||
436 | static void keyOff(struct OPLChannel* ch) | ||
437 | { | ||
438 | slotOff(&ch->mod); | ||
439 | slotOff(&ch->car); | ||
440 | } | ||
441 | |||
442 | |||
443 | //**********************************************************// | ||
444 | // // | ||
445 | // Y8950 // | ||
446 | // // | ||
447 | //**********************************************************// | ||
448 | |||
449 | void 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 | |||
478 | void 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. | ||
494 | void 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 | ||
538 | static inline void keyOn_BD(struct Y8950* this) { keyOn(&this->ch[6]); } | ||
539 | static inline void keyOn_HH(struct Y8950* this) { slotOn(&this->ch[7].mod); } | ||
540 | static inline void keyOn_SD(struct Y8950* this) { slotOn(&this->ch[7].car); } | ||
541 | static inline void keyOn_TOM(struct Y8950* this) { slotOn(&this->ch[8].mod); } | ||
542 | static inline void keyOn_CYM(struct Y8950* this) { slotOn(&this->ch[8].car); } | ||
543 | |||
544 | // Drum key off | ||
545 | static inline void keyOff_BD(struct Y8950* this) { keyOff(&this->ch[6]); } | ||
546 | static inline void keyOff_HH(struct Y8950* this) { slotOff(&this->ch[7].mod); } | ||
547 | static inline void keyOff_SD(struct Y8950* this) { slotOff(&this->ch[7].car); } | ||
548 | static inline void keyOff_TOM(struct Y8950* this){ slotOff(&this->ch[8].mod); } | ||
549 | static inline void keyOff_CYM(struct Y8950* this){ slotOff(&this->ch[8].car); } | ||
550 | |||
551 | // Change Rhythm Mode | ||
552 | inline 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). | ||
582 | inline 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). | ||
592 | inline 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 | |||
601 | static 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 | |||
620 | static 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 | |||
628 | static 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 | |||
638 | static 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 | |||
707 | inline 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 | |||
716 | inline 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 | ||
735 | inline 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 | ||
745 | inline 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 | ||
759 | inline 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 | ||
770 | inline 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 | |||
781 | static 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 | |||
825 | bool 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 | |||
847 | void checkMute(struct Y8950* this) | ||
848 | { | ||
849 | bool mute = checkMuteHelper(this); | ||
850 | //PRT_DEBUG("Y8950: muted " << mute); | ||
851 | OPL_setInternalMute(this, mute); | ||
852 | } | ||
853 | |||
854 | int* 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 | |||
888 | void OPL_setInternalVolume(struct Y8950* this, short newVolume) | ||
889 | { | ||
890 | this->maxVolume = newVolume; | ||
891 | } | ||
892 | |||
893 | //**************************************************// | ||
894 | // // | ||
895 | // I/O Ctrl // | ||
896 | // // | ||
897 | //**************************************************// | ||
898 | |||
899 | void 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 | |||
1136 | byte 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 | |||
1162 | byte 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 | |||
1171 | void 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 | } | ||
1179 | void 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 | } | ||
1187 | void 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 | ||
10 | static const double EG_STEP = 0.1875; | ||
11 | #define EG_BITS 9 | ||
12 | #define EG_MUTE (1<<EG_BITS) | ||
13 | // Dynamic range of sustine level | ||
14 | static const double SL_STEP = 3.0; | ||
15 | static 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 | ||
21 | static 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 | ||
25 | static const int EG_DP_BITS = 23; | ||
26 | #define EG_DP_WIDTH (1<<EG_DP_BITS) | ||
27 | // Dynamic range of total level | ||
28 | static const double TL_STEP = 0.75; | ||
29 | #define TL_BITS 6 | ||
30 | #define TL_MUTE (1<<TL_BITS) | ||
31 | |||
32 | static 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) | ||
36 | static const int PM_AMP_BITS = 8; | ||
37 | #define PM_AMP (1<<PM_AMP_BITS) | ||
38 | |||
39 | |||
40 | |||
41 | static const int CLK_FREQ = 3579545; | ||
42 | static const double MPI = 3.14159265358979; | ||
43 | // PM speed(Hz) and depth(cent) | ||
44 | static const double PM_SPEED = 6.4; | ||
45 | static const double PM_DEPTH = (13.75/2); | ||
46 | static const double PM_DEPTH2 = 13.75; | ||
47 | // AM speed(Hz) and depth(dB) | ||
48 | static const double AM_SPEED = 3.7; | ||
49 | static const double AM_DEPTH = 1.0; | ||
50 | static const double AM_DEPTH2 = 4.8; | ||
51 | // Bits for liner value | ||
52 | static 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) | ||
58 | static 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) | ||
62 | static const int AM_DP_BITS = 16; | ||
63 | #define AM_DP_WIDTH (1<<AM_DP_BITS) | ||
64 | |||
65 | // Bitmask for register 0x04 | ||
66 | /** Timer1 Start. */ | ||
67 | static const int R04_ST1 = 0x01; | ||
68 | /** Timer2 Start. */ | ||
69 | static const int R04_ST2 = 0x02; | ||
70 | // not used | ||
71 | //static const int R04 = 0x04; | ||
72 | /** Mask 'Buffer Ready'. */ | ||
73 | static const int R04_MASK_BUF_RDY = 0x08; | ||
74 | /** Mask 'End of sequence'. */ | ||
75 | static const int R04_MASK_EOS = 0x10; | ||
76 | /** Mask Timer2 flag. */ | ||
77 | static const int R04_MASK_T2 = 0x20; | ||
78 | /** Mask Timer1 flag. */ | ||
79 | static const int R04_MASK_T1 = 0x40; | ||
80 | /** IRQ RESET. */ | ||
81 | static 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 | ||
90 | enum { ATTACK,DECAY,SUSHOLD,SUSTINE,RELEASE,FINISH }; | ||
91 | |||
92 | struct 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 | |||
105 | void patchReset(struct Patch* p); | ||
106 | |||
107 | struct 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 | |||
147 | void slotReset(struct Slot* slot); | ||
148 | |||
149 | |||
150 | struct OPLChannel { | ||
151 | bool alg; | ||
152 | struct Slot mod, car; | ||
153 | }; | ||
154 | |||
155 | void channelReset(struct OPLChannel* ch); | ||
156 | |||
157 | |||
158 | struct 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 | |||
220 | void OPL_init(struct Y8950* this_, byte* ramBank, int sampleRam); | ||
221 | |||
222 | void OPL_reset(struct Y8950* this_); | ||
223 | void OPL_writeReg(struct Y8950* this_, byte reg, byte data); | ||
224 | byte OPL_readReg(struct Y8950* this_, byte reg); | ||
225 | byte OPL_readStatus(struct Y8950* this_); | ||
226 | static inline void OPL_setInternalMute(struct Y8950* this_, bool muted) { this_->internalMuted = muted; } | ||
227 | static inline bool OPL_isInternalMuted(struct Y8950* this_) { return this_->internalMuted; } | ||
228 | |||
229 | void OPL_setSampleRate(struct Y8950* this_, int sampleRate, int clockRate); | ||
230 | int* OPL_updateBuffer(struct Y8950* this_, int length); | ||
231 | |||
232 | // SoundDevice | ||
233 | void OPL_setInternalVolume(struct Y8950* this_, short maxVolume); | ||
234 | |||
235 | void OPL_setStatus(struct Y8950* this_, byte flags); | ||
236 | void OPL_resetStatus(struct Y8950* this_, byte flags); | ||
237 | void OPL_changeStatusMask(struct Y8950* this_, byte newMask); | ||
238 | |||
239 | |||
240 | // Adjust envelope speed which depends on sampling rate | ||
241 | static 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 | ||
18 | const int ADPCM_VOLUME = 356; | ||
19 | |||
20 | // Bitmask for register 0x07 | ||
21 | static const int R07_RESET = 0x01; | ||
22 | //static const int R07 = 0x02;. // not used | ||
23 | //static const int R07 = 0x04;. // not used | ||
24 | const int R07_SP_OFF = 0x08; | ||
25 | const int R07_REPEAT = 0x10; | ||
26 | const int R07_MEMORY_DATA = 0x20; | ||
27 | const int R07_REC = 0x40; | ||
28 | const int R07_START = 0x80; | ||
29 | |||
30 | //Bitmask for register 0x08 | ||
31 | const int R08_ROM = 0x01; | ||
32 | const int R08_64K = 0x02; | ||
33 | const int R08_DA_AD = 0x04; | ||
34 | const int R08_SAMPL = 0x08; | ||
35 | //const int R08 = 0x10;. // not used | ||
36 | //const int R08 = 0x20;. // not used | ||
37 | const int R08_NOTE_SET = 0x40; | ||
38 | const int R08_CSM = 0x80; | ||
39 | |||
40 | const int DMAX = 0x6000; | ||
41 | const int DMIN = 0x7F; | ||
42 | const int DDEF = 0x7F; | ||
43 | |||
44 | const int DECODE_MAX = 32767; | ||
45 | const 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 | |||
57 | int 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 | |||
69 | void 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 | |||
79 | void restart(struct Y8950Adpcm* this_); | ||
80 | void 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 | |||
95 | void ADPCM_setSampleRate(struct Y8950Adpcm* this_, int sr, int clk) | ||
96 | { | ||
97 | this_->sampleRate = sr; | ||
98 | this_->clockRate = clk; | ||
99 | } | ||
100 | |||
101 | bool 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 | |||
112 | void 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 | |||
123 | void 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 | |||
209 | byte 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 | |||
240 | int 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 | |||
8 | typedef unsigned short word; | ||
9 | typedef unsigned __int64 uint64; | ||
10 | struct Y8950; | ||
11 | |||
12 | struct 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 | |||
43 | void ADPCM_init(struct Y8950Adpcm* this_, struct Y8950* y8950, byte* ramBank, int sampleRam); | ||
44 | void ADPCM_reset(struct Y8950Adpcm* this_); | ||
45 | void ADPCM_setSampleRate(struct Y8950Adpcm* this_, int sr, int clk); | ||
46 | bool ADPCM_muted(struct Y8950Adpcm* this_); | ||
47 | void ADPCM_writeReg(struct Y8950Adpcm* this_, byte rg, byte data); | ||
48 | byte ADPCM_readReg(struct Y8950Adpcm* this_, byte rg); | ||
49 | int 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 | |||
9 | static 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 | |||
31 | static 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 | |||
71 | static 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 | |||
148 | static 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 | ||
23 | extern "C" { | ||
24 | #endif | ||
25 | |||
26 | typedef unsigned int e_uint; | ||
27 | typedef signed int e_int; | ||
28 | |||
29 | typedef unsigned char e_uint8 ; | ||
30 | typedef signed char e_int8 ; | ||
31 | |||
32 | typedef unsigned short e_uint16 ; | ||
33 | typedef signed short e_int16 ; | ||
34 | |||
35 | typedef unsigned int e_uint32 ; | ||
36 | typedef 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 | ||
8 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
9 | General Public License as published by the Free Software Foundation; either | ||
10 | version 2.1 of the License, or (at your option) any later version. This | ||
11 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
13 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
14 | details. You should have received a copy of the GNU Lesser General Public | ||
15 | License along with this module; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
17 | |||
18 | #include "blargg_source.h" | ||
19 | |||
20 | int const vol_reg = 0xFF24; | ||
21 | int const stereo_reg = 0xFF25; | ||
22 | int const status_reg = 0xFF26; | ||
23 | int const wave_ram = 0xFF30; | ||
24 | |||
25 | int const power_mask = 0x80; | ||
26 | |||
27 | inline 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 | |||
33 | void 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 | |||
52 | void 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 | |||
58 | void 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 | |||
70 | void 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 | |||
79 | void 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 | |||
93 | void 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 | |||
101 | void 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 | |||
119 | void 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 | |||
155 | void 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 | |||
162 | void 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 | |||
192 | void 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 | |||
241 | inline 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 | |||
248 | void 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 | |||
264 | void 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 | |||
281 | void 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 | |||
296 | void 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 | |||
370 | int 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 | ||
10 | enum { clock_rate = 4194304 * GB_APU_OVERCLOCK }; | ||
11 | |||
12 | // Registers are at io_addr to io_addr+io_size-1 | ||
13 | enum { io_addr = 0xFF10 }; | ||
14 | enum { io_size = 0x30 }; | ||
15 | enum { regs_size = io_size + 0x10 }; | ||
16 | |||
17 | enum 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 | ||
24 | enum { osc_count = 4 }; // 0 <= chan < osc_count | ||
25 | |||
26 | struct 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 | ||
49 | void Apu_init( struct Gb_Apu* this ); | ||
50 | |||
51 | // Emulates to time t, then writes data to addr | ||
52 | void 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. | ||
56 | void 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 | ||
61 | int 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. | ||
65 | void 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 | ||
68 | void 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 | ||
72 | void 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. | ||
76 | void 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. | ||
80 | void Apu_set_tempo( struct Gb_Apu* this, double t ); | ||
81 | |||
82 | |||
83 | void 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 | ||
8 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
9 | General Public License as published by the Free Software Foundation; either | ||
10 | version 2.1 of the License, or (at your option) any later version. This | ||
11 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
13 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
14 | details. You should have received a copy of the GNU Lesser General Public | ||
15 | License along with this module; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
17 | |||
18 | #include "blargg_source.h" | ||
19 | |||
20 | inline 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 | |||
27 | void 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 | |||
43 | void 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 | |||
10 | typedef int addr_t; | ||
11 | |||
12 | // Emulator reads this many bytes past end of a page | ||
13 | enum { cpu_padding = 8 }; | ||
14 | enum { mem_size = 0x10000 }; | ||
15 | enum { page_bits = 13 }; | ||
16 | enum { page_size = 1 << page_bits }; | ||
17 | enum { page_count = mem_size >> page_bits }; | ||
18 | |||
19 | // Game Boy Z-80 registers. NOT kept updated during emulation. | ||
20 | struct core_regs_t { | ||
21 | uint16_t bc, de, hl, fa; | ||
22 | }; | ||
23 | |||
24 | struct 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 | |||
31 | struct cpu_state_t { | ||
32 | byte* code_map [page_count + 1]; | ||
33 | int time; | ||
34 | }; | ||
35 | |||
36 | struct 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 | ||
46 | static 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 | ||
53 | void 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. | ||
57 | void Cpu_map_code( struct Gb_Cpu* this, addr_t start, int size, void* code ) ICODE_ATTR; | ||
58 | |||
59 | // Current time. | ||
60 | static 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. | ||
64 | static 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 | ||
75 | static 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, | ||
6 | though they NEVER have side-effects, so multiple evaluation is OK. | ||
7 | - Output parameters might be a multiple-assignment expression like "a=x", | ||
8 | so 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 | ||
31 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
32 | General Public License as published by the Free Software Foundation; either | ||
33 | version 2.1 of the License, or (at your option) any later version. This | ||
34 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
35 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
36 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
37 | details. You should have received a copy of the GNU Lesser General Public | ||
38 | License along with this module; if not, write to the Free Software Foundation, | ||
39 | Inc., 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. | ||
73 | int const z80 = 0x80; // cz | ||
74 | int const n40 = 0x40; // ph | ||
75 | int const h20 = 0x20; // ph | ||
76 | int 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 | |||
152 | loop: | ||
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 | |||
1173 | stop: | ||
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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | int const cgb_02 = 0; // enables bug in early CGB units that causes problems in some games | ||
19 | int const cgb_05 = 0; // enables CGB-05 zombie behavior | ||
20 | |||
21 | int const trigger_mask = 0x80; | ||
22 | int const length_enabled = 0x40; | ||
23 | |||
24 | void 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 | |||
33 | inline 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 | |||
46 | void 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 | |||
55 | void 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 | |||
67 | void 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 | |||
79 | inline 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 | |||
86 | void 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 | |||
107 | void 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 | |||
120 | int 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 | |||
138 | int 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 | |||
165 | inline 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 | |||
201 | inline 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 | |||
237 | bool 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 | |||
278 | inline 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 | |||
318 | inline 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 | |||
334 | void 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 | |||
346 | inline 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 | |||
379 | void 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 | |||
395 | void 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. | ||
487 | static 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 | |||
562 | void 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 | |||
674 | void 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 | |||
18 | enum { clk_mul = GB_APU_OVERCLOCK }; | ||
19 | enum { dac_bias = 7 }; | ||
20 | |||
21 | struct 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 | ||
38 | static inline int Osc_frequency( struct Gb_Osc* this ) { return (this->regs [4] & 7) * 0x100 + this->regs [3]; } | ||
39 | |||
40 | void Osc_update_amp( struct Gb_Osc* this, blip_time_t, int new_amp ) ICODE_ATTR; | ||
41 | int Osc_write_trig( struct Gb_Osc* this, int frame_phase, int max_len, int old_data ) ICODE_ATTR; | ||
42 | void Osc_clock_length( struct Gb_Osc* this ) ICODE_ATTR; | ||
43 | void Osc_reset( struct Gb_Osc* this ); | ||
44 | |||
45 | // Square | ||
46 | |||
47 | enum { period_mask = 0x70 }; | ||
48 | enum { shift_mask = 0x07 }; | ||
49 | |||
50 | struct 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 | |||
64 | bool Square_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; | ||
65 | void Square_run( struct Gb_Square* this, blip_time_t, blip_time_t ) ICODE_ATTR; | ||
66 | void Square_clock_envelope( struct Gb_Square* this ) ICODE_ATTR; | ||
67 | |||
68 | static 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 | ||
76 | static inline int Square_period( struct Gb_Square* this ) { return (2048 - Osc_frequency( &this->osc )) * (4 * clk_mul); } | ||
77 | static inline int Square_dac_enabled( struct Gb_Square* this) { return this->osc.regs [2] & 0xF8; } | ||
78 | static 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 | |||
87 | void clock_sweep( struct Gb_Square* this ) ICODE_ATTR; | ||
88 | void Sweep_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; | ||
89 | |||
90 | static 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 | |||
103 | void calc_sweep( struct Gb_Square* this, bool update ) ICODE_ATTR; | ||
104 | void reload_sweep_timer( struct Gb_Square* this ) ICODE_ATTR; | ||
105 | |||
106 | // Noise | ||
107 | |||
108 | enum { period2_mask = 0x1FFFF }; | ||
109 | |||
110 | struct 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 | |||
120 | void Noise_run( struct Gb_Noise* this, blip_time_t, blip_time_t ) ICODE_ATTR; | ||
121 | void Noise_write_register( struct Gb_Noise* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; | ||
122 | |||
123 | static 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 | |||
133 | void Noise_clock_envelope( struct Gb_Noise* this ) ICODE_ATTR; | ||
134 | |||
135 | // Non-zero if DAC is enabled | ||
136 | static inline int Noise_dac_enabled( struct Gb_Noise* this) { return this->osc.regs [2] & 0xF8; } | ||
137 | static 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 | |||
144 | static inline int period2_index( struct Gb_Noise* this ) { return this->osc.regs [3] >> 4; } | ||
145 | static inline int period2( struct Gb_Noise* this, int base ) { return base << period2_index( this ); } | ||
146 | static inline unsigned lfsr_mask( struct Gb_Noise* this ) { return (this->osc.regs [3] & 0x08) ? ~0x4040 : ~0x4000; } | ||
147 | |||
148 | // Wave | ||
149 | |||
150 | enum { bank40_mask = 0x40 }; | ||
151 | enum { wave_bank_size = 32 }; | ||
152 | |||
153 | struct 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 | |||
162 | void Wave_write_register( struct Gb_Wave* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; | ||
163 | void Wave_run( struct Gb_Wave* this, blip_time_t, blip_time_t ) ICODE_ATTR; | ||
164 | |||
165 | static 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 | ||
172 | static 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 | ||
175 | static inline int Wave_dac_enabled( struct Gb_Wave* this ) { return this->osc.regs [0] & 0x80; } | ||
176 | |||
177 | void corrupt_wave( struct Gb_Wave* this ); | ||
178 | |||
179 | static 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 | ||
182 | int wave_access( struct Gb_Wave* this, int addr ) ICODE_ATTR; | ||
183 | |||
184 | // Reads/writes wave RAM | ||
185 | static 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 | |||
191 | static 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 | ||
7 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
8 | General Public License as published by the Free Software Foundation; either | ||
9 | version 2.1 of the License, or (at your option) any later version. This | ||
10 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
11 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
12 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
13 | details. You should have received a copy of the GNU Lesser General Public | ||
14 | License along with this module; if not, write to the Free Software Foundation, | ||
15 | Inc., 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 | |||
23 | int 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 | |||
32 | inline 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 | |||
44 | void 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 | |||
69 | void Write_io_( struct Gbs_Emu* this, int offset, int data ) | ||
70 | { | ||
71 | Write_io_inline( this, offset, data, io_base ); | ||
72 | } | ||
73 | |||
74 | inline 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 | |||
83 | int 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 \ | ||
116 | void 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 | ||
9 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
10 | General Public License as published by the Free Software Foundation; either | ||
11 | version 2.1 of the License, or (at your option) any later version. this | ||
12 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
14 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
15 | details. You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this module; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
18 | |||
19 | |||
20 | const char gme_wrong_file_type [] ICONST_ATTR = "Wrong file type for this emulator"; | ||
21 | |||
22 | int const idle_addr = 0xF00D; | ||
23 | int const tempo_unit = 16; | ||
24 | |||
25 | int const stereo = 2; // number of channels for stereo | ||
26 | int const silence_max = 6; // seconds | ||
27 | int const silence_threshold = 0x10; | ||
28 | long const fade_block_size = 512; | ||
29 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
30 | |||
31 | void 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 | |||
45 | void 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 | |||
72 | static 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 | |||
81 | blargg_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 | |||
137 | void 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 | |||
145 | void 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. | ||
164 | void 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 | |||
172 | blargg_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 | |||
211 | blargg_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 | |||
229 | blargg_err_t Run_clocks( struct Gbs_Emu* this, blip_time_t duration ) | ||
230 | { | ||
231 | return End_frame( this, duration ); | ||
232 | } | ||
233 | |||
234 | blargg_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 | |||
259 | blargg_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 | |||
275 | void 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 | |||
285 | void 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 | |||
307 | void 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 | |||
321 | void fill_buf( struct Gbs_Emu* this ); | ||
322 | blargg_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 | |||
402 | blargg_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 | |||
409 | long 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 | |||
416 | blargg_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 | |||
424 | blargg_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 | |||
453 | blargg_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 | |||
485 | void 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 ) | ||
492 | static 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 | |||
499 | void 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 | |||
523 | void 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 | ||
536 | static 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 | ||
547 | void 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 | |||
564 | blargg_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; */ | ||
14 | typedef short sample_t; | ||
15 | |||
16 | enum { joypad_addr = 0xFF00 }; | ||
17 | enum { ram_addr = 0xA000 }; | ||
18 | enum { hi_page = 0xFF00 - ram_addr }; | ||
19 | enum { io_base = 0xFF00 }; | ||
20 | enum { 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(). | ||
24 | enum 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 | ||
32 | enum { header_size = 112 }; | ||
33 | struct 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 | |||
50 | struct 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 | ||
113 | void Gbs_init( struct Gbs_Emu* this ); | ||
114 | |||
115 | // Stops (clear) Gbs_Emu structure | ||
116 | void Gbs_stop( struct Gbs_Emu* this ); | ||
117 | |||
118 | // Loads a file from memory | ||
119 | blargg_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. | ||
122 | blargg_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. | ||
125 | blargg_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. | ||
129 | blargg_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 | ||
133 | long Track_tell( struct Gbs_Emu* this ); | ||
134 | |||
135 | // Seek to new time in track. Seeking backwards or far forward can take a while. | ||
136 | blargg_err_t Track_seek( struct Gbs_Emu* this, long msec ); | ||
137 | |||
138 | // Skip n samples | ||
139 | blargg_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. | ||
143 | void Track_set_fade( struct Gbs_Emu* this, long start_msec, long length_msec ); | ||
144 | |||
145 | // Get track length in milliseconds | ||
146 | static 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. | ||
161 | void Sound_set_tempo( struct Gbs_Emu* this, double ); | ||
162 | |||
163 | // Mute/unmute voice i, where voice 0 is first voice | ||
164 | void 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. | ||
168 | void 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(). | ||
172 | static 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 | |||
181 | blargg_err_t Run_clocks( struct Gbs_Emu* this, blip_time_t duration ) ICODE_ATTR; | ||
182 | void Set_bank( struct Gbs_Emu* this, int ) ICODE_ATTR; | ||
183 | void Update_timer( struct Gbs_Emu* this ) ICODE_ATTR; | ||
184 | |||
185 | // Runs CPU until time becomes >= 0 | ||
186 | void Run_cpu( struct Gbs_Emu* this ) ICODE_ATTR; | ||
187 | |||
188 | // Reads/writes memory and I/O | ||
189 | int Read_mem( struct Gbs_Emu* this, addr_t addr ) ICODE_ATTR; | ||
190 | void Write_mem( struct Gbs_Emu* this, addr_t addr, int data ) ICODE_ATTR; | ||
191 | |||
192 | // Current time | ||
193 | static inline blip_time_t Time( struct Gbs_Emu* this ) | ||
194 | { | ||
195 | return Cpu_time( &this->cpu ) + this->end_time; | ||
196 | } | ||
197 | |||
198 | void Jsr_then_stop( struct Gbs_Emu* this, byte const [] ) ICODE_ATTR; | ||
199 | void Write_io_inline( struct Gbs_Emu* this, int offset, int data, int base ) ICODE_ATTR; | ||
200 | void Write_io_( struct Gbs_Emu* this, int offset, int data ) ICODE_ATTR; | ||
201 | int Read_io( struct Gbs_Emu* this, int offset ) ICODE_ATTR; | ||
202 | void 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) */ | ||
12 | typedef 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 | ||
7 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
8 | General Public License as published by the Free Software Foundation; either | ||
9 | version 2.1 of the License, or (at your option) any later version. This | ||
10 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
11 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
12 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
13 | details. You should have received a copy of the GNU Lesser General Public | ||
14 | License along with this module; if not, write to the Free Software Foundation, | ||
15 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
16 | |||
17 | #include "blargg_source.h" | ||
18 | |||
19 | enum { center_waves = 1 }; // reduces asymmetry and clamping when starting notes | ||
20 | |||
21 | static void Apu_balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc ) ICODE_ATTR; | ||
22 | static 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 | |||
68 | void 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 | |||
85 | void 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 | |||
102 | void 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 | |||
118 | void 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 | |||
230 | void 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 | |||
303 | void 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 | |||
10 | enum { amp_range = 0x8000 }; | ||
11 | enum { osc_count = 6 }; | ||
12 | enum { start_addr = 0x0800 }; | ||
13 | enum { end_addr = 0x0809 }; | ||
14 | |||
15 | struct 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 | |||
34 | void Osc_run_until( struct Hes_Osc* this, struct Blip_Synth* synth, blip_time_t ) ICODE_ATTR; | ||
35 | |||
36 | struct 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 | ||
45 | void Apu_init( struct Hes_Apu* this ); | ||
46 | |||
47 | // Reset HES apu couns chip | ||
48 | void Apu_reset( struct Hes_Apu* this ); | ||
49 | |||
50 | void Apu_osc_output( struct Hes_Apu* this, int index, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right ) ICODE_ATTR; | ||
51 | void Apu_write_data( struct Hes_Apu* this, blip_time_t, int addr, int data ) ICODE_ATTR; | ||
52 | void Apu_end_frame( struct Hes_Apu* this, blip_time_t ) ICODE_ATTR; | ||
53 | |||
54 | static 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | |||
17 | void 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 | |||
24 | void 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 | |||
48 | static 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 | |||
58 | static int Adpcm_decode( struct Hes_Apu_Adpcm* this,int code ) ICODE_ATTR; | ||
59 | static 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 | |||
102 | static void Adpcm_run_until( struct Hes_Apu_Adpcm* this, blip_time_t end_time ) ICODE_ATTR; | ||
103 | static 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 | |||
175 | void 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 | |||
259 | int 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 | |||
289 | void 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 | |||
11 | enum { adpcm_amp_range = 2048 }; | ||
12 | enum { adpcm_osc_count = 1 }; // 0 <= chan < osc_count | ||
13 | |||
14 | // Registers are at io_addr to io_addr+io_size-1 | ||
15 | enum { io_addr = 0x1800 }; | ||
16 | enum { io_size = 0x400 }; | ||
17 | |||
18 | struct 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 | |||
40 | struct 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 | ||
51 | void Adpcm_init( struct Hes_Apu_Adpcm* this ); | ||
52 | |||
53 | // Rest HES adpcm sound chip | ||
54 | void 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. | ||
58 | static 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 | ||
78 | void 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 | ||
81 | int 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. | ||
85 | void Adpcm_end_frame( struct Hes_Apu_Adpcm* this,blip_time_t t ) ICODE_ATTR; | ||
86 | |||
87 | // Sets overall volume, where 1.0 is normal | ||
88 | static 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 | ||
10 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
11 | General Public License as published by the Free Software Foundation; either | ||
12 | version 2.1 of the License, or (at your option) any later version. This | ||
13 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
15 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
16 | details. You should have received a copy of the GNU Lesser General Public | ||
17 | License along with this module; if not, write to the Free Software Foundation, | ||
18 | Inc., 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 | ||
24 | int 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 | ||
40 | int const st_n = 0x80; | ||
41 | int const st_v = 0x40; | ||
42 | int const st_t = 0x20; | ||
43 | int const st_b = 0x10; | ||
44 | int const st_d = 0x08; | ||
45 | int const st_i = 0x04; | ||
46 | int const st_z = 0x02; | ||
47 | int const st_c = 0x01; | ||
48 | |||
49 | void Cpu_init( struct Hes_Cpu* this ) | ||
50 | { | ||
51 | this->state = &this->state_; | ||
52 | } | ||
53 | |||
54 | void 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 | |||
74 | void 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 | ||
96 | typedef int fint16; | ||
97 | typedef unsigned fuint16; | ||
98 | typedef unsigned fuint8; | ||
99 | typedef blargg_long fint32; | ||
100 | |||
101 | bool 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; | ||
150 | branch_not_taken: | ||
151 | s_time -= 2; | ||
152 | loop: | ||
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; | ||
212 | almost_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 | { | ||
224 | possibly_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_; | ||
1261 | handle_brk: | ||
1262 | pc++; | ||
1263 | result_ = 6; | ||
1264 | |||
1265 | interrupt: | ||
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 | |||
1290 | idle_done: | ||
1291 | s_time = 0; | ||
1292 | out_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 | |||
9 | typedef blargg_long hes_time_t; // clock cycle count | ||
10 | typedef unsigned hes_addr_t; // 16-bit address | ||
11 | |||
12 | struct Hes_Emu; | ||
13 | |||
14 | enum { future_hes_time = LONG_MAX / 2 + 1 }; | ||
15 | enum { page_size = 0x2000 }; | ||
16 | enum { page_shift = 13 }; | ||
17 | enum { 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) | ||
22 | enum { idle_addr = 0x1FFF }; | ||
23 | |||
24 | // Can read this many bytes past end of a page | ||
25 | enum { cpu_padding = 8 }; | ||
26 | enum { irq_inhibit = 0x04 }; | ||
27 | |||
28 | |||
29 | // Cpu state | ||
30 | struct 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 | ||
37 | struct 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 | |||
46 | struct 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 | ||
61 | void Cpu_init( struct Hes_Cpu* this ); | ||
62 | |||
63 | // Reset hes cpu | ||
64 | void 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. | ||
68 | bool Cpu_run( struct Hes_Emu* this, hes_time_t end_time ) ICODE_ATTR; | ||
69 | |||
70 | void Cpu_set_mmr( struct Hes_Emu* this, int reg, int bank ) ICODE_ATTR; | ||
71 | |||
72 | // Time of ning of next instruction to be executed | ||
73 | static inline hes_time_t Cpu_time( struct Hes_Cpu* this ) | ||
74 | { | ||
75 | return this->state->time + this->state->base; | ||
76 | } | ||
77 | |||
78 | static 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 | |||
87 | static 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 | |||
6 | int 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 | |||
15 | void 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 | ||
9 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
10 | General Public License as published by the Free Software Foundation; either | ||
11 | version 2.1 of the License, or (at your option) any later version. This | ||
12 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
14 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
15 | details. You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this module; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
18 | |||
19 | int const timer_mask = 0x04; | ||
20 | int const vdp_mask = 0x02; | ||
21 | int const i_flag_mask = 0x04; | ||
22 | int const unmapped = 0xFF; | ||
23 | |||
24 | long const period_60hz = 262 * 455L; // scanlines * clocks per scanline | ||
25 | |||
26 | int const stereo = 2; // number of channels for stereo | ||
27 | int const silence_max = 6; // seconds | ||
28 | int const silence_threshold = 0x10; | ||
29 | long const fade_block_size = 512; | ||
30 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
31 | |||
32 | const char gme_wrong_file_type [] ICONST_ATTR = "Wrong file type for this emulator"; | ||
33 | |||
34 | void 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 | |||
48 | void 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 | |||
76 | static 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 | |||
85 | blargg_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 | |||
154 | void recalc_timer_load( struct Hes_Emu* this ) ICODE_ATTR; | ||
155 | void 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 | |||
162 | void irq_changed( struct Hes_Emu* this ) ICODE_ATTR; | ||
163 | void run_until( struct Hes_Emu* this, hes_time_t present ) ICODE_ATTR; | ||
164 | void 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 | |||
193 | int 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 | |||
237 | void 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 | |||
316 | int 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 | |||
377 | void 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 | |||
395 | void 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 | |||
422 | static void adjust_time( blargg_long* time, hes_time_t delta ) ICODE_ATTR; | ||
423 | static 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 | |||
433 | blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ) ICODE_ATTR; | ||
434 | blargg_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 | |||
466 | blargg_err_t play_( struct Hes_Emu* this, long count, sample_t* out ) ICODE_ATTR; | ||
467 | blargg_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 | |||
495 | blargg_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 | |||
508 | void 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 | |||
518 | void 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 | |||
547 | void 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 | |||
560 | void fill_buf( struct Hes_Emu* this ) ICODE_ATTR; | ||
561 | blargg_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 | |||
635 | blargg_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 | |||
642 | long 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 | |||
649 | blargg_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 | |||
657 | blargg_err_t skip_( struct Hes_Emu* this, long count ) ICODE_ATTR; | ||
658 | blargg_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 | |||
687 | blargg_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 | |||
722 | void 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 ) | ||
729 | static int int_log( blargg_long x, int step, int unit ) ICODE_ATTR; | ||
730 | static 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 | |||
737 | void handle_fade( struct Hes_Emu* this, long out_count, sample_t* out ) ICODE_ATTR; | ||
738 | void 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 | |||
762 | void emu_play( struct Hes_Emu* this, long count, sample_t* out ) ICODE_ATTR; | ||
763 | void 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 | ||
778 | static long count_silence( sample_t* begin, long size ) ICODE_ATTR; | ||
779 | static 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 | ||
790 | void 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 | |||
807 | blargg_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 | |||
16 | typedef short sample_t; | ||
17 | |||
18 | enum { buf_size = 2048 }; | ||
19 | |||
20 | // HES file header | ||
21 | enum { header_size = 0x20 }; | ||
22 | struct 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 | |||
36 | struct 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 | |||
45 | struct vdp_t { | ||
46 | hes_time_t next_vbl; | ||
47 | byte latch; | ||
48 | byte control; | ||
49 | }; | ||
50 | |||
51 | struct irq_t { | ||
52 | hes_time_t timer; | ||
53 | hes_time_t vdp; | ||
54 | byte disables; | ||
55 | }; | ||
56 | |||
57 | |||
58 | struct 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 | ||
123 | void Hes_init( struct Hes_Emu* this ); | ||
124 | |||
125 | // Stops (clear) Hes_Emu structure | ||
126 | void Hes_stop( struct Hes_Emu* this ); | ||
127 | |||
128 | // Loads a file from memory | ||
129 | blargg_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. | ||
132 | blargg_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. | ||
135 | blargg_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. | ||
139 | blargg_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 | ||
143 | long Track_tell( struct Hes_Emu* this ); | ||
144 | |||
145 | // Seek to new time in track. Seeking backwards or far forward can take a while. | ||
146 | blargg_err_t Track_seek( struct Hes_Emu* this, long msec ); | ||
147 | |||
148 | // Skip n samples | ||
149 | blargg_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. | ||
153 | void Track_set_fade( struct Hes_Emu* this, long start_msec, long length_msec ); | ||
154 | |||
155 | // Get track length in milliseconds | ||
156 | static 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. | ||
171 | void Sound_set_tempo( struct Hes_Emu* this, double ); | ||
172 | |||
173 | // Mute/unmute voice i, where voice 0 is first voice | ||
174 | void 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. | ||
178 | void 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(). | ||
182 | static 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 | |||
191 | int Cpu_read( struct Hes_Emu* this, hes_addr_t ) ICODE_ATTR; | ||
192 | void Cpu_write( struct Hes_Emu* this, hes_addr_t, int ) ICODE_ATTR; | ||
193 | void Cpu_write_vdp( struct Hes_Emu* this, int addr, int data ) ICODE_ATTR; | ||
194 | int Cpu_done( struct Hes_Emu* this ) ICODE_ATTR; | ||
195 | |||
196 | int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t ) ICODE_ATTR; | ||
197 | void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t, int data ) ICODE_ATTR; | ||
198 | |||
199 | static 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 | |||
26 | void error_die(const char* msg) | ||
27 | { | ||
28 | (void)msg; | ||
29 | } | ||
30 | |||
31 | void error_msg(const char* msg) | ||
32 | { | ||
33 | (void)msg; | ||
34 | } | ||
35 | |||
36 | size_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 | */ | ||
52 | ssize_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. */ | ||
78 | void 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. */ | ||
89 | unsigned char xread_char(struct mbreader_t *md) | ||
90 | { | ||
91 | unsigned char tmp; | ||
92 | |||
93 | xread(md, &tmp, 1); | ||
94 | |||
95 | return tmp; | ||
96 | } | ||
97 | |||
98 | void 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 | |||
25 | void error_die(const char* msg); | ||
26 | void error_msg(const char* msg); | ||
27 | size_t safe_read(struct mbreader_t *md, void *buf, size_t count); | ||
28 | ssize_t full_read(struct mbreader_t *md, void *buf, size_t len); | ||
29 | void xread(struct mbreader_t *md, void *buf, ssize_t count); | ||
30 | unsigned char xread_char(struct mbreader_t *md); | ||
31 | void 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 | |||
48 | typedef 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;*/ | ||
58 | static void *huftbuffer1; | ||
59 | static void *huftbuffer2; | ||
60 | |||
61 | #define HUFT_MMP1 8 | ||
62 | #define HUFT_MMP2 9 | ||
63 | |||
64 | static struct mbreader_t *gunzip_src_md; | ||
65 | static unsigned int gunzip_bytes_out; /* number of output bytes */ | ||
66 | static 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 */ | ||
70 | enum { | ||
71 | gunzip_wsize = 0x8000 | ||
72 | }; | ||
73 | |||
74 | static unsigned char *gunzip_window; | ||
75 | static uint32_t ifl_total; | ||
76 | |||
77 | static 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 */ | ||
84 | static unsigned int gunzip_bb; /* bit buffer */ | ||
85 | static unsigned char gunzip_bk; /* bits in bit buffer */ | ||
86 | |||
87 | /* These control the size of the bytebuffer */ | ||
88 | static unsigned int bytebuffer_max = 0x8000; | ||
89 | static unsigned char *bytebuffer = NULL; | ||
90 | static unsigned int bytebuffer_offset = 0; | ||
91 | static unsigned int bytebuffer_size = 0; | ||
92 | |||
93 | static 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 */ | ||
99 | static 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 */ | ||
106 | static 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 */ | ||
112 | static 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 */ | ||
118 | static 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 */ | ||
125 | static 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 | |||
129 | static 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 | |||
183 | static 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 | */ | ||
214 | static 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 | */ | ||
236 | static | ||
237 | int 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 | */ | ||
437 | static int inflate_codes_resumeCopy = 0; | ||
438 | static 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 */ | ||
533 | do_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 | |||
583 | static 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 */ | ||
626 | static 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 | |||
921 | static 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 | |||
932 | static int inflate_get_next_window_method = -1; /* Method == -1 for stored, -2 | ||
933 | for codes */ | ||
934 | static int inflate_get_next_window_e = 0; | ||
935 | static int inflate_get_next_window_needAnotherBlock = 1; | ||
936 | |||
937 | static 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 */ | ||
980 | static 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 | |||
988 | static void inflate_cleanup(void) | ||
989 | { | ||
990 | /* free(bytebuffer); */ | ||
991 | } | ||
992 | |||
993 | USE_DESKTOP(long long) static int | ||
994 | inflate_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 | |||
1047 | USE_DESKTOP(long long) static int | ||
1048 | inflate_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*/ | ||
1097 | uint32_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 | |||
28 | uint32_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 | |||
12 | unsigned char* mallocbuffer[MEMPOOL_MAX]; | ||
13 | long memory_ptr[MEMPOOL_MAX]; | ||
14 | size_t buffersize[MEMPOOL_MAX]; | ||
15 | |||
16 | int 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 | |||
24 | int 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 | |||
33 | void wpw_reset_mempool(unsigned char mempool) | ||
34 | { | ||
35 | memory_ptr[mempool]=0; | ||
36 | } | ||
37 | |||
38 | void wpw_destroy_mempool(unsigned char mempool) | ||
39 | { | ||
40 | memory_ptr[mempool] = 0; | ||
41 | mallocbuffer[mempool] =0; | ||
42 | buffersize[mempool]=0; | ||
43 | } | ||
44 | |||
45 | long wpw_available(unsigned char mempool) | ||
46 | { | ||
47 | return buffersize[mempool]-memory_ptr[mempool]; | ||
48 | } | ||
49 | |||
50 | void* 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 | |||
63 | void* 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 | |||
74 | void wpw_free(unsigned char mempool,void* ptr) | ||
75 | { | ||
76 | (void)ptr; | ||
77 | (void)mempool; | ||
78 | } | ||
79 | |||
80 | void* 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 | |||
6 | int wpw_init_mempool(unsigned char mempool); | ||
7 | int wpw_init_mempool_pdm(unsigned char mempool, | ||
8 | unsigned char* mem,long memsize); | ||
9 | |||
10 | void wpw_reset_mempool(unsigned char mempool); | ||
11 | void wpw_destroy_mempool(unsigned char mempool); | ||
12 | void* wpw_malloc(unsigned char mempool,size_t size); | ||
13 | void* wpw_calloc(unsigned char mempool,size_t nmemb, size_t size); | ||
14 | void wpw_free(unsigned char mempool,void* ptr); | ||
15 | void* wpw_realloc(unsigned char mempool,void* ptr, size_t size); | ||
16 | long 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 | |||
8 | int 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 | |||
7 | struct mbreader_t { | ||
8 | const char *ptr; | ||
9 | size_t size; | ||
10 | size_t offset; | ||
11 | }; | ||
12 | |||
13 | int 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 | ||
9 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
10 | General Public License as published by the Free Software Foundation; either | ||
11 | version 2.1 of the License, or (at your option) any later version. This | ||
12 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
14 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
15 | details. You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this module; if not, write to the Free Software Foundation, | ||
17 | Inc., 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 \ | ||
27 | bool 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 | ||
8 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
9 | General Public License as published by the Free Software Foundation; either | ||
10 | version 2.1 of the License, or (at your option) any later version. This | ||
11 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
13 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
14 | details. You should have received a copy of the GNU Lesser General Public | ||
15 | License along with this module; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
17 | |||
18 | #include "blargg_source.h" | ||
19 | |||
20 | long const clock_rate = 3579545; | ||
21 | |||
22 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; | ||
23 | |||
24 | int const stereo = 2; // number of channels for stereo | ||
25 | int const silence_max = 6; // seconds | ||
26 | int const silence_threshold = 0x10; | ||
27 | long const fade_block_size = 512; | ||
28 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
29 | |||
30 | void 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 | |||
45 | static 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 | |||
52 | void 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 | |||
90 | static 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 | |||
99 | void 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 | |||
121 | blargg_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 | |||
244 | void 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 | |||
275 | void 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 | |||
282 | void 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 | |||
306 | void 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 | |||
341 | void 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 | |||
394 | int 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 | |||
419 | blargg_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 | |||
434 | blargg_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 | |||
469 | blargg_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 | |||
480 | void 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 | |||
490 | void 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 | |||
512 | void 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 | |||
526 | void fill_buf( struct Kss_Emu* this ); | ||
527 | blargg_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 | |||
626 | blargg_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 | |||
633 | long 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 | |||
640 | blargg_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 | |||
648 | blargg_err_t play_( struct Kss_Emu* this, long count, sample_t* out ); | ||
649 | blargg_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 | |||
678 | blargg_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 | |||
709 | void 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 ) | ||
716 | static 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 | |||
723 | void 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 | |||
747 | void 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 | ||
760 | static 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 | ||
771 | void 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 | |||
788 | blargg_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 | |||
860 | blargg_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 | |||
20 | typedef short sample_t; | ||
21 | typedef int kss_time_t; | ||
22 | typedef int kss_addr_t; | ||
23 | typedef struct Z80_Cpu Kss_Cpu; | ||
24 | |||
25 | // Sound chip flags | ||
26 | enum { | ||
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 | |||
35 | enum { idle_addr = 0xFFFF }; | ||
36 | enum { scc_enabled_true = 0xC000 }; | ||
37 | enum { mem_size = 0x10000 }; | ||
38 | enum { buf_size = 2048 }; | ||
39 | |||
40 | // KSS file header | ||
41 | enum { header_size = 0x20 }; | ||
42 | enum { header_base_size = 0x10 }; | ||
43 | enum { header_ext_size = header_size - header_base_size }; | ||
44 | |||
45 | struct 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 | |||
68 | struct sms_t { | ||
69 | struct Sms_Apu psg; | ||
70 | struct Opl_Apu fm; | ||
71 | }; | ||
72 | |||
73 | struct msx_t { | ||
74 | struct Ay_Apu psg; | ||
75 | struct Scc_Apu scc; | ||
76 | struct Opl_Apu music; | ||
77 | struct Opl_Apu audio; | ||
78 | }; | ||
79 | |||
80 | struct 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 | |||
146 | void Kss_init( struct Kss_Emu* this ); | ||
147 | blargg_err_t Kss_load_mem( struct Kss_Emu* this, const void* data, long size ); | ||
148 | blargg_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. | ||
151 | blargg_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. | ||
154 | blargg_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. | ||
158 | blargg_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 | ||
163 | long Track_tell( struct Kss_Emu* this ); | ||
164 | |||
165 | // Seek to new time in track. Seeking backwards or far forward can take a while. | ||
166 | blargg_err_t Track_seek( struct Kss_Emu* this, long msec ); | ||
167 | |||
168 | // Skip n samples | ||
169 | blargg_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. | ||
173 | void Track_set_fade( struct Kss_Emu* this, long start_msec, long length_msec ); | ||
174 | |||
175 | // Get track length in milliseconds | ||
176 | static 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. | ||
195 | void Sound_set_tempo( struct Kss_Emu* this, double t ); | ||
196 | |||
197 | // Mute/unmute voice i, where voice 0 is first voice | ||
198 | void 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. | ||
202 | void 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(). | ||
206 | static 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 | ||
213 | void cpu_write( struct Kss_Emu* this, kss_addr_t, int ) ICODE_ATTR; | ||
214 | int cpu_in( struct Kss_Emu* this, kss_time_t, kss_addr_t ) ICODE_ATTR; | ||
215 | void cpu_out( struct Kss_Emu* this, kss_time_t, kss_addr_t, int ) ICODE_ATTR; | ||
216 | |||
217 | void cpu_write_( struct Kss_Emu* this, kss_addr_t addr, int data ) ICODE_ATTR; | ||
218 | bool run_cpu( struct Kss_Emu* this, kss_time_t end ) ICODE_ATTR; | ||
219 | void jsr( struct Kss_Emu* this, byte const addr [] ) ICODE_ATTR; | ||
220 | |||
221 | static inline int sms_psg_enabled( struct Kss_Emu* this ) { return this->chip_flags & sms_psg_flag; } | ||
222 | static inline int sms_fm_enabled( struct Kss_Emu* this ) { return this->chip_flags & sms_fm_flag; } | ||
223 | static inline int msx_psg_enabled( struct Kss_Emu* this ) { return this->chip_flags & msx_psg_flag; } | ||
224 | static inline int msx_scc_enabled( struct Kss_Emu* this ) { return this->chip_flags & msx_scc_flag; } | ||
225 | static inline int msx_music_enabled( struct Kss_Emu* this ) { return this->chip_flags & msx_music_flag;} | ||
226 | static 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 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). | ||
20 | extern int const inaudible_freq; | ||
21 | |||
22 | int const wave_size = 0x20; | ||
23 | |||
24 | static 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 | |||
31 | void 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 | |||
36 | void 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 | |||
47 | void 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 | |||
56 | static 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 | |||
131 | void 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 | |||
159 | void 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 | |||
10 | enum { scc_reg_count = 0xB0 }; // 0 <= reg < reg_count | ||
11 | enum { scc_osc_count = 5 }; | ||
12 | enum { scc_amp_range = 0x8000 }; | ||
13 | |||
14 | struct scc_osc_t | ||
15 | { | ||
16 | int delay; | ||
17 | int phase; | ||
18 | int last_amp; | ||
19 | struct Blip_Buffer* output; | ||
20 | }; | ||
21 | |||
22 | struct 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 | |||
30 | void Scc_init( struct Scc_Apu* this ); | ||
31 | |||
32 | // Resets sound chip | ||
33 | void Scc_reset( struct Scc_Apu* this ); | ||
34 | |||
35 | // Set overall volume, where 1.0 is normal | ||
36 | void Scc_volume( struct Scc_Apu* this, double v ); | ||
37 | |||
38 | static 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 | ||
45 | void 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. | ||
49 | void 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 | ||
3 | AYLIB := $(CODECDIR)/libay.a | ||
4 | AYLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/AYSOURCES) | ||
5 | AYLIB_OBJ := $(call c2obj, $(AYLIB_SRC)) | ||
6 | OTHER_SRC += $(AYLIB_SRC) | ||
7 | |||
8 | $(AYLIB): $(AYLIB_OBJ) | ||
9 | $(SILENT)$(shell rm -f $@) | ||
10 | $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null | ||
11 | |||
12 | AYFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_AY_TYPE | ||
13 | ifeq ($(CPU),arm) | ||
14 | AYFLAGS += -O3 | ||
15 | else | ||
16 | AYFLAGS += -O2 | ||
17 | endif | ||
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 | ||
3 | GBSLIB := $(CODECDIR)/libgbs.a | ||
4 | GBSLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/GBSSOURCES) | ||
5 | GBSLIB_OBJ := $(call c2obj, $(GBSLIB_SRC)) | ||
6 | OTHER_SRC += $(GBSLIB_SRC) | ||
7 | |||
8 | $(GBSLIB): $(GBSLIB_OBJ) | ||
9 | $(SILENT)$(shell rm -f $@) | ||
10 | $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null | ||
11 | |||
12 | GBSFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_GBS_TYPE | ||
13 | ifeq ($(CPU),arm) | ||
14 | GBSFLAGS += -O3 | ||
15 | else | ||
16 | GBSFLAGS += -O2 | ||
17 | endif | ||
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 | ||
3 | HESLIB := $(CODECDIR)/libhes.a | ||
4 | HESLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/HESSOURCES) | ||
5 | HESLIB_OBJ := $(call c2obj, $(HESLIB_SRC)) | ||
6 | OTHER_SRC += $(HESLIB_SRC) | ||
7 | |||
8 | $(HESLIB): $(HESLIB_OBJ) | ||
9 | $(SILENT)$(shell rm -f $@) | ||
10 | $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null | ||
11 | |||
12 | HESFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_HES_TYPE | ||
13 | ifeq ($(CPU),arm) | ||
14 | HESFLAGS += -O3 | ||
15 | else | ||
16 | HESFLAGS += -O2 | ||
17 | endif | ||
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 | ||
3 | KSSLIB := $(CODECDIR)/libkss.a | ||
4 | KSSLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/KSSSOURCES) | ||
5 | KSSLIB_OBJ := $(call c2obj, $(KSSLIB_SRC)) | ||
6 | OTHER_SRC += $(KSSLIB_SRC) | ||
7 | |||
8 | $(KSSLIB): $(KSSLIB_OBJ) | ||
9 | $(SILENT)$(shell rm -f $@) | ||
10 | $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null | ||
11 | |||
12 | KSSFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_KSS_TYPE | ||
13 | ifeq ($(CPU),arm) | ||
14 | KSSFLAGS += -O3 | ||
15 | else | ||
16 | KSSFLAGS += -O2 | ||
17 | endif | ||
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 | ||
3 | NSFLIB := $(CODECDIR)/libnsf.a | ||
4 | NSFLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/NSFSOURCES) | ||
5 | NSFLIB_OBJ := $(call c2obj, $(NSFLIB_SRC)) | ||
6 | OTHER_SRC += $(NSFLIB_SRC) | ||
7 | |||
8 | $(NSFLIB): $(NSFLIB_OBJ) | ||
9 | $(SILENT)$(shell rm -f $@) | ||
10 | $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null | ||
11 | |||
12 | NSFFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_NSF_TYPE | ||
13 | ifeq ($(CPU),arm) | ||
14 | NSFFLAGS += -O3 | ||
15 | else | ||
16 | NSFFLAGS += -O2 | ||
17 | endif | ||
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 | ||
3 | SGCLIB := $(CODECDIR)/libsgc.a | ||
4 | SGCLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/SGCSOURCES) | ||
5 | SGCLIB_OBJ := $(call c2obj, $(SGCLIB_SRC)) | ||
6 | OTHER_SRC += $(SGCLIB_SRC) | ||
7 | |||
8 | $(SGCLIB): $(SGCLIB_OBJ) | ||
9 | $(SILENT)$(shell rm -f $@) | ||
10 | $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null | ||
11 | |||
12 | SGCFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_SGC_TYPE | ||
13 | ifeq ($(CPU),arm) | ||
14 | SGCFLAGS += -O3 | ||
15 | else | ||
16 | SGCFLAGS += -O2 | ||
17 | endif | ||
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 | ||
3 | VGMLIB := $(CODECDIR)/libvgm.a | ||
4 | VGMLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libgme/VGMSOURCES) | ||
5 | VGMLIB_OBJ := $(call c2obj, $(VGMLIB_SRC)) | ||
6 | OTHER_SRC += $(VGMLIB_SRC) | ||
7 | |||
8 | $(VGMLIB): $(VGMLIB_OBJ) | ||
9 | $(SILENT)$(shell rm -f $@) | ||
10 | $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null | ||
11 | |||
12 | VGMFLAGS = $(filter-out -O%,$(CODECFLAGS)) -fno-strict-aliasing -DGME_VGM_TYPE | ||
13 | ifeq ($(CPU),arm) | ||
14 | VGMFLAGS += -O3 | ||
15 | else | ||
16 | VGMFLAGS += -O2 | ||
17 | endif | ||
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 | |||
9 | struct entry_t | ||
10 | { | ||
11 | unsigned char track; // 1-based | ||
12 | int length; // milliseconds | ||
13 | }; | ||
14 | |||
15 | /* Short version of the m3u playlist */ | ||
16 | struct M3u_Playlist | ||
17 | { | ||
18 | unsigned char size; | ||
19 | struct entry_t *entries; | ||
20 | }; | ||
21 | |||
22 | static 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 | ||
5 | extern "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 | */ | ||
21 | typedef unsigned char UInt8; | ||
22 | #ifndef __CARBON__ | ||
23 | typedef unsigned short UInt16; | ||
24 | typedef unsigned int UInt32; | ||
25 | typedef unsigned __int64 UInt64; | ||
26 | #endif | ||
27 | typedef signed char Int8; | ||
28 | typedef signed short Int16; | ||
29 | typedef 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 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 | |||
24 | void 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 | |||
40 | blargg_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 | |||
51 | void 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 | |||
58 | void 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 | |||
65 | struct channel_t Buffer_channel( struct Stereo_Buffer* this ) | ||
66 | { | ||
67 | return this->chan; | ||
68 | } | ||
69 | |||
70 | void 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 | |||
79 | void 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 | |||
90 | long 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 | |||
135 | unsigned Buffer_channels_changed_count( struct Stereo_Buffer* this ) | ||
136 | { | ||
137 | return this->channels_changed_count_; | ||
138 | } | ||
139 | |||
140 | void Buffer_channels_changed( struct Stereo_Buffer* this ) | ||
141 | { | ||
142 | this->channels_changed_count_++; | ||
143 | } | ||
144 | |||
145 | void 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 | |||
178 | void 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 | |||
207 | void 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 | ||
11 | struct channel_t { | ||
12 | struct Blip_Buffer* center; | ||
13 | struct Blip_Buffer* left; | ||
14 | struct Blip_Buffer* right; | ||
15 | }; | ||
16 | |||
17 | enum { type_index_mask = 0xFF }; | ||
18 | enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type }; | ||
19 | enum { buf_count = 3 }; | ||
20 | |||
21 | struct 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 | ||
34 | void Buffer_init( struct Stereo_Buffer* this ); | ||
35 | |||
36 | blargg_err_t Buffer_set_sample_rate( struct Stereo_Buffer* this, long, int msec ); | ||
37 | void Buffer_clock_rate( struct Stereo_Buffer* this, long ); | ||
38 | void Buffer_bass_freq( struct Stereo_Buffer* this, int ); | ||
39 | void Buffer_clear( struct Stereo_Buffer* this ); | ||
40 | struct channel_t Buffer_channel( struct Stereo_Buffer* this ); | ||
41 | void Buffer_end_frame( struct Stereo_Buffer* this, blip_time_t ) ICODE_ATTR; | ||
42 | |||
43 | long 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. | ||
47 | unsigned Buffer_channels_changed_count( struct Stereo_Buffer* this ) ICODE_ATTR; | ||
48 | void Buffer_channels_changed( struct Stereo_Buffer* this ) ICODE_ATTR; | ||
49 | |||
50 | void Buffer_mix_stereo_no_center( struct Stereo_Buffer* this, blip_sample_t*, blargg_long ) ICODE_ATTR; | ||
51 | void Buffer_mix_stereo( struct Stereo_Buffer* this, blip_sample_t*, blargg_long ) ICODE_ATTR; | ||
52 | void 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) | ||
55 | static inline int Buffer_samples_per_frame( struct Stereo_Buffer* this ) | ||
56 | { | ||
57 | return this->samples_per_frame_; | ||
58 | } | ||
59 | |||
60 | // See Blip_Buffer.h | ||
61 | static inline long Buffer_sample_rate( struct Stereo_Buffer* this ) | ||
62 | { | ||
63 | return this->sample_rate_; | ||
64 | } | ||
65 | |||
66 | // Length of buffer, in milliseconds | ||
67 | static 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | int const amp_range = 15; | ||
19 | |||
20 | void 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 | |||
46 | static double nonlinear_tnd_gain( void ) { return 0.75; } | ||
47 | void 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 | |||
64 | void 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 | |||
73 | void 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 | |||
80 | void 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 | |||
88 | void 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 | |||
119 | void 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 | |||
138 | void 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 | |||
149 | void 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 | |||
229 | static 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 | |||
238 | void 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 | |||
276 | static 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 | |||
283 | void 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 | |||
370 | int 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 | |||
10 | enum { apu_status_addr = 0x4015 }; | ||
11 | enum { apu_osc_count = 5 }; | ||
12 | enum { apu_no_irq = INT_MAX / 2 + 1 }; | ||
13 | enum { apu_irq_waiting = 0 }; | ||
14 | |||
15 | enum { apu_io_addr = 0x4000 }; | ||
16 | enum { apu_io_size = 0x18 }; | ||
17 | |||
18 | struct apu_state_t; | ||
19 | |||
20 | struct 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 | ||
48 | void Apu_init( struct Nes_Apu* this ); | ||
49 | |||
50 | // Set buffer to generate all sound into, or disable sound if NULL | ||
51 | void 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) | ||
58 | void Apu_write_register( struct Nes_Apu* this, nes_time_t, addr_t, int data ) ICODE_ATTR; | ||
59 | |||
60 | // Read from status register at 0x4015 | ||
61 | int 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. | ||
66 | void 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. | ||
74 | void Apu_reset( struct Nes_Apu* this, bool pal_mode, int initial_dmc_dac ); | ||
75 | |||
76 | // Adjust frame period | ||
77 | void Apu_set_tempo( struct Nes_Apu* this, double ); | ||
78 | |||
79 | // Set overall volume (default is 1.0) | ||
80 | void 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). | ||
84 | void 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. | ||
90 | static 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. | ||
99 | static 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. | ||
108 | static 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. | ||
117 | static 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 | |||
122 | static 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 | ||
131 | static inline nes_time_t Apu_next_dmc_read_time( struct Nes_Apu* this ) { return Dmc_next_read_time( &this->dmc ); } | ||
132 | void 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 | ||
8 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
9 | General Public License as published by the Free Software Foundation; either | ||
10 | version 2.1 of the License, or (at your option) any later version. This | ||
11 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
13 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
14 | details. You should have received a copy of the GNU Lesser General Public | ||
15 | License along with this module; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
17 | |||
18 | #include "blargg_source.h" | ||
19 | |||
20 | inline 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 | |||
27 | void 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 | |||
41 | void 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 | |||
10 | typedef int nes_time_t; | ||
11 | typedef int addr_t; | ||
12 | |||
13 | enum { page_bits = 11 }; | ||
14 | enum { page_size = 1 << page_bits }; | ||
15 | enum { page_count = 0x10000 >> page_bits }; | ||
16 | |||
17 | // Unmapped page should be filled with this | ||
18 | enum { halt_opcode = 0x22 }; | ||
19 | |||
20 | enum { future_time = INT_MAX/2 + 1 }; | ||
21 | enum { irq_inhibit_mask = 0x04 }; | ||
22 | |||
23 | // Can read this many bytes past end of a page | ||
24 | enum { cpu_padding = 8 }; | ||
25 | |||
26 | struct 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 | |||
35 | struct cpu_state_t { | ||
36 | uint8_t const* code_map [page_count + 1]; | ||
37 | nes_time_t base; | ||
38 | int time; | ||
39 | }; | ||
40 | |||
41 | struct 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 | |||
51 | static 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 | ||
54 | void 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. | ||
60 | void 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 | ||
63 | static inline nes_time_t Cpu_time( struct Nes_Cpu* this ) { return this->cpu_state->time + this->cpu_state->base; } | ||
64 | static inline void Cpu_set_time( struct Nes_Cpu* this, nes_time_t t ) { this->cpu_state->time = t - this->cpu_state->base; } | ||
65 | static inline void Cpu_adjust_time( struct Nes_Cpu* this, int delta ) { this->cpu_state->time += delta; } | ||
66 | |||
67 | // Clocks past end (negative if before) | ||
68 | static 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 | ||
79 | static 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 | |||
84 | static 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 | ||
94 | static 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 | |||
100 | static 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 | |||
12 | int 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 | |||
52 | void 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, | ||
6 | though they NEVER have side-effects, so multiple evaluation is OK. | ||
7 | - Output parameters might be a multiple-assignment expression like "a=x", | ||
8 | so they must NOT be parenthesized. | ||
9 | - Except where noted, time() and related functions will NOT work | ||
10 | correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and | ||
11 | CACHE_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 | ||
62 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
63 | General Public License as published by the Free Software Foundation; either | ||
64 | version 2.1 of the License, or (at your option) any later version. This | ||
65 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
66 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
67 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
68 | details. You should have received a copy of the GNU Lesser General Public | ||
69 | License along with this module; if not, write to the Free Software Foundation, | ||
70 | Inc., 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. | ||
142 | int const n80 = 0x80; // nz | ||
143 | int const v40 = 0x40; // flags | ||
144 | int const r20 = 0x20; | ||
145 | int const b10 = 0x10; | ||
146 | int const d08 = 0x08; // flags | ||
147 | int const i04 = 0x04; // flags | ||
148 | int const z02 = 0x02; // nz | ||
149 | int 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 | |||
199 | loop: | ||
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 )\ | ||
284 | case op - 0x04: /* (ind,x) */\ | ||
285 | IND_X( data )\ | ||
286 | goto ptr##op;\ | ||
287 | case op + 0x0C: /* (ind),y */\ | ||
288 | IND_Y( PAGE_PENALTY, data )\ | ||
289 | goto ptr##op;\ | ||
290 | case op + 0x10: /* zp,X */\ | ||
291 | data = BYTE( data + x );\ | ||
292 | case op + 0x00: /* zp */\ | ||
293 | data = READ_LOW( data );\ | ||
294 | goto imm##op;\ | ||
295 | case op + 0x14: /* abs,Y */\ | ||
296 | data += y;\ | ||
297 | goto ind##op;\ | ||
298 | case op + 0x18: /* abs,X */\ | ||
299 | data += x;\ | ||
300 | ind##op:\ | ||
301 | PAGE_PENALTY( data );\ | ||
302 | case op + 0x08: /* abs */\ | ||
303 | ADD_PAGE( data );\ | ||
304 | ptr##op:\ | ||
305 | FLUSH_TIME();\ | ||
306 | data = READ_MEM( data );\ | ||
307 | CACHE_TIME();\ | ||
308 | case op + 0x04: /* imm */\ | ||
309 | imm##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_; | ||
1059 | handle_brk: | ||
1060 | pc++; | ||
1061 | result_ = b10 | 4; | ||
1062 | |||
1063 | #ifdef CPU_DONE | ||
1064 | interrupt: | ||
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 | |||
1093 | out_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 | ||
1106 | stop: | ||
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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | int const fract_range = 65536; | ||
19 | |||
20 | void 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 | |||
30 | void 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 | |||
61 | void 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 | |||
111 | void 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 | |||
122 | void 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 | |||
10 | enum { lfo_base_tempo = 8 }; | ||
11 | enum { fds_osc_count = 1 }; | ||
12 | |||
13 | enum { fds_io_addr = 0x4040 }; | ||
14 | enum { fds_io_size = 0x53 }; | ||
15 | |||
16 | enum { fds_wave_size = 0x40 }; | ||
17 | enum { fds_master_vol_max = 10 }; | ||
18 | enum { fds_vol_max = 0x20 }; | ||
19 | enum { fds_wave_sample_max = 0x3F }; | ||
20 | |||
21 | struct 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 | ||
49 | void Fds_init( struct Nes_Fds_Apu* this ); | ||
50 | // setup | ||
51 | void Fds_set_tempo( struct Nes_Fds_Apu* this, double t ); | ||
52 | |||
53 | // emulation | ||
54 | void Fds_reset( struct Nes_Fds_Apu* this ); | ||
55 | |||
56 | static 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 | |||
61 | static 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 | |||
71 | void Fds_run_until( struct Nes_Fds_Apu* this, blip_time_t ) ICODE_ATTR; | ||
72 | static 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 | |||
80 | void Fds_write_( struct Nes_Fds_Apu* this, unsigned addr, int data ) ICODE_ATTR; | ||
81 | static 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 | |||
87 | static 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) | ||
114 | static 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 | ||
8 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
9 | General Public License as published by the Free Software Foundation; either | ||
10 | version 2.1 of the License, or (at your option) any later version. This | ||
11 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
13 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
14 | details. You should have received a copy of the GNU Lesser General Public | ||
15 | License along with this module; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
17 | |||
18 | #include "blargg_source.h" | ||
19 | |||
20 | void 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 | |||
29 | void 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 | |||
43 | static 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 | |||
53 | void 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 | |||
10 | enum { fme7_reg_count = 14 }; | ||
11 | |||
12 | // Mask and addresses of registers | ||
13 | enum { fme7_addr_mask = 0xE000 }; | ||
14 | enum { fme7_data_addr = 0xE000 }; | ||
15 | enum { fme7_latch_addr = 0xC000 }; | ||
16 | enum { fme7_osc_count = 3 }; | ||
17 | |||
18 | enum { amp_range = 192 }; // can be any value; this gives best error/quality tradeoff | ||
19 | |||
20 | struct osc_t { | ||
21 | struct Blip_Buffer* output; | ||
22 | int last_amp; | ||
23 | }; | ||
24 | |||
25 | // static unsigned char const amp_table [16]; | ||
26 | |||
27 | struct 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 | ||
41 | void Fme7_init( struct Nes_Fme7_Apu* this ); | ||
42 | void Fme7_reset( struct Nes_Fme7_Apu* this ); | ||
43 | |||
44 | static 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 | |||
49 | static 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 | |||
55 | static 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 | ||
63 | static inline void Fme7_write_latch( struct Nes_Fme7_Apu* this, int data ) { this->latch = data; } | ||
64 | |||
65 | // (addr & addr_mask) == data_addr | ||
66 | void Fme7_run_until( struct Nes_Fme7_Apu* this, blip_time_t end_time ) ICODE_ATTR; | ||
67 | static 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 | |||
81 | static 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 | |||
10 | enum { mmc5_regs_addr = 0x5000 }; | ||
11 | enum { mmc5_regs_size = 0x16 }; | ||
12 | enum { mmc5_osc_count = 3 }; | ||
13 | enum { mmc5_exram_size = 1024 }; | ||
14 | |||
15 | struct Nes_Mmc5_Apu { | ||
16 | struct Nes_Apu apu; | ||
17 | unsigned char exram [mmc5_exram_size]; | ||
18 | }; | ||
19 | |||
20 | static inline void Mmc5_init( struct Nes_Mmc5_Apu* this ) | ||
21 | { | ||
22 | Apu_init( &this->apu ); | ||
23 | } | ||
24 | |||
25 | static 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 | |||
34 | static 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | void 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 | |||
27 | void 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 | |||
45 | void 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 | |||
52 | void 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 | |||
61 | void 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 | |||
10 | struct namco_state_t; | ||
11 | |||
12 | enum { namco_osc_count = 8 }; | ||
13 | enum { namco_addr_reg_addr = 0xF800 }; | ||
14 | enum { namco_data_reg_addr = 0x4800 }; | ||
15 | enum { namco_reg_count = 0x80 }; | ||
16 | |||
17 | struct Namco_Osc { | ||
18 | blargg_long delay; | ||
19 | struct Blip_Buffer* output; | ||
20 | short last_amp; | ||
21 | short wave_pos; | ||
22 | }; | ||
23 | |||
24 | struct 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. | ||
36 | void Namco_init( struct Nes_Namco_Apu* this ); | ||
37 | void Namco_output( struct Nes_Namco_Apu* this, struct Blip_Buffer* ); | ||
38 | |||
39 | void Namco_reset( struct Nes_Namco_Apu* this ); | ||
40 | void Namco_end_frame( struct Nes_Namco_Apu* this, blip_time_t ) ICODE_ATTR; | ||
41 | |||
42 | static 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 | |||
50 | static 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 | ||
53 | static inline void Namco_write_addr( struct Nes_Namco_Apu* this, int v ) { this->addr_reg = v; } | ||
54 | |||
55 | static inline int Namco_read_data( struct Nes_Namco_Apu* this ) { return *namco_access( this ); } | ||
56 | |||
57 | static 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 | ||
64 | void Namco_run_until( struct Nes_Namco_Apu* this, blip_time_t ) ICODE_ATTR; | ||
65 | static 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | // Nes_Osc | ||
19 | |||
20 | void 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 | |||
28 | void 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 | |||
44 | int 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 | |||
50 | void 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 | ||
85 | inline 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 | |||
98 | void 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 | |||
174 | void 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 | |||
186 | inline 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 | ||
195 | inline 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 | |||
209 | void 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 | |||
270 | void 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 | |||
287 | void 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 | |||
300 | int 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 | |||
329 | static 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 | |||
337 | inline 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 | |||
343 | static 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 | |||
355 | void 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 | |||
377 | void Dmc_start( struct Nes_Dmc* this ) | ||
378 | { | ||
379 | Dmc_reload_sample( this ); | ||
380 | Dmc_fill_buffer( this ); | ||
381 | Dmc_recalc_irq( this ); | ||
382 | } | ||
383 | |||
384 | void 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 | |||
407 | void 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 | |||
482 | static 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 | |||
487 | void 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 | |||
503 | int 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 | |||
509 | void 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 | |||
11 | struct Nes_Apu; | ||
12 | |||
13 | struct 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 | |||
23 | void Osc_clock_length( struct Nes_Osc* this, int halt_mask ); | ||
24 | static inline int Osc_period( struct Nes_Osc* this ) | ||
25 | { | ||
26 | return (this->regs [3] & 7) * 0x100 + (this->regs [2] & 0xFF); | ||
27 | } | ||
28 | |||
29 | static inline void Osc_reset( struct Nes_Osc* this ) | ||
30 | { | ||
31 | this->delay = 0; | ||
32 | this->last_amp = 0; | ||
33 | } | ||
34 | |||
35 | static 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 | |||
44 | enum { negate_flag = 0x08 }; | ||
45 | enum { shift_mask = 0x07 }; | ||
46 | enum { square_phase_range = 8 }; | ||
47 | |||
48 | typedef struct Blip_Synth Synth; | ||
49 | |||
50 | struct 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 | |||
61 | static inline void Square_set_synth( struct Nes_Square* this, Synth* s ) { this->synth = s; } | ||
62 | |||
63 | void Square_clock_sweep( struct Nes_Square* this, int adjust ); | ||
64 | void Square_run( struct Nes_Square* this, nes_time_t, nes_time_t ); | ||
65 | |||
66 | static 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 | |||
74 | void Square_clock_envelope( struct Nes_Square* this ); | ||
75 | int Square_volume( struct Nes_Square* this ); | ||
76 | |||
77 | // Nes_Triangle | ||
78 | |||
79 | enum { Triangle_phase_range = 16 }; | ||
80 | |||
81 | struct Nes_Triangle | ||
82 | { | ||
83 | struct Nes_Osc osc; | ||
84 | |||
85 | int phase; | ||
86 | int linear_counter; | ||
87 | struct Blip_Synth synth; | ||
88 | }; | ||
89 | |||
90 | void Triangle_run( struct Nes_Triangle* this, nes_time_t, nes_time_t ); | ||
91 | void Triangle_clock_linear_counter( struct Nes_Triangle* this ); | ||
92 | |||
93 | static 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 | ||
101 | struct 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 | |||
111 | void Noise_clock_envelope( struct Nes_Noise* this ); | ||
112 | int Noise_volume( struct Nes_Noise* this ); | ||
113 | void Noise_run( struct Nes_Noise* this, nes_time_t, nes_time_t ); | ||
114 | |||
115 | static 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 | |||
125 | enum { loop_flag = 0x40 }; | ||
126 | |||
127 | struct 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 | |||
155 | void Dmc_start( struct Nes_Dmc* this ); | ||
156 | void Dmc_write_register( struct Nes_Dmc* this, int, int ) ICODE_ATTR; | ||
157 | void Dmc_run( struct Nes_Dmc* this, nes_time_t, nes_time_t ) ICODE_ATTR; | ||
158 | void Dmc_recalc_irq( struct Nes_Dmc* this ) ICODE_ATTR; | ||
159 | void Dmc_fill_buffer( struct Nes_Dmc* this ) ICODE_ATTR; | ||
160 | void Dmc_reload_sample( struct Nes_Dmc* this ) ICODE_ATTR; | ||
161 | void Dmc_reset( struct Nes_Dmc* this ) ICODE_ATTR; | ||
162 | |||
163 | int 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | void 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 | |||
28 | void 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 | |||
45 | void 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 | |||
52 | void run_square( struct Nes_Vrc6_Apu* this, struct Vrc6_Osc* osc, blip_time_t end_time ); | ||
53 | void run_saw( struct Nes_Vrc6_Apu* this, blip_time_t end_time ); | ||
54 | void 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 | |||
63 | void 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 | |||
72 | void 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 | |||
81 | void 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 | |||
135 | void 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 | |||
10 | enum { vrc6_osc_count = 3 }; | ||
11 | enum { vrc6_reg_count = 3 }; | ||
12 | enum { vrc6_base_addr = 0x9000 }; | ||
13 | enum { vrc6_addr_step = 0x1000 }; | ||
14 | |||
15 | struct 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 | |||
25 | static inline int Vrc6_osc_period( struct Vrc6_Osc* this ) | ||
26 | { | ||
27 | return (this->regs [2] & 0x0F) * 0x100 + this->regs [1] + 1; | ||
28 | } | ||
29 | |||
30 | struct 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 | ||
39 | void Vrc6_init( struct Nes_Vrc6_Apu* this ); | ||
40 | void Vrc6_reset( struct Nes_Vrc6_Apu* this ); | ||
41 | void Vrc6_output( struct Nes_Vrc6_Apu* this, struct Blip_Buffer* ); | ||
42 | void 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 | ||
47 | void Vrc6_write_osc( struct Nes_Vrc6_Apu* this, blip_time_t, int osc, int reg, int data ) ICODE_ATTR; | ||
48 | |||
49 | static 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 | |||
55 | static 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 | |||
5 | int const period = 36; // NES CPU clocks per FM clock | ||
6 | |||
7 | void 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 | |||
22 | void 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 | |||
32 | void 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 | |||
38 | void Vrc7_write_reg( struct Nes_Vrc7_Apu* this, int data ) | ||
39 | { | ||
40 | this->addr = data; | ||
41 | } | ||
42 | |||
43 | void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time ); | ||
44 | void 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 | |||
53 | void 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 | |||
65 | void 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 | |||
11 | enum { vrc7_osc_count = 6 }; | ||
12 | |||
13 | struct vrc7_osc_t { | ||
14 | struct Blip_Buffer* output; | ||
15 | int last_amp; | ||
16 | }; | ||
17 | |||
18 | struct 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 | ||
28 | void Vrc7_init( struct Nes_Vrc7_Apu* this ); | ||
29 | void Vrc7_reset( struct Nes_Vrc7_Apu* this ); | ||
30 | void Vrc7_set_rate( struct Nes_Vrc7_Apu* this, double r ); | ||
31 | void Vrc7_end_frame( struct Nes_Vrc7_Apu* this, blip_time_t ) ICODE_ATTR; | ||
32 | |||
33 | void Vrc7_write_reg( struct Nes_Vrc7_Apu* this, int reg ) ICODE_ATTR; | ||
34 | void Vrc7_write_data( struct Nes_Vrc7_Apu* this, blip_time_t, int data ) ICODE_ATTR; | ||
35 | |||
36 | void output_changed( struct Nes_Vrc7_Apu* this ); | ||
37 | static 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 | ||
50 | static 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 | ||
16 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
17 | General Public License as published by the Free Software Foundation; either | ||
18 | version 2.1 of the License, or (at your option) any later version. This | ||
19 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
20 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
21 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
22 | details. You should have received a copy of the GNU Lesser General Public | ||
23 | License along with this module; if not, write to the Free Software Foundation, | ||
24 | Inc., 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 | |||
32 | int 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 | |||
49 | void 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 \ | ||
106 | bool 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 | ||
9 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
10 | General Public License as published by the Free Software Foundation; either | ||
11 | version 2.1 of the License, or (at your option) any later version. This | ||
12 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
14 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
15 | details. You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this module; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
18 | |||
19 | #include "blargg_source.h" | ||
20 | |||
21 | const char gme_wrong_file_type [] ICONST_ATTR = "Wrong file type for this emulator"; | ||
22 | long const clock_divisor = 12; | ||
23 | |||
24 | int const stereo = 2; // number of channels for stereo | ||
25 | int const silence_max = 6; // seconds | ||
26 | int const silence_threshold = 0x10; | ||
27 | long const fade_block_size = 512; | ||
28 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
29 | |||
30 | // number of frames until play interrupts init | ||
31 | int const initial_play_delay = 7; // KikiKaikai needed this to work | ||
32 | int const rom_addr = 0x8000; | ||
33 | |||
34 | void 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 | |||
48 | static int pcm_read( void* emu, addr_t addr ) | ||
49 | { | ||
50 | return *Cpu_get_code( &((struct Nsf_Emu*) emu)->cpu, addr ); | ||
51 | } | ||
52 | |||
53 | void 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 | |||
85 | blargg_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 | ||
171 | bool 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 | ||
177 | static bool pal_only( struct header_t* this ) | ||
178 | { | ||
179 | return (this->speed_flags & 3) == 1; | ||
180 | } | ||
181 | |||
182 | static double clock_rate( struct header_t* this ) | ||
183 | { | ||
184 | return pal_only( this ) ? 1662607.125 : 1789772.727272727; | ||
185 | } | ||
186 | |||
187 | int 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. | ||
215 | addr_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 | |||
223 | static 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 | |||
230 | blargg_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 | |||
253 | blargg_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 | |||
294 | void 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 | |||
300 | void Nsf_clear_playlist( struct Nsf_Emu* this ) | ||
301 | { | ||
302 | Nsf_disable_playlist( this, true ); | ||
303 | } | ||
304 | |||
305 | void 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 | |||
333 | void 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 | |||
373 | void 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 | |||
432 | blargg_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 | |||
445 | void 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 | |||
455 | void 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 | |||
477 | void 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 | |||
496 | inline 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. | ||
503 | void 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 | |||
510 | int 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 | |||
536 | int 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 | |||
552 | void 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 | |||
646 | void 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 | |||
666 | void fill_buf( struct Nsf_Emu* this ); | ||
667 | blargg_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 | |||
750 | void 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 | |||
804 | void 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 | |||
810 | void 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 | |||
836 | blargg_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 | |||
843 | long 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 | |||
850 | blargg_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 | |||
858 | blargg_err_t skip_( struct Nsf_Emu* this, long count ) ICODE_ATTR; | ||
859 | blargg_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 | |||
889 | blargg_err_t play_( struct Nsf_Emu* this, long count, sample_t* out ) ICODE_ATTR; | ||
890 | blargg_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 | |||
921 | void 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 ) | ||
928 | static 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 | |||
935 | void 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 | |||
959 | void emu_play( struct Nsf_Emu* this, long count, sample_t* out ) ICODE_ATTR; | ||
960 | void 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 | ||
975 | static 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 | ||
986 | void 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 | |||
1003 | blargg_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 | |||
1072 | blargg_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 | |||
1097 | blargg_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 | |||
23 | typedef short sample_t; | ||
24 | |||
25 | // Sound chip flags | ||
26 | enum { | ||
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 | |||
35 | enum { fds_banks = 2 }; | ||
36 | enum { bank_count = fds_banks + 8 }; | ||
37 | |||
38 | enum { rom_begin = 0x8000 }; | ||
39 | enum { bank_select_addr = 0x5FF8 }; | ||
40 | enum { mem_size = 0x10000 }; | ||
41 | |||
42 | // cpu sits here when waiting for next call to play routine | ||
43 | enum { idle_addr = 0x5FF6 }; | ||
44 | enum { banks_addr = idle_addr }; | ||
45 | enum { badop_addr = bank_select_addr }; | ||
46 | |||
47 | enum { low_ram_size = 0x800 }; | ||
48 | enum { sram_size = 0x2000 }; | ||
49 | enum { fdsram_size = 0x6000 }; | ||
50 | enum { fdsram_offset = 0x2000 + page_size + 8 }; | ||
51 | enum { sram_addr = 0x6000 }; | ||
52 | enum { unmapped_size= page_size + 8 }; | ||
53 | |||
54 | enum { buf_size = 2048 }; | ||
55 | |||
56 | // NSF file header | ||
57 | enum { header_size = 0x80 }; | ||
58 | struct 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 | |||
78 | struct 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 | |||
153 | void Nsf_init( struct Nsf_Emu* this ); | ||
154 | blargg_err_t Nsf_load( struct Nsf_Emu* this, void* data, long size ); | ||
155 | blargg_err_t Nsf_post_load( struct Nsf_Emu* this ); | ||
156 | |||
157 | // Set output sample rate. Must be called only once before loading file. | ||
158 | blargg_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. | ||
161 | blargg_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. | ||
165 | blargg_err_t Nsf_play( struct Nsf_Emu* this, long count, sample_t* buf ); | ||
166 | |||
167 | void Nsf_clear_playlist( struct Nsf_Emu* this ); | ||
168 | void 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 | ||
173 | long Track_tell( struct Nsf_Emu* this ); | ||
174 | |||
175 | // Seek to new time in track. Seeking backwards or far forward can take a while. | ||
176 | blargg_err_t Track_seek( struct Nsf_Emu* this, long msec ); | ||
177 | |||
178 | // Skip n samples | ||
179 | blargg_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. | ||
183 | void Track_set_fade( struct Nsf_Emu* this, long start_msec, long length_msec ); | ||
184 | |||
185 | // Get track length in milliseconds | ||
186 | long 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. | ||
192 | void Sound_set_tempo( struct Nsf_Emu* this, double t ); | ||
193 | |||
194 | // Mute/unmute voice i, where voice 0 is first voice | ||
195 | void 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. | ||
199 | void 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(). | ||
203 | static 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 | |||
211 | blargg_err_t run_clocks( struct Nsf_Emu* this, blip_time_t* duration, int ); | ||
212 | |||
213 | void map_memory( struct Nsf_Emu* this ) ICODE_ATTR; | ||
214 | void write_bank( struct Nsf_Emu* this, int index, int data ) ICODE_ATTR; | ||
215 | int cpu_read( struct Nsf_Emu* this, addr_t ) ICODE_ATTR; | ||
216 | void cpu_write( struct Nsf_Emu* this, addr_t, int ) ICODE_ATTR; | ||
217 | void push_byte( struct Nsf_Emu* this, int ) ICODE_ATTR; | ||
218 | addr_t get_addr( byte const [] ) ICODE_ATTR; | ||
219 | bool 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 | ||
222 | static inline void set_play_period( struct Nsf_Emu* this, int p ) { this->play_period = p; } | ||
223 | |||
224 | // Time play routine will next be called | ||
225 | static 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. | ||
228 | void 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). | ||
232 | bool 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) | ||
235 | int read_mem( struct Nsf_Emu* this, addr_t ) ICODE_ATTR; | ||
236 | void write_mem( struct Nsf_Emu* this, addr_t, int ) ICODE_ATTR; | ||
237 | |||
238 | // Address of play routine | ||
239 | static 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). | ||
243 | void 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. | ||
247 | int read_code( struct Nsf_Emu* this, addr_t addr ) ICODE_ATTR; | ||
248 | |||
249 | static inline byte* fdsram( struct Nsf_Emu* this ) { return &this->high_ram [fdsram_offset]; } | ||
250 | static inline byte* sram( struct Nsf_Emu* this ) { return this->high_ram; } | ||
251 | static inline byte* unmapped_code( struct Nsf_Emu* this ) { return &this->high_ram [sram_size]; } | ||
252 | |||
253 | #ifndef NSF_EMU_APU_ONLY | ||
254 | static inline int fds_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & fds_flag; } | ||
255 | static inline int vrc6_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & vrc6_flag; } | ||
256 | static inline int vrc7_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & vrc7_flag; } | ||
257 | static inline int mmc5_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & mmc5_flag; } | ||
258 | static inline int namco_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & namco_flag; } | ||
259 | static 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 | ||
9 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
10 | General Public License as published by the Free Software Foundation; either | ||
11 | version 2.1 of the License, or (at your option) any later version. This | ||
12 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
14 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
15 | details. You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this module; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
18 | |||
19 | #include "blargg_source.h" | ||
20 | |||
21 | void Info_init( struct Nsfe_Info* this ) | ||
22 | { | ||
23 | this->playlist_disabled = false; | ||
24 | } | ||
25 | |||
26 | void 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... ? | ||
36 | void 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 | |||
44 | int 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 | |||
51 | const char eof_error [] = "Unexpected end of file"; | ||
52 | |||
53 | // Read n bytes from memory buffer | ||
54 | static 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 | |||
63 | static 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 | ||
74 | static 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 | |||
98 | struct 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 | |||
110 | blargg_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 | |||
251 | long 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 | |||
9 | struct Nsf_Emu; | ||
10 | |||
11 | // Allows reading info from NSFE file without creating emulator | ||
12 | struct 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 | |||
23 | void Info_init( struct Nsfe_Info* this ); | ||
24 | blargg_err_t Info_load( struct Nsfe_Info* this, void *data, long size, struct Nsf_Emu* ); | ||
25 | void Info_disable_playlist( struct Nsfe_Info* this, bool b ); | ||
26 | int Info_remap_track( struct Nsfe_Info* this, int i ); | ||
27 | void 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 | |||
7 | blargg_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 | |||
41 | void 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 | |||
55 | void 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 | |||
76 | static void run_until( struct Opl_Apu* this, blip_time_t end_time ); | ||
77 | void 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 | |||
95 | int 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 | |||
112 | void 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 | |||
121 | static 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 | |||
11 | enum opl_type_t { type_opll = 0x10, type_msxmusic = 0x11, type_smsfmunit = 0x12, | ||
12 | type_vrc7 = 0x13, type_msxaudio = 0x21 }; | ||
13 | |||
14 | enum { opl_osc_count = 1 }; | ||
15 | |||
16 | struct 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 | |||
38 | blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type ); | ||
39 | |||
40 | void Opl_reset( struct Opl_Apu* this ); | ||
41 | static inline void Opl_volume( struct Opl_Apu* this, double v ) { Synth_volume( &this->synth, 1.0 / (4096 * 6) * v ); } | ||
42 | |||
43 | static 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 | |||
52 | static inline void Opl_set_output( struct Opl_Apu* this, struct Blip_Buffer* buf ) { Opl_osc_output( this, 0, buf ); } | ||
53 | void Opl_end_frame( struct Opl_Apu* this, blip_time_t ) ICODE_ATTR; | ||
54 | |||
55 | static inline void Opl_write_addr( struct Opl_Apu* this, int data ) { this->addr = data; } | ||
56 | void Opl_write_data( struct Opl_Apu* this, blip_time_t, int data ) ICODE_ATTR; | ||
57 | |||
58 | int Opl_read( struct Opl_Apu* this, blip_time_t, int port ) ICODE_ATTR; | ||
59 | |||
60 | static 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 | |||
7 | static 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 | |||
57 | static 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 | |||
107 | static 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 | |||
134 | static 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 | |||
161 | static 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 | |||
188 | static 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 | |||
215 | static 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 | ||
9 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
10 | General Public License as published by the Free Software Foundation; either | ||
11 | version 2.1 of the License, or (at your option) any later version. This | ||
12 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
14 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
15 | details. You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this module; if not, write to the Free Software Foundation, | ||
17 | Inc., 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. | ||
22 | unsigned const resampler_extra = 34; | ||
23 | |||
24 | enum { shift = 14 }; | ||
25 | int const unit = 1 << shift; | ||
26 | |||
27 | blargg_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 | |||
37 | blargg_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 | |||
49 | void 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 | |||
60 | void 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 | |||
93 | void 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 | |||
136 | void 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 | |||
174 | dsample_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 | |||
212 | inline 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 | |||
226 | int 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 | |||
238 | void 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 | |||
290 | void 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 | |||
10 | typedef short dsample_t; | ||
11 | |||
12 | enum { stereo = 2 }; | ||
13 | enum { max_buf_size = 3960 }; | ||
14 | enum { max_resampler_size = 5942 }; | ||
15 | enum { write_offset = 8 * stereo }; | ||
16 | enum { gain_bits = 14 }; | ||
17 | |||
18 | struct 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 | |||
40 | static inline void Resampler_init( struct Resampler* this ) | ||
41 | { | ||
42 | this->pos = 0; | ||
43 | this->write_pos = 0; | ||
44 | this->rate_ = 0; | ||
45 | } | ||
46 | |||
47 | blargg_err_t Resampler_reset( struct Resampler* this, int max_pairs ); | ||
48 | void Resampler_resize( struct Resampler* this, int pairs_per_frame ); | ||
49 | |||
50 | void Resampler_play( struct Resampler* this, long count, dsample_t* out, struct Stereo_Buffer* ) ICODE_ATTR; | ||
51 | |||
52 | static 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 | |||
58 | blargg_err_t Resampler_setup( struct Resampler* this, double oversample, double rolloff, double gain ); | ||
59 | |||
60 | static 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 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 | |||
21 | blargg_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 | |||
46 | void 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 | |||
14 | extern const char gme_wrong_file_type []; // declared in gme.h | ||
15 | |||
16 | enum { pad_extra = 8 }; | ||
17 | enum { max_bank_size = 0x4000 }; | ||
18 | enum { max_pad_size = max_bank_size + pad_extra }; | ||
19 | enum { max_rom_size = 2 * max_pad_size }; | ||
20 | |||
21 | struct 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 | ||
38 | static 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'. | ||
47 | blargg_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 | ||
50 | void Rom_set_addr( struct Rom_Data* this, long addr ); | ||
51 | |||
52 | // Mask address to nearest power of two greater than size() | ||
53 | static 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. | ||
62 | static 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 | ||
9 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
10 | General Public License as published by the Free Software Foundation; either | ||
11 | version 2.1 of the License, or (at your option) any later version. This | ||
12 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
14 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
15 | details. You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this module; if not, write to the Free Software Foundation, | ||
17 | Inc., 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 \ | ||
28 | bool 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | int const osc_count = sms_osc_count + fm_apu_osc_count; | ||
19 | |||
20 | int const stereo = 2; // number of channels for stereo | ||
21 | int const silence_max = 6; // seconds | ||
22 | int const silence_threshold = 0x10; | ||
23 | long const fade_block_size = 512; | ||
24 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
25 | |||
26 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; | ||
27 | |||
28 | void 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 | |||
43 | void 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 | |||
72 | blargg_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 | |||
113 | void 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 | |||
121 | blargg_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 | |||
166 | void 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 | |||
203 | void 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 | |||
210 | void 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 | |||
216 | void 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 | |||
252 | blargg_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 | |||
265 | void 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 | |||
275 | void 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 | |||
297 | void 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 | |||
309 | void fill_buf( struct Sgc_Emu* this ) ICODE_ATTR; | ||
310 | blargg_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 | |||
411 | blargg_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 | |||
418 | long 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 | |||
425 | blargg_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 | |||
433 | blargg_err_t skip_( struct Sgc_Emu* this, long count ) ICODE_ATTR; | ||
434 | blargg_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 | |||
466 | blargg_err_t play_( struct Sgc_Emu* this, long count, sample_t* out ) ICODE_ATTR; | ||
467 | blargg_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 | |||
498 | void 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 ) | ||
505 | static 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 | |||
512 | void 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 | |||
536 | void 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 | ||
550 | static 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 | ||
561 | void 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 | |||
578 | blargg_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 | |||
650 | blargg_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 | |||
16 | typedef short sample_t; | ||
17 | typedef struct Z80_Cpu Sgc_Cpu; | ||
18 | |||
19 | enum { buf_size = 2048 }; | ||
20 | |||
21 | // SGC file header | ||
22 | enum { header_size = 0xA0 }; | ||
23 | struct 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 | ||
48 | static inline bool valid_tag( struct header_t* h ) | ||
49 | { | ||
50 | return 0 == memcmp( h->tag, "SGC\x1A", 4 ); | ||
51 | } | ||
52 | |||
53 | static inline int effect_count( struct header_t* h ) { return h->last_effect ? h->last_effect - h->first_effect + 1 : 0; } | ||
54 | |||
55 | |||
56 | struct 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 | |||
119 | void Sgc_init( struct Sgc_Emu* this ); | ||
120 | |||
121 | blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ); | ||
122 | |||
123 | static inline int clock_rate( struct Sgc_Emu* this ) { return this->header.rate ? 3546893 : 3579545; } | ||
124 | |||
125 | // 0x2000 bytes | ||
126 | static 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. | ||
129 | blargg_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. | ||
132 | blargg_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. | ||
136 | blargg_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 | ||
141 | long Track_tell( struct Sgc_Emu* this ); | ||
142 | |||
143 | // Seek to new time in track. Seeking backwards or far forward can take a while. | ||
144 | blargg_err_t Track_seek( struct Sgc_Emu* this, long msec ); | ||
145 | |||
146 | // Skip n samples | ||
147 | blargg_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. | ||
151 | void Track_set_fade( struct Sgc_Emu* this, long start_msec, long length_msec ); | ||
152 | |||
153 | // Get track length in milliseconds | ||
154 | static 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. | ||
169 | void Sound_set_tempo( struct Sgc_Emu* this, double t ); | ||
170 | |||
171 | // Mute/unmute voice i, where voice 0 is first voice | ||
172 | void 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. | ||
176 | void 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(). | ||
180 | static 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 | ||
187 | static 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 | |||
194 | bool run_cpu( struct Sgc_Emu* this, cpu_time_t end_time ) ICODE_ATTR; | ||
195 | void cpu_out( struct Sgc_Emu* this, cpu_time_t time, addr_t addr, int data ) ICODE_ATTR; | ||
196 | void cpu_write( struct Sgc_Emu* this, addr_t addr, int data ) ICODE_ATTR; | ||
197 | void 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | int const noise_osc = 3; | ||
19 | |||
20 | void 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 | |||
26 | inline 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 | |||
32 | void 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 | |||
63 | static 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 | |||
74 | void 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 | |||
106 | void 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 | |||
123 | static 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 | |||
239 | void 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 | |||
269 | void 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 | |||
303 | void 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 | ||
11 | enum { sms_osc_count = 4 }; // 0 <= chan < osc_count | ||
12 | |||
13 | struct 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 | |||
25 | struct 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 | |||
39 | void 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. | ||
43 | void 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 | ||
46 | void 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 | ||
49 | void 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. | ||
53 | void 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 | ||
58 | void Sms_apu_reset( struct Sms_Apu* this, unsigned noise_feedback, int noise_width ); | ||
59 | |||
60 | // Sets overall volume, where 1.0 is normal | ||
61 | void 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 | |||
5 | void Fm_apu_create( struct Sms_Fm_Apu* this ) | ||
6 | { | ||
7 | Synth_init( &this->synth ); | ||
8 | Ym2413_init( &this->apu ); | ||
9 | } | ||
10 | |||
11 | blargg_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 | |||
22 | void 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 | |||
31 | void fm_run_until( struct Sms_Fm_Apu* this, blip_time_t end_time ) ICODE_ATTR; | ||
32 | void 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 | |||
40 | void 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 | |||
72 | void 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 | |||
8 | enum { fm_apu_osc_count = 1 }; | ||
9 | |||
10 | struct 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 | |||
24 | void Fm_apu_create( struct Sms_Fm_Apu* this ); | ||
25 | |||
26 | static inline bool Fm_apu_supported( void ) { return Ym2413_supported(); } | ||
27 | blargg_err_t Fm_apu_init( struct Sms_Fm_Apu* this, double clock_rate, double sample_rate ); | ||
28 | |||
29 | static inline void Fm_apu_set_output( struct Sms_Fm_Apu* this, struct Blip_Buffer* b ) | ||
30 | { | ||
31 | this->output_ = b; | ||
32 | } | ||
33 | |||
34 | static inline void Fm_apu_volume( struct Sms_Fm_Apu* this, double v ) { Synth_volume( &this->synth, 0.4 / 4096 * v ); } | ||
35 | |||
36 | void Fm_apu_reset( struct Sms_Fm_Apu* this ); | ||
37 | |||
38 | static inline void Fm_apu_write_addr( struct Sms_Fm_Apu* this, int data ) { this->addr = data; } | ||
39 | void Fm_apu_write_data( struct Sms_Fm_Apu* this, blip_time_t, int data ) ICODE_ATTR; | ||
40 | |||
41 | void 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 | ||
10 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
11 | General Public License as published by the Free Software Foundation; either | ||
12 | version 2.1 of the License, or (at your option) any later version. This | ||
13 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
15 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
16 | details. You should have received a copy of the GNU Lesser General Public | ||
17 | License along with this module; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
19 | |||
20 | #include "blargg_source.h" | ||
21 | |||
22 | const char* const gme_wrong_file_type = "Wrong file type for this emulator"; | ||
23 | |||
24 | double const fm_gain = 3.0; // FM emulators are internally quieter to avoid 16-bit overflow | ||
25 | double const rolloff = 0.990; | ||
26 | double const oversample_factor = 1.5; | ||
27 | |||
28 | int const silence_max = 6; // seconds | ||
29 | int const silence_threshold = 0x10; | ||
30 | long const fade_block_size = 512; | ||
31 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
32 | |||
33 | // VGM commands (Spec v1.50) | ||
34 | enum { | ||
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 | |||
56 | void 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 | |||
69 | int play_frame( struct Vgm_Emu* this, blip_time_t blip_time, int sample_count, sample_t* buf ); | ||
70 | static 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 | |||
75 | void 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 | |||
116 | static 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 | |||
127 | static 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 | |||
141 | static 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 | |||
146 | static 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 | |||
154 | int const gd3_header_size = 12; | ||
155 | |||
156 | static 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 | |||
168 | byte 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 | |||
188 | static 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 | |||
208 | blargg_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 | |||
221 | static 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 | |||
228 | void 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 | |||
237 | blargg_err_t setup_fm( struct Vgm_Emu* this ); | ||
238 | blargg_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 | |||
312 | void update_fm_rates( struct Vgm_Emu* this, int* ym2413_rate, int* ym2612_rate ); | ||
313 | blargg_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 | |||
343 | blargg_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 | |||
367 | blip_time_t run( struct Vgm_Emu* this, vgm_time_t end_time ); | ||
368 | blargg_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 | |||
377 | blargg_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 | |||
410 | inline 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 | |||
421 | inline 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 | |||
426 | inline 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 | |||
431 | void 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 | |||
448 | blip_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 | |||
586 | int 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 | ||
619 | void 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 | |||
666 | blargg_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 | |||
679 | void 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 | |||
689 | void 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 | |||
736 | void 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 | |||
760 | void fill_buf( struct Vgm_Emu *this ); | ||
761 | blargg_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 | |||
824 | blargg_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 | |||
831 | long 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 | |||
838 | blargg_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 | |||
846 | blargg_err_t skip_( struct Vgm_Emu* this, long count ); | ||
847 | blargg_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 | |||
875 | blargg_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 | |||
906 | void 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 ) | ||
913 | static 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 | |||
920 | void 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 | |||
944 | void 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 | ||
956 | static 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 | ||
967 | void 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 | |||
984 | blargg_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 | |||
15 | typedef short sample_t; | ||
16 | typedef int vgm_time_t; | ||
17 | typedef int fm_time_t; | ||
18 | |||
19 | enum { fm_time_bits = 12 }; | ||
20 | enum { blip_time_bits = 12 }; | ||
21 | enum { buf_size = 2048 }; | ||
22 | |||
23 | // VGM header format | ||
24 | enum { header_size = 0x40 }; | ||
25 | struct 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 | |||
46 | enum { gme_max_field = 63 }; | ||
47 | struct 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. | ||
65 | struct 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 | |||
134 | void 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. | ||
138 | static inline void Vgm_disable_oversampling( struct Vgm_Emu* this, bool disable ) { this->disable_oversampling = disable; } | ||
139 | |||
140 | // Header for currently loaded file | ||
141 | static 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) | ||
144 | blargg_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. | ||
148 | static 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. | ||
151 | blargg_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. | ||
154 | blargg_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. | ||
158 | blargg_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 | ||
163 | long Track_tell( struct Vgm_Emu* this ); | ||
164 | |||
165 | // Seek to new time in track. Seeking backwards or far forward can take a while. | ||
166 | blargg_err_t Track_seek( struct Vgm_Emu* this, long msec ); | ||
167 | |||
168 | // Skip n samples | ||
169 | blargg_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. | ||
173 | void Track_set_fade( struct Vgm_Emu* this, long start_msec, long length_msec ); | ||
174 | |||
175 | // Get track length in milliseconds | ||
176 | static 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. | ||
193 | void Sound_set_tempo( struct Vgm_Emu* this, double t ); | ||
194 | |||
195 | // Mute/unmute voice i, where voice 0 is first voice | ||
196 | void 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. | ||
200 | void 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(). | ||
204 | static 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 */ | ||
2 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
3 | 0x33,0x01,0x09,0x0e,0x94,0x90,0x40,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
4 | 0x13,0x41,0x0f,0x0d,0xce,0xd3,0x43,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
5 | 0x01,0x12,0x1b,0x06,0xff,0xd2,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
6 | 0x61,0x61,0x1b,0x07,0xaf,0x63,0x20,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
7 | 0x22,0x21,0x1e,0x06,0xf0,0x76,0x08,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
8 | 0x66,0x21,0x15,0x00,0x93,0x94,0x20,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
9 | 0x21,0x61,0x1c,0x07,0x82,0x81,0x10,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
10 | 0x23,0x21,0x20,0x1f,0xc0,0x71,0x07,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
11 | 0x25,0x31,0x26,0x05,0x64,0x41,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
12 | 0x17,0x21,0x28,0x07,0xff,0x83,0x02,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
13 | 0x97,0x81,0x25,0x07,0xcf,0xc8,0x02,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
14 | 0x21,0x21,0x54,0x0f,0x80,0x7f,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
15 | 0x01,0x01,0x56,0x03,0xd3,0xb2,0x43,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
16 | 0x31,0x21,0x0c,0x03,0x82,0xc0,0x40,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
17 | 0x21,0x01,0x0c,0x03,0xd4,0xd3,0x40,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
18 | 0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
19 | 0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
20 | 0x25,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 | |||
5 | void Ym2413_init( struct Ym2413_Emu* this ) | ||
6 | { | ||
7 | this->last_time = disabled_time; this->out = 0; | ||
8 | } | ||
9 | |||
10 | int 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 | |||
19 | void Ym2413_reset( struct Ym2413_Emu* this ) | ||
20 | { | ||
21 | OPLL_reset( &this->opll ); | ||
22 | OPLL_setMask( &this->opll, 0 ); | ||
23 | } | ||
24 | |||
25 | void 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 | |||
31 | void Ym2413_mute_voices( struct Ym2413_Emu* this, int mask ) | ||
32 | { | ||
33 | OPLL_setMask( &this->opll, mask ); | ||
34 | } | ||
35 | |||
36 | void 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 | |||
10 | enum { out_chan_count = 2 }; // stereo | ||
11 | enum { channel_count = 14 }; | ||
12 | enum { disabled_time = -1 }; | ||
13 | |||
14 | struct Ym2413_Emu { | ||
15 | OPLL opll; | ||
16 | |||
17 | // Impl | ||
18 | int last_time; | ||
19 | short* out; | ||
20 | }; | ||
21 | |||
22 | void Ym2413_init( struct Ym2413_Emu* this ); | ||
23 | |||
24 | static 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. | ||
28 | int Ym2413_set_rate( struct Ym2413_Emu* this, double sample_rate, double clock_rate ); | ||
29 | |||
30 | // Resets to power-up state | ||
31 | void Ym2413_reset( struct Ym2413_Emu* this ); | ||
32 | |||
33 | // Mutes voice n if bit n (1 << n) of mask is set | ||
34 | void Ym2413_mute_voices( struct Ym2413_Emu* this, int mask ); | ||
35 | |||
36 | // Writes data to addr | ||
37 | void Ym2413_write( struct Ym2413_Emu* this, int addr, int data ) ICODE_ATTR; | ||
38 | |||
39 | // Runs and writes pair_count*2 samples to output | ||
40 | void Ym2413_run( struct Ym2413_Emu* this, int pair_count, short* out ) ICODE_ATTR; | ||
41 | |||
42 | static inline void Ym2413_enable( struct Ym2413_Emu* this, bool b ) { this->last_time = b ? 0 : disabled_time; } | ||
43 | static inline bool Ym2413_enabled( struct Ym2413_Emu* this ) { return this->last_time != disabled_time; } | ||
44 | static inline void Ym2413_begin_frame( struct Ym2413_Emu* this, short* buf ) { this->out = buf; this->last_time = 0; } | ||
45 | |||
46 | static 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 | ||
16 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
17 | General Public License as published by the Free Software Foundation; either | ||
18 | version 2.1 of the License, or (at your option) any later version. This | ||
19 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
20 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
21 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
22 | details. You should have received a copy of the GNU Lesser General Public | ||
23 | License along with this module; if not, write to the Free Software Foundation, | ||
24 | Inc., 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 | |||
44 | const int output_bits = 14; | ||
45 | |||
46 | static 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 | |||
65 | static 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 | |||
73 | static const unsigned char LFO_AMS_TAB [4] ICONST_ATTR = | ||
74 | { | ||
75 | 31, 4, 1, 0 | ||
76 | }; | ||
77 | |||
78 | static 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 | |||
86 | int in0, in1, in2, in3; // current phase calculation | ||
87 | // int en0, en1, en2, en3; // current enveloppe calculation | ||
88 | |||
89 | inline 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 | |||
101 | inline void YM2612_Special_Update(void) { } | ||
102 | |||
103 | void 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 | |||
126 | void 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 | |||
144 | int 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 | |||
248 | int 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 | |||
351 | int 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) | ||
460 | double fabs(double x) | ||
461 | { | ||
462 | if (x < 0.0) return -x; | ||
463 | return x; | ||
464 | } | ||
465 | |||
466 | double 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 | |||
482 | void impl_reset( struct Ym2612_Impl* impl ); | ||
483 | void 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 | |||
685 | const 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 | |||
698 | inline 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 | |||
718 | inline 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 | |||
733 | void 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 | |||
798 | void Ym2612_reset( struct Ym2612_Emu* this ) | ||
799 | { | ||
800 | impl_reset( &this->impl ); | ||
801 | } | ||
802 | |||
803 | void Ym2612_write0( struct Ym2612_Emu* this, int addr, int data ) | ||
804 | { | ||
805 | write0( &this->impl, addr, data ); | ||
806 | } | ||
807 | |||
808 | void Ym2612_write1( struct Ym2612_Emu* this, int addr, int data ) | ||
809 | { | ||
810 | write1( &this->impl, addr, data ); | ||
811 | } | ||
812 | |||
813 | void Ym2612_mute_voices( struct Ym2612_Emu* this, int mask ) { this->impl.mute_mask = mask; } | ||
814 | |||
815 | static 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 | |||
878 | static 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 | |||
886 | typedef void (*ym2612_update_chan_t)( struct tables_t*, struct channel_*, short*, int ); | ||
887 | |||
888 | #define GET_CURRENT_PHASE \ | ||
889 | int in0 = ch->SLOT[S0].Fcnt; \ | ||
890 | int in1 = ch->SLOT[S1].Fcnt; \ | ||
891 | int in2 = ch->SLOT[S2].Fcnt; \ | ||
892 | int in3 = ch->SLOT[S3].Fcnt; \ | ||
893 | |||
894 | #define GET_CURRENT_LFO \ | ||
895 | int YM2612_LFOinc = g->LFOinc; \ | ||
896 | int 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 \ | ||
904 | int const env_LFO = g->LFO_ENV_TAB [YM2612_LFOcnt >> LFO_LBITS & LFO_MASK]; \ | ||
905 | short const* const ENV_TAB = g->ENV_TAB; \ | ||
906 | CALC_EN( 0 ) \ | ||
907 | CALC_EN( 1 ) \ | ||
908 | CALC_EN( 2 ) \ | ||
909 | CALC_EN( 3 ) \ | ||
910 | int const* const TL_TAB = g->TL_TAB; | ||
911 | |||
912 | #define DO_FEEDBACK \ | ||
913 | int 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 \ | ||
923 | CH_OUTd >>= MAX_OUT_BITS - output_bits + 2; \ | ||
924 | |||
925 | #define UPDATE_PHASE_CYCLE \ | ||
926 | unsigned freq_LFO = ((g->LFO_FREQ_TAB [YM2612_LFOcnt >> LFO_LBITS & LFO_MASK] * \ | ||
927 | ch->FMS) >> (LFO_HBITS - 1 + 1)) + (1 << (LFO_FMS_LBITS - 1)); \ | ||
928 | YM2612_LFOcnt += YM2612_LFOinc; \ | ||
929 | in0 += (ch->SLOT [S0].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); \ | ||
930 | in1 += (ch->SLOT [S1].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); \ | ||
931 | in2 += (ch->SLOT [S2].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); \ | ||
932 | in3 += (ch->SLOT [S3].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); | ||
933 | |||
934 | #define UPDATE_ENV \ | ||
935 | int t0 = buf [0] + (CH_OUTd & ch->LEFT); \ | ||
936 | int t1 = buf [1] + (CH_OUTd & ch->RIGHT); \ | ||
937 | update_envelope( &ch->SLOT [0] ); \ | ||
938 | update_envelope( &ch->SLOT [1] ); \ | ||
939 | update_envelope( &ch->SLOT [2] ); \ | ||
940 | update_envelope( &ch->SLOT [3] ); | ||
941 | |||
942 | #define DO_OUTPUT_0 \ | ||
943 | ch->S0_OUT [0] = CH_S0_OUT_0; \ | ||
944 | buf [0] = t0; \ | ||
945 | buf [1] = t1; \ | ||
946 | buf += 2; \ | ||
947 | |||
948 | #define DO_OUTPUT_1 \ | ||
949 | ch->S0_OUT [1] = CH_S0_OUT_1; | ||
950 | |||
951 | #define UPDATE_PHASE \ | ||
952 | ch->SLOT [S0].Fcnt = in0; \ | ||
953 | ch->SLOT [S1].Fcnt = in1; \ | ||
954 | ch->SLOT [S2].Fcnt = in2; \ | ||
955 | ch->SLOT [S3].Fcnt = in3; | ||
956 | |||
957 | void 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 | |||
990 | void 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 | |||
1022 | void 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 | |||
1054 | void 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 | |||
1087 | void 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 | |||
1121 | void 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 | |||
1157 | void 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 | |||
1192 | void 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 | |||
1228 | static 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 | |||
1241 | void 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 | |||
1287 | void 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 | |||
1359 | void 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 | |||
9 | enum { ym2612_out_chan_count = 2 }; // stereo | ||
10 | enum { ym2612_channel_count = 6 }; | ||
11 | enum { ym2612_disabled_time = -1 }; | ||
12 | |||
13 | struct 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 | |||
57 | struct 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 | |||
73 | struct 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 | |||
153 | struct 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 | |||
175 | struct Ym2612_Impl | ||
176 | { | ||
177 | struct state_t YM2612; | ||
178 | int mute_mask; | ||
179 | struct tables_t g; | ||
180 | }; | ||
181 | |||
182 | void impl_reset( struct Ym2612_Impl* impl ); | ||
183 | |||
184 | struct 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 | |||
194 | static 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 | ||
202 | const char* Ym2612_set_rate( struct Ym2612_Emu* this_, double sample_rate, double clock_rate ); | ||
203 | |||
204 | // Resets to power-up state | ||
205 | void Ym2612_reset( struct Ym2612_Emu* this_ ); | ||
206 | |||
207 | // Mutes voice n if bit n (1 << n) of mask is set | ||
208 | void Ym2612_mute_voices( struct Ym2612_Emu* this_, int mask ); | ||
209 | |||
210 | // Writes addr to register 0 then data to register 1 | ||
211 | void Ym2612_write0( struct Ym2612_Emu* this_, int addr, int data ) ICODE_ATTR; | ||
212 | |||
213 | // Writes addr to register 2 then data to register 3 | ||
214 | void 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 | ||
217 | void Ym2612_run( struct Ym2612_Emu* this_, int pair_count, short* out ) ICODE_ATTR; | ||
218 | |||
219 | static inline void Ym2612_enable( struct Ym2612_Emu* this_, bool b ) { this_->last_time = b ? 0 : ym2612_disabled_time; } | ||
220 | static inline bool Ym2612_enabled( struct Ym2612_Emu* this_ ) { return this_->last_time != ym2612_disabled_time; } | ||
221 | static inline void Ym2612_begin_frame( struct Ym2612_Emu* this_, short* buf ) { this_->out = buf; this_->last_time = 0; } | ||
222 | |||
223 | static 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 */ | ||
80 | static 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 */ | ||
86 | static 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 | ||
92 | void 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 | |||
103 | UINT8 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) */ | ||
155 | static const UINT8 dram_rightshift[4] ICONST_ATTR ={3,0,0,0}; | ||
156 | |||
157 | /* DELTA-T ADPCM write register */ | ||
158 | void 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 | /* | ||
167 | START: | ||
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 | |||
173 | REC: | ||
174 | 0 = ADPCM synthesis (playback) | ||
175 | 1 = ADPCM analysis (record) | ||
176 | |||
177 | MEMDATA: | ||
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 | |||
182 | SPOFF: | ||
183 | controls output pin that should disable the speaker while ADPCM analysis | ||
184 | |||
185 | RESET and REPEAT only work with external memory. | ||
186 | |||
187 | |||
188 | some examples: | ||
189 | value: 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 | /* | ||
315 | some examples: | ||
316 | value: 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 | |||
413 | void 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 | ||
442 | void 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 | } | ||
458 | void 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 | |||
479 | static 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 | |||
561 | static 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) */ | ||
620 | void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT) | ||
621 | { | ||
622 | |||
623 | /* | ||
624 | some examples: | ||
625 | value: 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__ | ||
11 | typedef unsigned char UINT8; /* unsigned 8bit */ | ||
12 | typedef unsigned short UINT16; /* unsigned 16bit */ | ||
13 | typedef unsigned int UINT32; /* unsigned 32bit */ | ||
14 | typedef signed char INT8; /* signed 8bit */ | ||
15 | typedef signed short INT16; /* signed 16bit */ | ||
16 | typedef signed int INT32; /* signed 32bit */ | ||
17 | |||
18 | typedef 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 | |||
28 | typedef void (*STATUS_CHANGE_HANDLER)(void *chip, UINT8 status_bits); | ||
29 | |||
30 | |||
31 | /* DELTA-T (adpcm type B) struct */ | ||
32 | typedef 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 | |||
92 | UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT) ICODE_ATTR; | ||
93 | void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v) ICODE_ATTR; | ||
94 | void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode); | ||
95 | void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT) ICODE_ATTR; | ||
96 | |||
97 | /*void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs); | ||
98 | void 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 | |||
6 | static 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 | |||
312 | static 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 | |||
395 | static 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 | |||
477 | static 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 | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 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 | ||
19 | int const S80 = 0x80; | ||
20 | int const Z40 = 0x40; | ||
21 | int const F20 = 0x20; | ||
22 | int const H10 = 0x10; | ||
23 | int const F08 = 0x08; | ||
24 | int const V04 = 0x04; | ||
25 | int const P04 = 0x04; | ||
26 | int const N02 = 0x02; | ||
27 | int const C01 = 0x01; | ||
28 | |||
29 | void 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 | |||
47 | inline 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 | |||
58 | void 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 | |||
73 | void 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 | |||
10 | typedef int cpu_time_t; | ||
11 | typedef int addr_t; | ||
12 | |||
13 | enum { page_bits = 10 }; | ||
14 | enum { page_size = 1 << page_bits }; | ||
15 | enum { page_count = 0x10000 / page_size }; | ||
16 | |||
17 | // Can read this far past end of memory | ||
18 | enum { cpu_padding = 0x100 }; | ||
19 | |||
20 | // Can read this many bytes past end of a page | ||
21 | enum { 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 | |||
30 | struct pairs_t { uint16_t bc, de, hl, fa; }; | ||
31 | |||
32 | // Registers are not updated until run() returns | ||
33 | struct 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 | |||
53 | struct 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 | |||
60 | struct 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 | |||
70 | void Z80_init( struct Z80_Cpu* this ); | ||
71 | |||
72 | // Clears registers and maps all pages to unmapped | ||
73 | void 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. | ||
78 | void 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 | ||
81 | static inline cpu_time_t Z80_time( struct Z80_Cpu* this ) { return this->cpu_state->time + this->cpu_state->base; } | ||
82 | |||
83 | // Alter current time | ||
84 | static inline void Z80_set_time( struct Z80_Cpu* this, cpu_time_t t ) { this->cpu_state->time = t - this->cpu_state->base; } | ||
85 | static 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 | ||
94 | static 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 | |||
99 | static 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 | |||
104 | static 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 | |||
109 | static 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, | ||
11 | though they NEVER have side-effects, so multiple evaluation is OK. | ||
12 | - Output parameters might be a multiple-assignment expression like "a=x", | ||
13 | so they must NOT be parenthesized. | ||
14 | - Except where noted, time() and related functions will NOT work | ||
15 | correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and | ||
16 | CACHE_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 | ||
56 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
57 | General Public License as published by the Free Software Foundation; either | ||
58 | version 2.1 of the License, or (at your option) any later version. This | ||
59 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
60 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
61 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
62 | details. You should have received a copy of the GNU Lesser General Public | ||
63 | License along with this module; if not, write to the Free Software Foundation, | ||
64 | Inc., 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 | ||
73 | int const S80 = 0x80; | ||
74 | int const Z40 = 0x40; | ||
75 | int const F20 = 0x20; | ||
76 | int const H10 = 0x10; | ||
77 | int const F08 = 0x08; | ||
78 | int const V04 = 0x04; | ||
79 | int const P04 = 0x04; | ||
80 | int const N02 = 0x02; | ||
81 | int 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 | |||
152 | bool 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 | |||
182 | call_not_taken: | ||
183 | s_time -= 7; | ||
184 | jp_not_taken: | ||
185 | pc += 2; | ||
186 | loop: | ||
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 | ||
1677 | hit_idle_addr: | ||
1678 | s_time -= 11; | ||
1679 | goto out_of_time; | ||
1680 | #endif | ||
1681 | halt: | ||
1682 | s_time &= 3; // increment by multiple of 4 | ||
1683 | out_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 | ||
30 | CODEC_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 | 9 | CODEC_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 | |||
60 | static 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 | |||
85 | CREATE_TIMER(total); | ||
86 | CREATE_TIMER(cpu); | ||
87 | CREATE_TIMER(apu); | ||
88 | CREATE_TIMER(squares); | ||
89 | CREATE_TIMER(tnd); | ||
90 | CREATE_TIMER(tnd_enter); | ||
91 | CREATE_TIMER(tnd_tri); | ||
92 | CREATE_TIMER(tnd_noise); | ||
93 | CREATE_TIMER(tnd_dmc); | ||
94 | CREATE_TIMER(fds); | ||
95 | CREATE_TIMER(frame); | ||
96 | CREATE_TIMER(mix); | ||
97 | |||
98 | void 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 | |||
113 | int logfd=-1; | ||
114 | |||
115 | void 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 | ||
152 | union TWIN | ||
153 | { | ||
154 | uint16_t W; | ||
155 | struct{ uint8_t l; uint8_t h; } B; | ||
156 | }; | ||
157 | |||
158 | union QUAD | ||
159 | { | ||
160 | uint32_t D; | ||
161 | struct{ uint8_t l; uint8_t h; uint16_t w; } B; | ||
162 | }; | ||
163 | #else | ||
164 | |||
165 | union TWIN | ||
166 | { | ||
167 | uint16_t W; | ||
168 | struct{ uint8_t h; uint8_t l; } B; | ||
169 | }; | ||
170 | |||
171 | union 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 */ | ||
189 | static const int32_t ModulationTable[8] ICONST_ATTR = {0,1,2,4,0,-4,-2,-1}; | ||
190 | static 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 | |||
199 | static const uint8_t DUTY_CYCLE_TABLE[4] ICONST_ATTR_NSF_LARGE_IRAM = { | ||
200 | 2,4,8,12 | ||
201 | }; | ||
202 | |||
203 | static 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 | |||
209 | static 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 | |||
218 | struct 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 | |||
239 | struct 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 | |||
250 | static int32_t LoadFile(uint8_t *,size_t); | ||
251 | |||
252 | static int32_t LoadFile_NESM(uint8_t *,size_t); | ||
253 | static int32_t LoadFile_NSFE(uint8_t *,size_t); | ||
254 | |||
255 | /* NSF file info */ | ||
256 | |||
257 | /* basic NSF info */ | ||
258 | static int32_t bIsExtended=0; /* 0 = NSF, 1 = NSFE */ | ||
259 | static uint8_t nIsPal=0; /* 0 = NTSC, 1 = PAL, 2,3 = mixed | ||
260 | NTSC/PAL (interpretted as NTSC) */ | ||
261 | static int32_t nfileLoadAddress=0; /* The address to which the NSF code is | ||
262 | loaded */ | ||
263 | static int32_t nfileInitAddress=0; /* The address of the Init routine | ||
264 | (called at track change) */ | ||
265 | static int32_t nfilePlayAddress=0; /* The address of the Play routine | ||
266 | (called several times a second) */ | ||
267 | static uint8_t nChipExtensions=0; /* Bitwise representation of the | ||
268 | external chips used by this NSF. */ | ||
269 | |||
270 | /* old NESM speed stuff (blarg) */ | ||
271 | static int32_t nNTSC_PlaySpeed=0; | ||
272 | static int32_t nPAL_PlaySpeed=0; | ||
273 | |||
274 | /* track info */ | ||
275 | /* The number of tracks in the NSF (1 = 1 track, 5 = 5 tracks, etc) */ | ||
276 | static int32_t nTrackCount=0; | ||
277 | /* The initial track (ZERO BASED: 0 = 1st track, 4 = 5th track, etc) */ | ||
278 | static int32_t nInitialTrack=0; | ||
279 | |||
280 | /* nsf data */ | ||
281 | static uint8_t* pDataBuffer=0; /* the buffer containing NSF code. */ | ||
282 | static int32_t nDataBufferSize=0; /* the size of the above buffer. */ | ||
283 | |||
284 | /* playlist */ | ||
285 | static uint8_t nPlaylist[256]; /* Each entry is the zero based index of | ||
286 | the song to play */ | ||
287 | static int32_t nPlaylistSize=0; /* number of tracks in the playlist */ | ||
288 | |||
289 | /* track time / fade */ | ||
290 | static int32_t nTrackTime[256]; /* track times -1 if no track times | ||
291 | specified */ | ||
292 | static int32_t nTrackFade[256]; /* track fade times -1 if none are | ||
293 | specified */ | ||
294 | |||
295 | /* string info */ | ||
296 | static uint8_t szGameTitle[0x101]; | ||
297 | static uint8_t szArtist[0x101]; | ||
298 | static uint8_t szCopyright[0x101]; | ||
299 | static uint8_t szRipper[0x101]; | ||
300 | |||
301 | /* bankswitching info */ | ||
302 | static 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 | |||
307 | static 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 | |||
335 | static 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 | |||
386 | static 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 | |||
556 | struct 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 | }; | ||
611 | static int16_t FDS_nOutputTable_L[4][0x21][0x40] IBSS_ATTR_NSF_LARGE_IRAM MEM_ALIGN_ATTR; | ||
612 | |||
613 | struct 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 | |||
632 | static int16_t FME07_nOutputTable_L[0x10] IDATA_ATTR MEM_ALIGN_ATTR; | ||
633 | |||
634 | struct 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 | |||
672 | static int16_t N106_nOutputTable_L[0x10][0x10] IBSS_ATTR_NSF_LARGE_IRAM MEM_ALIGN_ATTR; | ||
673 | |||
674 | struct 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 | |||
697 | static int16_t VRC6Pulse_nOutputTable_L[0x10] IDATA_ATTR MEM_ALIGN_ATTR; | ||
698 | |||
699 | struct 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 | |||
719 | static int16_t VRC6Saw_nOutputTable_L[0x20] IDATA_ATTR MEM_ALIGN_ATTR; | ||
720 | |||
721 | struct 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 | |||
757 | static int16_t Squares_nOutputTable_L[0x10][0x10] IDATA_ATTR MEM_ALIGN_ATTR; | ||
758 | |||
759 | struct 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 */ | ||
848 | static struct Wave_Squares mWave_Squares IDATA_ATTR; /* Square channels 1 and 2 */ | ||
849 | static struct Wave_TND mWave_TND IDATA_ATTR; /* Triangle/Noise/DMC channels */ | ||
850 | static struct VRC6PulseWave mWave_VRC6Pulse[2] IDATA_ATTR; | ||
851 | static struct VRC6SawWave mWave_VRC6Saw IDATA_ATTR; | ||
852 | static struct N106Wave mWave_N106 IDATA_ATTR; | ||
853 | static struct FDSWave mWave_FDS IDATA_ATTR; | ||
854 | static 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 | ||
864 | static void Wave_N106_DoTicks(const int32_t ticks) ICODE_ATTR; | ||
865 | static void Wave_N106_DoTicks(const int32_t ticks) | ||
866 | #else | ||
867 | static inline void Wave_N106_DoTicks(const int32_t ticks); | ||
868 | static 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 | ||
934 | static void Wave_VRC6_DoTicks(const int32_t ticks) ICODE_ATTR; | ||
935 | static void Wave_VRC6_DoTicks(const int32_t ticks) | ||
936 | #else | ||
937 | static inline void Wave_VRC6_DoTicks(const int32_t ticks); | ||
938 | static 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 | ||
996 | static void Wave_Squares_ClockMajor(void) ICODE_ATTR; | ||
997 | static void Wave_Squares_ClockMajor() | ||
998 | #else | ||
999 | static inline void Wave_Squares_ClockMajor(void); | ||
1000 | static 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 | ||
1041 | static void Wave_Squares_CheckSweepForcedSilence(const int32_t i) ICODE_ATTR; | ||
1042 | static void Wave_Squares_CheckSweepForcedSilence(const int32_t i) | ||
1043 | #else | ||
1044 | static inline void Wave_Squares_CheckSweepForcedSilence(const int32_t i); | ||
1045 | static 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 | ||
1061 | static void Wave_Squares_ClockMinor(void) ICODE_ATTR; | ||
1062 | static void Wave_Squares_ClockMinor() | ||
1063 | #else | ||
1064 | static inline void Wave_Squares_ClockMinor(void); | ||
1065 | static 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 | /* */ | ||
1094 | other_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 | ||
1121 | static void Wave_TND_ClockMajor(void) ICODE_ATTR; | ||
1122 | static void Wave_TND_ClockMajor() | ||
1123 | #else | ||
1124 | static inline void Wave_TND_ClockMajor(void); | ||
1125 | static 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 | ||
1159 | static void Wave_TND_ClockMinor(void) ICODE_ATTR; | ||
1160 | static void Wave_TND_ClockMinor() | ||
1161 | #else | ||
1162 | static inline void Wave_TND_ClockMinor(void); | ||
1163 | static 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 */ | ||
1183 | static uint8_t pRAM[0x800] IBSS_ATTR_NSF_LARGE_IRAM MEM_ALIGN_ATTR; | ||
1184 | /* SRAM: 0x6000 - 0x7FFF (non-FDS only) */ | ||
1185 | static 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) */ | ||
1188 | static uint8_t pExRAM[0x1000] IBSS_ATTR_NSF_LARGE_IRAM MEM_ALIGN_ATTR; | ||
1189 | /* Full ROM buffer */ | ||
1190 | static uint8_t* pROM_Full IDATA_ATTR; | ||
1191 | |||
1192 | static uint16_t main_nOutputTable_L[0x8000] MEM_ALIGN_ATTR; | ||
1193 | |||
1194 | static uint8_t* pROM[10] IDATA_ATTR;/* ROM banks (point to areas in pROM_Full) */ | ||
1195 | /* 0x8000 - 0xFFFF */ | ||
1196 | /* also includes 0x6000 - 0x7FFF (FDS only) */ | ||
1197 | static uint8_t* pStack; /* the stack (points to areas in pRAM) */ | ||
1198 | /* 0x0100 - 0x01FF */ | ||
1199 | |||
1200 | static int32_t nROMSize; /* size of this ROM file in bytes */ | ||
1201 | static int32_t nROMBankCount; /* max number of 4k banks */ | ||
1202 | static int32_t nROMMaxSize; /* size of allocated pROM_Full buffer */ | ||
1203 | |||
1204 | /* | ||
1205 | * Memory Proc Pointers | ||
1206 | */ | ||
1207 | |||
1208 | typedef uint8_t ( *ReadProc)(uint16_t); | ||
1209 | typedef void ( *WriteProc)(uint16_t,uint8_t); | ||
1210 | static ReadProc ReadMemory[0x10] IDATA_ATTR MEM_ALIGN_ATTR; | ||
1211 | static WriteProc WriteMemory[0x10] IDATA_ATTR MEM_ALIGN_ATTR; | ||
1212 | |||
1213 | /* | ||
1214 | * 6502 Registers / Mode | ||
1215 | */ | ||
1216 | |||
1217 | static uint8_t regA IDATA_ATTR; /* Accumulator */ | ||
1218 | static uint8_t regX IDATA_ATTR; /* X-Index */ | ||
1219 | static uint8_t regY IDATA_ATTR; /* Y-Index */ | ||
1220 | static uint8_t regP IDATA_ATTR; /* Processor Status */ | ||
1221 | static uint8_t regSP IDATA_ATTR; /* Stack Pointer */ | ||
1222 | static uint16_t regPC IDATA_ATTR; /* Program Counter */ | ||
1223 | |||
1224 | static uint8_t bPALMode IDATA_ATTR;/* 1 if in PAL emulation mode, 0 if in NTSC */ | ||
1225 | static 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) */ | ||
1231 | static uint8_t nMultIn_Low; | ||
1232 | static uint8_t nMultIn_High; | ||
1233 | |||
1234 | /* | ||
1235 | * NSF Preparation Information | ||
1236 | */ | ||
1237 | |||
1238 | static uint8_t nBankswitchInitValues[10]; /* banks to swap to on tune init */ | ||
1239 | static uint16_t nPlayAddress; /* Play routine address */ | ||
1240 | static uint16_t nInitAddress; /* Init routine address */ | ||
1241 | |||
1242 | static uint8_t nExternalSound; /* external sound chips */ | ||
1243 | static uint8_t nCurTrack; | ||
1244 | |||
1245 | static float fNSFPlaybackSpeed; | ||
1246 | |||
1247 | /* | ||
1248 | * pAPU | ||
1249 | */ | ||
1250 | |||
1251 | static uint8_t nFrameCounter; /* Frame Sequence Counter */ | ||
1252 | static uint8_t nFrameCounterMax; /* Frame Sequence Counter Size | ||
1253 | (3 or 4 depending on $4017.7) */ | ||
1254 | static uint8_t bFrameIRQEnabled; /* TRUE if frame IRQs are enabled */ | ||
1255 | static uint8_t bFrameIRQPending; /* TRUE if the frame sequencer is | ||
1256 | holding down an IRQ */ | ||
1257 | |||
1258 | static uint8_t nFME07_Address; | ||
1259 | |||
1260 | /* | ||
1261 | * Timing and Counters | ||
1262 | */ | ||
1263 | /* fixed point -15.16 */ | ||
1264 | |||
1265 | static int32_t nTicksUntilNextFrame; | ||
1266 | static int32_t nTicksPerPlay; | ||
1267 | static int32_t nTicksUntilNextPlay; | ||
1268 | static int32_t nTicksPerSample; | ||
1269 | static int32_t nTicksUntilNextSample; | ||
1270 | |||
1271 | static uint32_t nCPUCycle IDATA_ATTR; | ||
1272 | static uint32_t nAPUCycle IDATA_ATTR; | ||
1273 | |||
1274 | |||
1275 | static uint32_t nTotalPlays; /* number of times the play subroutine has been | ||
1276 | called (for tracking output time) */ | ||
1277 | /* | ||
1278 | * Silence Tracker | ||
1279 | */ | ||
1280 | static int32_t nSilentSamples; | ||
1281 | static int32_t nSilentSampleMax; | ||
1282 | static int32_t nSilenceTrackMS; | ||
1283 | static uint8_t bNoSilenceIfTime; | ||
1284 | static uint8_t bTimeNotDefault; | ||
1285 | |||
1286 | /* | ||
1287 | * Sound output options | ||
1288 | */ | ||
1289 | static const int32_t nSampleRate=44100; | ||
1290 | |||
1291 | /* | ||
1292 | * Volume/fading/filter tracking | ||
1293 | */ | ||
1294 | |||
1295 | static uint32_t nStartFade; /* play call to start fading out */ | ||
1296 | static uint32_t nEndFade; /* play call to stop fading out (song is over) */ | ||
1297 | static uint8_t bFade; /* are we fading? */ | ||
1298 | static float fFadeVolume; | ||
1299 | static float fFadeChange; | ||
1300 | |||
1301 | /* | ||
1302 | * Designated Output Buffer | ||
1303 | */ | ||
1304 | static uint8_t* pOutput IDATA_ATTR; | ||
1305 | |||
1306 | static const uint8_t bDMCPopReducer=1; | ||
1307 | static uint8_t nDMCPop_Prev IDATA_ATTR = 0; | ||
1308 | static uint8_t bDMCPop_Skip IDATA_ATTR = 0; | ||
1309 | static uint8_t bDMCPop_SamePlay IDATA_ATTR = 0; | ||
1310 | |||
1311 | static const uint8_t nForce4017Write=0; | ||
1312 | static const uint8_t bN106PopReducer=0; | ||
1313 | static const uint8_t bIgnore4011Writes=0; | ||
1314 | |||
1315 | static const uint8_t bIgnoreBRK=0; | ||
1316 | static const uint8_t bIgnoreIllegalOps=0; | ||
1317 | static const uint8_t bNoWaitForReturn=0; | ||
1318 | static const uint8_t bPALPreference=0; | ||
1319 | static const uint8_t bCleanAXY=0; | ||
1320 | static const uint8_t bResetDuty=0; | ||
1321 | |||
1322 | /* | ||
1323 | * Sound Filter | ||
1324 | */ | ||
1325 | |||
1326 | static int64_t nFilterAccL IDATA_ATTR; | ||
1327 | static int64_t nHighPass IDATA_ATTR; | ||
1328 | |||
1329 | static int32_t nHighPassBase IDATA_ATTR; | ||
1330 | |||
1331 | static 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 | |||
1351 | static uint32_t Emulate6502(uint32_t runto) ICODE_ATTR; | ||
1352 | static void EmulateAPU(uint8_t bBurnCPUCycles) ICODE_ATTR; | ||
1353 | |||
1354 | static int NSFCore_Initialize(void); /* 1 = initialized ok, | ||
1355 | 0 = couldn't initialize (memory allocation error) */ | ||
1356 | |||
1357 | /* | ||
1358 | * Song Loading | ||
1359 | */ | ||
1360 | static int LoadNSF(int32_t); /* grab data from an existing file | ||
1361 | 1 = loaded ok, 0 = error loading */ | ||
1362 | |||
1363 | /* | ||
1364 | * Track Control | ||
1365 | */ | ||
1366 | static void SetTrack(uint8_t track); /* Change tracks */ | ||
1367 | |||
1368 | /* | ||
1369 | * Getting Samples | ||
1370 | */ | ||
1371 | /* fill a buffer with samples */ | ||
1372 | static 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) */ | ||
1378 | static int SetPlaybackOptions(int32_t samplerate); | ||
1379 | /* Speed throttling (0 = uses NSF specified speed) */ | ||
1380 | static void SetPlaybackSpeed(float playspersec); | ||
1381 | |||
1382 | static float GetPlaybackSpeed(void); | ||
1383 | /* rockbox: not used | ||
1384 | float GetMasterVolume(void); */ | ||
1385 | |||
1386 | /* rockbox: not used */ | ||
1387 | #if 0 | ||
1388 | /* | ||
1389 | * Seeking | ||
1390 | */ | ||
1391 | /* gets the number of 'play' routine calls executed */ | ||
1392 | float GetPlayCalls(void); | ||
1393 | |||
1394 | /* gets the output time (based on the given play rate, | ||
1395 | if basedplayspersec is zero, current playback speed is used */ | ||
1396 | uint32_t GetWrittenTime(float basedplayspersec); | ||
1397 | /* sets the number of 'plays' routines executed (for precise seeking) */ | ||
1398 | void SetPlayCalls(float plays); | ||
1399 | /* sets the written time (approx. seeking) */ | ||
1400 | void SetWrittenTime(uint32_t ms,float basedplays); | ||
1401 | #endif | ||
1402 | |||
1403 | /* | ||
1404 | * Fading | ||
1405 | */ | ||
1406 | |||
1407 | /* rockbox: not used | ||
1408 | void StopFade(void); */ /* stops all fading (plays indefinitely) */ | ||
1409 | static uint8_t SongCompleted(void); /* song has faded out (samples have | ||
1410 | stopped being generated) */ | ||
1411 | /* parameters are play calls */ | ||
1412 | static void SetFade(int32_t fadestart,int32_t fadestop,uint8_t bNotDefault); | ||
1413 | static 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 | */ | ||
1420 | static void RebuildOutputTables(void); | ||
1421 | static void RecalculateFade(void); /* called when fade status is changed. */ | ||
1422 | static void RecalcFilter(void); | ||
1423 | static void RecalcSilenceTracker(void); | ||
1424 | |||
1425 | static void WriteMemory_VRC6(uint16_t a,uint8_t v) ICODE_ATTR; | ||
1426 | static void WriteMemory_MMC5(uint16_t a,uint8_t v) ICODE_ATTR; | ||
1427 | static void WriteMemory_N106(uint16_t a,uint8_t v) ICODE_ATTR; | ||
1428 | static void WriteMemory_FME07(uint16_t a,uint8_t v) ICODE_ATTR; | ||
1429 | |||
1430 | /* | ||
1431 | * Memory Read/Write routines | ||
1432 | */ | ||
1433 | |||
1434 | static uint8_t ReadMemory_RAM(uint16_t a) ICODE_ATTR; | ||
1435 | static uint8_t ReadMemory_ExRAM(uint16_t a) ICODE_ATTR; | ||
1436 | static uint8_t ReadMemory_SRAM(uint16_t a) ICODE_ATTR; | ||
1437 | static uint8_t ReadMemory_pAPU(uint16_t a) ICODE_ATTR; | ||
1438 | static uint8_t ReadMemory_ROM(uint16_t a) ICODE_ATTR; | ||
1439 | static uint8_t ReadMemory_Default(uint16_t a) ICODE_ATTR; | ||
1440 | |||
1441 | static uint8_t ReadMemory_N106(uint16_t a) ICODE_ATTR; | ||
1442 | |||
1443 | static void WriteMemory_RAM(uint16_t a,uint8_t v) ICODE_ATTR; | ||
1444 | static void WriteMemory_ExRAM(uint16_t a,uint8_t v) ICODE_ATTR; | ||
1445 | static void WriteMemory_SRAM(uint16_t a,uint8_t v) ICODE_ATTR; | ||
1446 | static void WriteMemory_pAPU(uint16_t a,uint8_t v) ICODE_ATTR; | ||
1447 | static void WriteMemory_FDSRAM(uint16_t a,uint8_t v) ICODE_ATTR; | ||
1448 | static void WriteMemory_Default(uint16_t a,uint8_t v) ICODE_ATTR; | ||
1449 | |||
1450 | static uint8_t ReadMemory_RAM(uint16_t a) { return pRAM[a & 0x07FF]; } | ||
1451 | static uint8_t ReadMemory_ExRAM(uint16_t a) { return pExRAM[a & 0x0FFF]; } | ||
1452 | static uint8_t ReadMemory_SRAM(uint16_t a) { return pSRAM[a & 0x1FFF]; } | ||
1453 | static uint8_t ReadMemory_ROM(uint16_t a) | ||
1454 | { return pROM[(a >> 12) - 6][a & 0x0FFF]; } | ||
1455 | static uint8_t ReadMemory_Default(uint16_t a) { return (a >> 8); } | ||
1456 | |||
1457 | static void WriteMemory_RAM(uint16_t a,uint8_t v) | ||
1458 | { pRAM[a & 0x07FF] = v; } | ||
1459 | static void WriteMemory_ExRAM(uint16_t a,uint8_t v); | ||
1460 | static void WriteMemory_SRAM(uint16_t a,uint8_t v) | ||
1461 | { pSRAM[a & 0x1FFF] = v; } | ||
1462 | static void WriteMemory_FDSRAM(uint16_t a,uint8_t v) | ||
1463 | { pROM[(a >> 12) - 6][a & 0x0FFF] = v; } | ||
1464 | static void WriteMemory_Default(uint16_t a,uint8_t v) { (void)a; (void)v; } | ||
1465 | |||
1466 | |||
1467 | /* Read Memory Procs */ | ||
1468 | |||
1469 | static 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 | |||
1502 | static 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 */ | 14 | static int16_t samples[CHUNK_SIZE] IBSS_ATTR; |
1517 | 15 | static struct Nsf_Emu nsf_emu IDATA_ATTR CACHEALIGN_ATTR; | |
1518 | static 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 | |||
1539 | static 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 | |||
1888 | static 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 | |||
1951 | static 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; | ||
1967 | multiply: | ||
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 | |||
1981 | static 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 | |||
2053 | static 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 | |||
2086 | static int32_t fulltick; | ||
2087 | static 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 | |||
2605 | static 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 | |||
2764 | static 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 | |||
2938 | static 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 | |||
3067 | static 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 | |||
3086 | static 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 | |||
3101 | static 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 | |||
3111 | static 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 | |||
3124 | static 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 | |||
3137 | static 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 | |||
3242 | float 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 | */ | ||
3253 | uint32_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 | */ | ||
3267 | void StopFade() | ||
3268 | { | ||
3269 | bFade = 0; | ||
3270 | fFadeVolume = 1; | ||
3271 | } | ||
3272 | #endif | ||
3273 | |||
3274 | /* | ||
3275 | * SongCompleted | ||
3276 | */ | ||
3277 | |||
3278 | static 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 | |||
3291 | static 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 | |||
3310 | static 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 | |||
3326 | static 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 | |||
3358 | static 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 */ | ||
3572 | static const uint8_t CPU_Cycles[0x100] ICONST_ATTR_NSF_LARGE_IRAM = { | ||
3573 | 7,6,0,8,3,3,5,5,3,2,2,2,4,4,6,6, | ||
3574 | 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7, | ||
3575 | 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6, | ||
3576 | 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7, | ||
3577 | 6,6,0,8,3,3,5,5,3,2,2,2,3,4,6,6, | ||
3578 | 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7, | ||
3579 | 6,6,0,8,3,3,5,5,4,2,2,2,5,4,6,6, | ||
3580 | 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7, | ||
3581 | 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, | ||
3582 | 2,6,0,6,4,4,4,4,2,5,2,5,5,5,5,5, | ||
3583 | 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, | ||
3584 | 2,5,0,5,4,4,4,4,2,4,2,4,4,4,4,4, | ||
3585 | 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6, | ||
3586 | 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7, | ||
3587 | 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6, | ||
3588 | 2,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 */ | ||
3591 | static const uint8_t NZTable[0x100] ICONST_ATTR_NSF_LARGE_IRAM = { | ||
3592 | Z_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, | ||
3593 | 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,0, | ||
3594 | 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,0, | ||
3595 | 0,0,0,0,0,0,0,0,0,0,0, | ||
3596 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3597 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3598 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3599 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3600 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3601 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3602 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3603 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3604 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3605 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3606 | N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG, | ||
3607 | N_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 | |||
3821 | static uint8_t val; | ||
3822 | static uint8_t op; | ||
3823 | |||
3824 | static 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 | |||
4308 | jammed: | ||
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 **/ | 19 | static void set_codec_track(int t, int multitrack) { |
4324 | static int track = 0; | 20 | Nsf_start_track(&nsf_emu, t); |
4325 | static char last_path[MAX_PATH]; | ||
4326 | static int dontresettrack = 0; | ||
4327 | static bool repeat_one = false; | ||
4328 | |||
4329 | static 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 */ |
4346 | enum codec_status codec_main(enum codec_entry_call_reason reason) | 31 | enum 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 */ |
4361 | enum codec_status codec_run(void) | 49 | enum 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) | |
4389 | init_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)) { | 88 | next_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(¶m); | 93 | enum codec_command_action action = ci->get_command(¶m); |
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 | |||
7 | CODEC_HEADER | ||
8 | |||
9 | /* Maximum number of bytes to process in one iteration */ | ||
10 | #define CHUNK_SIZE (1024*2) | ||
11 | |||
12 | static int16_t samples[CHUNK_SIZE] IBSS_ATTR; | ||
13 | static struct Sgc_Emu sgc_emu IDATA_ATTR CACHEALIGN_ATTR; | ||
14 | |||
15 | /* Coleco Bios */ | ||
16 | /* Colecovision not supported yet | ||
17 | static char coleco_bios[0x2000]; | ||
18 | */ | ||
19 | |||
20 | /****************** rockbox interface ******************/ | ||
21 | |||
22 | static 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 */ | ||
33 | enum 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 */ | ||
61 | enum 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 | |||
94 | next_track: | ||
95 | set_codec_track(track); | ||
96 | |||
97 | /* The main decoder loop */ | ||
98 | while (1) { | ||
99 | enum codec_command_action action = ci->get_command(¶m); | ||
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 | |||
12 | CODEC_HEADER | ||
13 | |||
14 | /* Maximum number of bytes to process in one iteration */ | ||
15 | #define CHUNK_SIZE (1024*4) | ||
16 | #define MAINMEMBUF 0 | ||
17 | |||
18 | static int16_t samples[CHUNK_SIZE] IBSS_ATTR; | ||
19 | static struct Vgm_Emu vgm_emu IDATA_ATTR CACHEALIGN_ATTR; | ||
20 | |||
21 | static void *inflatebuf; /* heap for gunzip */ | ||
22 | static char *songbuf; /* destination for uncompressed song */ | ||
23 | static uint32_t songbuflen=0; /* size of the song buffer */ | ||
24 | static uint32_t songlen=0; /* used size of the song buffer */ | ||
25 | |||
26 | /****************** rockbox interface ******************/ | ||
27 | |||
28 | /* this is the codec entry point */ | ||
29 | enum 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 */ | ||
47 | enum 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(¶m); | ||
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 | } | ||