diff options
Diffstat (limited to 'apps/codecs/libgme/sgc_emu.c')
-rw-r--r-- | apps/codecs/libgme/sgc_emu.c | 960 |
1 files changed, 480 insertions, 480 deletions
diff --git a/apps/codecs/libgme/sgc_emu.c b/apps/codecs/libgme/sgc_emu.c index e7253a8d5b..267f2c9271 100644 --- a/apps/codecs/libgme/sgc_emu.c +++ b/apps/codecs/libgme/sgc_emu.c | |||
@@ -1,480 +1,480 @@ | |||
1 | // Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ | 1 | // Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ |
2 | 2 | ||
3 | #include "sgc_emu.h" | 3 | #include "sgc_emu.h" |
4 | 4 | ||
5 | /* Copyright (C) 2009 Shay Green. This module is free software; you | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 12 | details. You should have received a copy of the GNU Lesser General Public |
13 | License aint with this module; if not, write to the Free Software Foundation, | 13 | License aint with this module; if not, write to the Free Software Foundation, |
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | 14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
15 | 15 | ||
16 | #include "blargg_source.h" | 16 | #include "blargg_source.h" |
17 | 17 | ||
18 | int const osc_count = sms_osc_count + fm_apu_osc_count; | 18 | int const osc_count = sms_osc_count + fm_apu_osc_count; |
19 | 19 | ||
20 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; | 20 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; |
21 | 21 | ||
22 | static void clear_track_vars( struct Sgc_Emu* this ) | 22 | static void clear_track_vars( struct Sgc_Emu* this ) |
23 | { | 23 | { |
24 | this->current_track = -1; | 24 | this->current_track = -1; |
25 | track_stop( &this->track_filter ); | 25 | track_stop( &this->track_filter ); |
26 | } | 26 | } |
27 | 27 | ||
28 | void Sgc_init( struct Sgc_Emu* this ) | 28 | void Sgc_init( struct Sgc_Emu* this ) |
29 | { | 29 | { |
30 | assert( offsetof (struct header_t,copyright [32]) == header_size ); | 30 | assert( offsetof (struct header_t,copyright [32]) == header_size ); |
31 | 31 | ||
32 | this->sample_rate = 0; | 32 | this->sample_rate = 0; |
33 | this->mute_mask_ = 0; | 33 | this->mute_mask_ = 0; |
34 | this->tempo = (int)FP_ONE_TEMPO; | 34 | this->tempo = (int)FP_ONE_TEMPO; |
35 | this->gain = (int)FP_ONE_GAIN; | 35 | this->gain = (int)FP_ONE_GAIN; |
36 | 36 | ||
37 | // defaults | 37 | // defaults |
38 | this->tfilter = *track_get_setup( &this->track_filter ); | 38 | this->tfilter = *track_get_setup( &this->track_filter ); |
39 | this->tfilter.max_initial = 2; | 39 | this->tfilter.max_initial = 2; |
40 | this->tfilter.lookahead = 6; | 40 | this->tfilter.lookahead = 6; |
41 | this->track_filter.silence_ignored_ = false; | 41 | this->track_filter.silence_ignored_ = false; |
42 | 42 | ||
43 | Sms_apu_init( &this->apu ); | 43 | Sms_apu_init( &this->apu ); |
44 | Fm_apu_create( &this->fm_apu ); | 44 | Fm_apu_create( &this->fm_apu ); |
45 | 45 | ||
46 | Rom_init( &this->rom, 0x4000 ); | 46 | Rom_init( &this->rom, 0x4000 ); |
47 | Z80_init( &this->cpu ); | 47 | Z80_init( &this->cpu ); |
48 | 48 | ||
49 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); | 49 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); |
50 | 50 | ||
51 | // Unload | 51 | // Unload |
52 | this->voice_count = 0; | 52 | this->voice_count = 0; |
53 | this->voice_types = 0; | 53 | this->voice_types = 0; |
54 | clear_track_vars( this ); | 54 | clear_track_vars( this ); |
55 | } | 55 | } |
56 | 56 | ||
57 | // Setup | 57 | // Setup |
58 | 58 | ||
59 | blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ) | 59 | blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ) |
60 | { | 60 | { |
61 | RETURN_ERR( Rom_load( &this->rom, data, size, header_size, &this->header, 0 ) ); | 61 | RETURN_ERR( Rom_load( &this->rom, data, size, header_size, &this->header, 0 ) ); |
62 | 62 | ||
63 | if ( !valid_tag( &this->header ) ) | 63 | if ( !valid_tag( &this->header ) ) |
64 | return gme_wrong_file_type; | 64 | return gme_wrong_file_type; |
65 | 65 | ||
66 | /* if ( header.vers != 1 ) | 66 | /* if ( header.vers != 1 ) |
67 | warning( "Unknown file version" ); */ | 67 | warning( "Unknown file version" ); */ |
68 | 68 | ||
69 | /* if ( header.system > 2 ) | 69 | /* if ( header.system > 2 ) |
70 | warning( "Unknown system" ); */ | 70 | warning( "Unknown system" ); */ |
71 | 71 | ||
72 | addr_t load_addr = get_le16( this->header.load_addr ); | 72 | addr_t load_addr = get_le16( this->header.load_addr ); |
73 | /* if ( load_addr < 0x400 ) | 73 | /* if ( load_addr < 0x400 ) |
74 | set_warning( "Invalid load address" ); */ | 74 | set_warning( "Invalid load address" ); */ |
75 | 75 | ||
76 | Rom_set_addr( &this->rom, load_addr ); | 76 | Rom_set_addr( &this->rom, load_addr ); |
77 | this->play_period = clock_rate( this ) / 60; | 77 | this->play_period = clock_rate( this ) / 60; |
78 | 78 | ||
79 | if ( sega_mapping( this ) && Fm_apu_supported() ) | 79 | if ( sega_mapping( this ) && Fm_apu_supported() ) |
80 | RETURN_ERR( Fm_apu_init( &this->fm_apu, clock_rate( this ), clock_rate( this ) / 72 ) ); | 80 | RETURN_ERR( Fm_apu_init( &this->fm_apu, clock_rate( this ), clock_rate( this ) / 72 ) ); |
81 | 81 | ||
82 | this->m3u.size = 0; | 82 | this->m3u.size = 0; |
83 | this->track_count = this->header.song_count; | 83 | this->track_count = this->header.song_count; |
84 | this->voice_count = sega_mapping( this ) ? osc_count : sms_osc_count; | 84 | this->voice_count = sega_mapping( this ) ? osc_count : sms_osc_count; |
85 | static int const types [sms_osc_count + fm_apu_osc_count] = { | 85 | static int const types [sms_osc_count + fm_apu_osc_count] = { |
86 | wave_type+1, wave_type+2, wave_type+3, mixed_type+1, mixed_type+2 | 86 | wave_type+1, wave_type+2, wave_type+3, mixed_type+1, mixed_type+2 |
87 | }; | 87 | }; |
88 | this->voice_types = types; | 88 | this->voice_types = types; |
89 | 89 | ||
90 | Sms_apu_volume( &this->apu, this->gain ); | 90 | Sms_apu_volume( &this->apu, this->gain ); |
91 | Fm_apu_volume( &this->fm_apu, this->gain ); | 91 | Fm_apu_volume( &this->fm_apu, this->gain ); |
92 | 92 | ||
93 | // Setup buffer | 93 | // Setup buffer |
94 | this->clock_rate_ = clock_rate( this ); | 94 | this->clock_rate_ = clock_rate( this ); |
95 | Buffer_clock_rate( &this->stereo_buf, clock_rate( this ) ); | 95 | Buffer_clock_rate( &this->stereo_buf, clock_rate( this ) ); |
96 | RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); | 96 | RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); |
97 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 97 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
98 | 98 | ||
99 | Sound_set_tempo( this, this->tempo ); | 99 | Sound_set_tempo( this, this->tempo ); |
100 | Sound_mute_voices( this, this->mute_mask_ ); | 100 | Sound_mute_voices( this, this->mute_mask_ ); |
101 | return 0; | 101 | return 0; |
102 | } | 102 | } |
103 | 103 | ||
104 | static void Sound_set_voice( struct Sgc_Emu* this, int i, struct Blip_Buffer* c, struct Blip_Buffer* l, struct Blip_Buffer* r ) | 104 | static void Sound_set_voice( struct Sgc_Emu* this, int i, struct Blip_Buffer* c, struct Blip_Buffer* l, struct Blip_Buffer* r ) |
105 | { | 105 | { |
106 | if ( i < sms_osc_count ) | 106 | if ( i < sms_osc_count ) |
107 | Sms_apu_set_output( &this->apu, i, c, l, r ); | 107 | Sms_apu_set_output( &this->apu, i, c, l, r ); |
108 | else | 108 | else |
109 | Fm_apu_set_output( &this->fm_apu, c ); | 109 | Fm_apu_set_output( &this->fm_apu, c ); |
110 | } | 110 | } |
111 | 111 | ||
112 | static blargg_err_t run_clocks( struct Sgc_Emu* this, blip_time_t* duration, int msec ) | 112 | static blargg_err_t run_clocks( struct Sgc_Emu* this, blip_time_t* duration, int msec ) |
113 | { | 113 | { |
114 | #if defined(ROCKBOX) | 114 | #if defined(ROCKBOX) |
115 | (void) msec; | 115 | (void) msec; |
116 | #endif | 116 | #endif |
117 | 117 | ||
118 | cpu_time_t t = *duration; | 118 | cpu_time_t t = *duration; |
119 | while ( Z80_time( &this->cpu ) < t ) | 119 | while ( Z80_time( &this->cpu ) < t ) |
120 | { | 120 | { |
121 | cpu_time_t next = min( t, this->next_play ); | 121 | cpu_time_t next = min( t, this->next_play ); |
122 | if ( run_cpu( this, next ) ) | 122 | if ( run_cpu( this, next ) ) |
123 | { | 123 | { |
124 | /* warning( "Unsupported CPU instruction" ); */ | 124 | /* warning( "Unsupported CPU instruction" ); */ |
125 | Z80_set_time( &this->cpu, next ); | 125 | Z80_set_time( &this->cpu, next ); |
126 | } | 126 | } |
127 | 127 | ||
128 | if ( this->cpu.r.pc == this->idle_addr ) | 128 | if ( this->cpu.r.pc == this->idle_addr ) |
129 | Z80_set_time( &this->cpu, next ); | 129 | Z80_set_time( &this->cpu, next ); |
130 | 130 | ||
131 | if ( Z80_time( &this->cpu ) >= this->next_play ) | 131 | if ( Z80_time( &this->cpu ) >= this->next_play ) |
132 | { | 132 | { |
133 | this->next_play += this->play_period; | 133 | this->next_play += this->play_period; |
134 | if ( this->cpu.r.pc == this->idle_addr ) | 134 | if ( this->cpu.r.pc == this->idle_addr ) |
135 | jsr( this, this->header.play_addr ); | 135 | jsr( this, this->header.play_addr ); |
136 | } | 136 | } |
137 | } | 137 | } |
138 | 138 | ||
139 | this->next_play -= t; | 139 | this->next_play -= t; |
140 | check( this->next_play >= 0 ); | 140 | check( this->next_play >= 0 ); |
141 | Z80_adjust_time( &this->cpu, -t ); | 141 | Z80_adjust_time( &this->cpu, -t ); |
142 | 142 | ||
143 | Sms_apu_end_frame( &this->apu, t ); | 143 | Sms_apu_end_frame( &this->apu, t ); |
144 | if ( sega_mapping( this ) && this->fm_accessed ) | 144 | if ( sega_mapping( this ) && this->fm_accessed ) |
145 | { | 145 | { |
146 | if ( Fm_apu_supported() ) | 146 | if ( Fm_apu_supported() ) |
147 | Fm_apu_end_frame( &this->fm_apu, t ); | 147 | Fm_apu_end_frame( &this->fm_apu, t ); |
148 | /* else | 148 | /* else |
149 | warning( "FM sound not supported" ); */ | 149 | warning( "FM sound not supported" ); */ |
150 | } | 150 | } |
151 | 151 | ||
152 | return 0; | 152 | return 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | // Emulation | 155 | // Emulation |
156 | 156 | ||
157 | void cpu_out( struct Sgc_Emu* this, cpu_time_t time, addr_t addr, int data ) | 157 | void cpu_out( struct Sgc_Emu* this, cpu_time_t time, addr_t addr, int data ) |
158 | { | 158 | { |
159 | int port = addr & 0xFF; | 159 | int port = addr & 0xFF; |
160 | 160 | ||
161 | if ( sega_mapping( this ) ) | 161 | if ( sega_mapping( this ) ) |
162 | { | 162 | { |
163 | switch ( port ) | 163 | switch ( port ) |
164 | { | 164 | { |
165 | case 0x06: | 165 | case 0x06: |
166 | Sms_apu_write_ggstereo( &this->apu, time, data ); | 166 | Sms_apu_write_ggstereo( &this->apu, time, data ); |
167 | return; | 167 | return; |
168 | 168 | ||
169 | case 0x7E: | 169 | case 0x7E: |
170 | case 0x7F: | 170 | case 0x7F: |
171 | Sms_apu_write_data( &this->apu, time, data ); /* dprintf( "$7E<-%02X\n", data ); */ | 171 | Sms_apu_write_data( &this->apu, time, data ); /* dprintf( "$7E<-%02X\n", data ); */ |
172 | return; | 172 | return; |
173 | 173 | ||
174 | case 0xF0: | 174 | case 0xF0: |
175 | this->fm_accessed = true; | 175 | this->fm_accessed = true; |
176 | if ( Fm_apu_supported() ) | 176 | if ( Fm_apu_supported() ) |
177 | Fm_apu_write_addr( &this->fm_apu, data );//, dprintf( "$F0<-%02X\n", data ); | 177 | Fm_apu_write_addr( &this->fm_apu, data );//, dprintf( "$F0<-%02X\n", data ); |
178 | return; | 178 | return; |
179 | 179 | ||
180 | case 0xF1: | 180 | case 0xF1: |
181 | this->fm_accessed = true; | 181 | this->fm_accessed = true; |
182 | if ( Fm_apu_supported() ) | 182 | if ( Fm_apu_supported() ) |
183 | Fm_apu_write_data( &this->fm_apu, time, data );//, dprintf( "$F1<-%02X\n", data ); | 183 | Fm_apu_write_data( &this->fm_apu, time, data );//, dprintf( "$F1<-%02X\n", data ); |
184 | return; | 184 | return; |
185 | } | 185 | } |
186 | } | 186 | } |
187 | else if ( port >= 0xE0 ) | 187 | else if ( port >= 0xE0 ) |
188 | { | 188 | { |
189 | Sms_apu_write_data( &this->apu, time, data ); | 189 | Sms_apu_write_data( &this->apu, time, data ); |
190 | return; | 190 | return; |
191 | } | 191 | } |
192 | } | 192 | } |
193 | 193 | ||
194 | void jsr( struct Sgc_Emu* this, byte addr [2] ) | 194 | void jsr( struct Sgc_Emu* this, byte addr [2] ) |
195 | { | 195 | { |
196 | *Z80_write( &this->cpu, --this->cpu.r.sp ) = this->idle_addr >> 8; | 196 | *Z80_write( &this->cpu, --this->cpu.r.sp ) = this->idle_addr >> 8; |
197 | *Z80_write( &this->cpu, --this->cpu.r.sp ) = this->idle_addr & 0xFF; | 197 | *Z80_write( &this->cpu, --this->cpu.r.sp ) = this->idle_addr & 0xFF; |
198 | this->cpu.r.pc = get_le16( addr ); | 198 | this->cpu.r.pc = get_le16( addr ); |
199 | } | 199 | } |
200 | 200 | ||
201 | static void set_bank( struct Sgc_Emu* this, int bank, void const* data ) | 201 | static void set_bank( struct Sgc_Emu* this, int bank, void const* data ) |
202 | { | 202 | { |
203 | //dprintf( "map bank %d to %p\n", bank, (byte*) data - rom.at_addr( 0 ) ); | 203 | //dprintf( "map bank %d to %p\n", bank, (byte*) data - rom.at_addr( 0 ) ); |
204 | Z80_map_mem( &this->cpu, bank * this->rom.bank_size, this->rom.bank_size, this->unmapped_write, data ); | 204 | Z80_map_mem( &this->cpu, bank * this->rom.bank_size, this->rom.bank_size, this->unmapped_write, data ); |
205 | } | 205 | } |
206 | 206 | ||
207 | void cpu_write( struct Sgc_Emu* this, addr_t addr, int data ) | 207 | void cpu_write( struct Sgc_Emu* this, addr_t addr, int data ) |
208 | { | 208 | { |
209 | if ( (addr ^ 0xFFFC) > 3 || !sega_mapping( this ) ) | 209 | if ( (addr ^ 0xFFFC) > 3 || !sega_mapping( this ) ) |
210 | { | 210 | { |
211 | *Z80_write( &this->cpu, addr ) = data; | 211 | *Z80_write( &this->cpu, addr ) = data; |
212 | return; | 212 | return; |
213 | } | 213 | } |
214 | 214 | ||
215 | switch ( addr ) | 215 | switch ( addr ) |
216 | { | 216 | { |
217 | case 0xFFFC: | 217 | case 0xFFFC: |
218 | Z80_map_mem_rw( &this->cpu, 2 * this->rom.bank_size, this->rom.bank_size, this->ram2 ); | 218 | Z80_map_mem_rw( &this->cpu, 2 * this->rom.bank_size, this->rom.bank_size, this->ram2 ); |
219 | if ( data & 0x08 ) | 219 | if ( data & 0x08 ) |
220 | break; | 220 | break; |
221 | 221 | ||
222 | this->bank2 = this->ram2; | 222 | this->bank2 = this->ram2; |
223 | // FALL THROUGH | 223 | // FALL THROUGH |
224 | 224 | ||
225 | case 0xFFFF: { | 225 | case 0xFFFF: { |
226 | bool rom_mapped = (Z80_read( &this->cpu, 2 * this->rom.bank_size ) == this->bank2); | 226 | bool rom_mapped = (Z80_read( &this->cpu, 2 * this->rom.bank_size ) == this->bank2); |
227 | this->bank2 = Rom_at_addr( &this->rom, data * this->rom.bank_size ); | 227 | this->bank2 = Rom_at_addr( &this->rom, data * this->rom.bank_size ); |
228 | if ( rom_mapped ) | 228 | if ( rom_mapped ) |
229 | set_bank( this, 2, this->bank2 ); | 229 | set_bank( this, 2, this->bank2 ); |
230 | break; | 230 | break; |
231 | } | 231 | } |
232 | 232 | ||
233 | case 0xFFFD: | 233 | case 0xFFFD: |
234 | set_bank( this, 0, Rom_at_addr( &this->rom, data * this->rom.bank_size ) ); | 234 | set_bank( this, 0, Rom_at_addr( &this->rom, data * this->rom.bank_size ) ); |
235 | break; | 235 | break; |
236 | 236 | ||
237 | case 0xFFFE: | 237 | case 0xFFFE: |
238 | set_bank( this, 1, Rom_at_addr( &this->rom, data * this->rom.bank_size ) ); | 238 | set_bank( this, 1, Rom_at_addr( &this->rom, data * this->rom.bank_size ) ); |
239 | break; | 239 | break; |
240 | } | 240 | } |
241 | } | 241 | } |
242 | 242 | ||
243 | blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, int rate ) | 243 | blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, int rate ) |
244 | { | 244 | { |
245 | require( !this->sample_rate ); // sample rate can't be changed once set | 245 | require( !this->sample_rate ); // sample rate can't be changed once set |
246 | Buffer_init( &this->stereo_buf ); | 246 | Buffer_init( &this->stereo_buf ); |
247 | Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ); | 247 | Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ); |
248 | 248 | ||
249 | // Set buffer bass | 249 | // Set buffer bass |
250 | Buffer_bass_freq( &this->stereo_buf, 80 ); | 250 | Buffer_bass_freq( &this->stereo_buf, 80 ); |
251 | 251 | ||
252 | this->sample_rate = rate; | 252 | this->sample_rate = rate; |
253 | RETURN_ERR( track_init( &this->track_filter, this ) ); | 253 | RETURN_ERR( track_init( &this->track_filter, this ) ); |
254 | this->tfilter.max_silence = 6 * stereo * this->sample_rate; | 254 | this->tfilter.max_silence = 6 * stereo * this->sample_rate; |
255 | return 0; | 255 | return 0; |
256 | } | 256 | } |
257 | 257 | ||
258 | void Sound_mute_voice( struct Sgc_Emu* this, int index, bool mute ) | 258 | void Sound_mute_voice( struct Sgc_Emu* this, int index, bool mute ) |
259 | { | 259 | { |
260 | require( (unsigned) index < (unsigned) this->voice_count ); | 260 | require( (unsigned) index < (unsigned) this->voice_count ); |
261 | int bit = 1 << index; | 261 | int bit = 1 << index; |
262 | int mask = this->mute_mask_ | bit; | 262 | int mask = this->mute_mask_ | bit; |
263 | if ( !mute ) | 263 | if ( !mute ) |
264 | mask ^= bit; | 264 | mask ^= bit; |
265 | Sound_mute_voices( this, mask ); | 265 | Sound_mute_voices( this, mask ); |
266 | } | 266 | } |
267 | 267 | ||
268 | void Sound_mute_voices( struct Sgc_Emu* this, int mask ) | 268 | void Sound_mute_voices( struct Sgc_Emu* this, int mask ) |
269 | { | 269 | { |
270 | require( this->sample_rate ); // sample rate must be set first | 270 | require( this->sample_rate ); // sample rate must be set first |
271 | this->mute_mask_ = mask; | 271 | this->mute_mask_ = mask; |
272 | 272 | ||
273 | int i; | 273 | int i; |
274 | for ( i = this->voice_count; i--; ) | 274 | for ( i = this->voice_count; i--; ) |
275 | { | 275 | { |
276 | if ( mask & (1 << i) ) | 276 | if ( mask & (1 << i) ) |
277 | { | 277 | { |
278 | Sound_set_voice( this, i, 0, 0, 0 ); | 278 | Sound_set_voice( this, i, 0, 0, 0 ); |
279 | } | 279 | } |
280 | else | 280 | else |
281 | { | 281 | { |
282 | struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); | 282 | struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); |
283 | assert( (ch.center && ch.left && ch.right) || | 283 | assert( (ch.center && ch.left && ch.right) || |
284 | (!ch.center && !ch.left && !ch.right) ); // all or nothing | 284 | (!ch.center && !ch.left && !ch.right) ); // all or nothing |
285 | Sound_set_voice( this, i, ch.center, ch.left, ch.right ); | 285 | Sound_set_voice( this, i, ch.center, ch.left, ch.right ); |
286 | } | 286 | } |
287 | } | 287 | } |
288 | } | 288 | } |
289 | 289 | ||
290 | void Sound_set_tempo( struct Sgc_Emu* this, int t ) | 290 | void Sound_set_tempo( struct Sgc_Emu* this, int t ) |
291 | { | 291 | { |
292 | require( this->sample_rate ); // sample rate must be set first | 292 | require( this->sample_rate ); // sample rate must be set first |
293 | int const min = (int)(FP_ONE_TEMPO*0.02); | 293 | int const min = (int)(FP_ONE_TEMPO*0.02); |
294 | int const max = (int)(FP_ONE_TEMPO*4.00); | 294 | int const max = (int)(FP_ONE_TEMPO*4.00); |
295 | if ( t < min ) t = min; | 295 | if ( t < min ) t = min; |
296 | if ( t > max ) t = max; | 296 | if ( t > max ) t = max; |
297 | this->tempo = t; | 297 | this->tempo = t; |
298 | 298 | ||
299 | this->play_period = (int) ((clock_rate( this ) * FP_ONE_TEMPO) / (this->header.rate ? 50 : 60) / t); | 299 | this->play_period = (int) ((clock_rate( this ) * FP_ONE_TEMPO) / (this->header.rate ? 50 : 60) / t); |
300 | } | 300 | } |
301 | 301 | ||
302 | blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ) | 302 | blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ) |
303 | { | 303 | { |
304 | clear_track_vars( this ); | 304 | clear_track_vars( this ); |
305 | 305 | ||
306 | // Remap track if playlist available | 306 | // Remap track if playlist available |
307 | if ( this->m3u.size > 0 ) { | 307 | if ( this->m3u.size > 0 ) { |
308 | struct entry_t* e = &this->m3u.entries[track]; | 308 | struct entry_t* e = &this->m3u.entries[track]; |
309 | track = e->track; | 309 | track = e->track; |
310 | } | 310 | } |
311 | 311 | ||
312 | this->current_track = track; | 312 | this->current_track = track; |
313 | 313 | ||
314 | if ( sega_mapping( this ) ) | 314 | if ( sega_mapping( this ) ) |
315 | { | 315 | { |
316 | Sms_apu_reset( &this->apu, 0, 0 ); | 316 | Sms_apu_reset( &this->apu, 0, 0 ); |
317 | Fm_apu_reset( &this->fm_apu ); | 317 | Fm_apu_reset( &this->fm_apu ); |
318 | this->fm_accessed = false; | 318 | this->fm_accessed = false; |
319 | } | 319 | } |
320 | else | 320 | else |
321 | { | 321 | { |
322 | Sms_apu_reset( &this->apu, 0x0003, 15 ); | 322 | Sms_apu_reset( &this->apu, 0x0003, 15 ); |
323 | } | 323 | } |
324 | 324 | ||
325 | memset( this->ram , 0, sizeof this->ram ); | 325 | memset( this->ram , 0, sizeof this->ram ); |
326 | memset( this->ram2, 0, sizeof this->ram2 ); | 326 | memset( this->ram2, 0, sizeof this->ram2 ); |
327 | memset( this->vectors, 0xFF, sizeof this->vectors ); | 327 | memset( this->vectors, 0xFF, sizeof this->vectors ); |
328 | Z80_reset( &this->cpu, this->unmapped_write, this->rom.unmapped ); | 328 | Z80_reset( &this->cpu, this->unmapped_write, this->rom.unmapped ); |
329 | 329 | ||
330 | if ( sega_mapping( this ) ) | 330 | if ( sega_mapping( this ) ) |
331 | { | 331 | { |
332 | this->vectors_addr = 0x10000 - page_size; | 332 | this->vectors_addr = 0x10000 - page_size; |
333 | this->idle_addr = this->vectors_addr; | 333 | this->idle_addr = this->vectors_addr; |
334 | int i; | 334 | int i; |
335 | for ( i = 1; i < 8; ++i ) | 335 | for ( i = 1; i < 8; ++i ) |
336 | { | 336 | { |
337 | this->vectors [i*8 + 0] = 0xC3; // JP addr | 337 | this->vectors [i*8 + 0] = 0xC3; // JP addr |
338 | this->vectors [i*8 + 1] = this->header.rst_addrs [i - 1] & 0xff; | 338 | this->vectors [i*8 + 1] = this->header.rst_addrs [i - 1] & 0xff; |
339 | this->vectors [i*8 + 2] = this->header.rst_addrs [i - 1] >> 8; | 339 | this->vectors [i*8 + 2] = this->header.rst_addrs [i - 1] >> 8; |
340 | } | 340 | } |
341 | 341 | ||
342 | Z80_map_mem_rw( &this->cpu, 0xC000, 0x2000, this->ram ); | 342 | Z80_map_mem_rw( &this->cpu, 0xC000, 0x2000, this->ram ); |
343 | Z80_map_mem( &this->cpu, this->vectors_addr, page_size, this->unmapped_write, this->vectors ); | 343 | Z80_map_mem( &this->cpu, this->vectors_addr, page_size, this->unmapped_write, this->vectors ); |
344 | 344 | ||
345 | this->bank2 = NULL; | 345 | this->bank2 = NULL; |
346 | for ( i = 0; i < 4; ++i ) | 346 | for ( i = 0; i < 4; ++i ) |
347 | cpu_write( this, 0xFFFC + i, this->header.mapping [i] ); | 347 | cpu_write( this, 0xFFFC + i, this->header.mapping [i] ); |
348 | } | 348 | } |
349 | else | 349 | else |
350 | { | 350 | { |
351 | if ( !this->coleco_bios ) | 351 | if ( !this->coleco_bios ) |
352 | return "Coleco BIOS not set"; /* BLARGG_ERR( BLARGG_ERR_CALLER, "Coleco BIOS not set" ); */ | 352 | return "Coleco BIOS not set"; /* BLARGG_ERR( BLARGG_ERR_CALLER, "Coleco BIOS not set" ); */ |
353 | 353 | ||
354 | this->vectors_addr = 0; | 354 | this->vectors_addr = 0; |
355 | Z80_map_mem( &this->cpu, 0, 0x2000, this->unmapped_write, this->coleco_bios ); | 355 | Z80_map_mem( &this->cpu, 0, 0x2000, this->unmapped_write, this->coleco_bios ); |
356 | int i; | 356 | int i; |
357 | for ( i = 0; i < 8; ++i ) | 357 | for ( i = 0; i < 8; ++i ) |
358 | Z80_map_mem_rw( &this->cpu, 0x6000 + i*0x400, 0x400, this->ram ); | 358 | Z80_map_mem_rw( &this->cpu, 0x6000 + i*0x400, 0x400, this->ram ); |
359 | 359 | ||
360 | this->idle_addr = 0x2000; | 360 | this->idle_addr = 0x2000; |
361 | Z80_map_mem( &this->cpu, 0x2000, page_size, this->unmapped_write, this->vectors ); | 361 | Z80_map_mem( &this->cpu, 0x2000, page_size, this->unmapped_write, this->vectors ); |
362 | 362 | ||
363 | for ( i = 0; i < 0x8000 / this->rom.bank_size; ++i ) | 363 | for ( i = 0; i < 0x8000 / this->rom.bank_size; ++i ) |
364 | { | 364 | { |
365 | int addr = 0x8000 + i*this->rom.bank_size; | 365 | int addr = 0x8000 + i*this->rom.bank_size; |
366 | Z80_map_mem( &this->cpu, addr, this->rom.bank_size, this->unmapped_write, Rom_at_addr( &this->rom, addr ) ); | 366 | Z80_map_mem( &this->cpu, addr, this->rom.bank_size, this->unmapped_write, Rom_at_addr( &this->rom, addr ) ); |
367 | } | 367 | } |
368 | } | 368 | } |
369 | 369 | ||
370 | this->cpu.r.sp = get_le16( this->header.stack_ptr ); | 370 | this->cpu.r.sp = get_le16( this->header.stack_ptr ); |
371 | this->cpu.r.b.a = track; | 371 | this->cpu.r.b.a = track; |
372 | this->next_play = this->play_period; | 372 | this->next_play = this->play_period; |
373 | 373 | ||
374 | jsr( this, this->header.init_addr ); | 374 | jsr( this, this->header.init_addr ); |
375 | 375 | ||
376 | Buffer_clear( &this->stereo_buf ); | 376 | Buffer_clear( &this->stereo_buf ); |
377 | 377 | ||
378 | // convert filter times to samples | 378 | // convert filter times to samples |
379 | struct setup_t s = this->tfilter; | 379 | struct setup_t s = this->tfilter; |
380 | s.max_initial *= this->sample_rate * stereo; | 380 | s.max_initial *= this->sample_rate * stereo; |
381 | #ifdef GME_DISABLE_SILENCE_LOOKAHEAD | 381 | #ifdef GME_DISABLE_SILENCE_LOOKAHEAD |
382 | s.lookahead = 1; | 382 | s.lookahead = 1; |
383 | #endif | 383 | #endif |
384 | track_setup( &this->track_filter, &s ); | 384 | track_setup( &this->track_filter, &s ); |
385 | 385 | ||
386 | return track_start( &this->track_filter ); | 386 | return track_start( &this->track_filter ); |
387 | } | 387 | } |
388 | 388 | ||
389 | // Tell/Seek | 389 | // Tell/Seek |
390 | 390 | ||
391 | static int msec_to_samples( int msec, int sample_rate ) | 391 | static int msec_to_samples( int msec, int sample_rate ) |
392 | { | 392 | { |
393 | int sec = msec / 1000; | 393 | int sec = msec / 1000; |
394 | msec -= sec * 1000; | 394 | msec -= sec * 1000; |
395 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; | 395 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; |
396 | } | 396 | } |
397 | 397 | ||
398 | int Track_tell( struct Sgc_Emu* this ) | 398 | int Track_tell( struct Sgc_Emu* this ) |
399 | { | 399 | { |
400 | int rate = this->sample_rate * stereo; | 400 | int rate = this->sample_rate * stereo; |
401 | int sec = track_sample_count( &this->track_filter ) / rate; | 401 | int sec = track_sample_count( &this->track_filter ) / rate; |
402 | return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; | 402 | return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; |
403 | } | 403 | } |
404 | 404 | ||
405 | blargg_err_t Track_seek( struct Sgc_Emu* this, int msec ) | 405 | blargg_err_t Track_seek( struct Sgc_Emu* this, int msec ) |
406 | { | 406 | { |
407 | int time = msec_to_samples( msec, this->sample_rate ); | 407 | int time = msec_to_samples( msec, this->sample_rate ); |
408 | if ( time < track_sample_count( &this->track_filter ) ) | 408 | if ( time < track_sample_count( &this->track_filter ) ) |
409 | RETURN_ERR( Sgc_start_track( this, this->current_track ) ); | 409 | RETURN_ERR( Sgc_start_track( this, this->current_track ) ); |
410 | return Track_skip( this, time - track_sample_count( &this->track_filter ) ); | 410 | return Track_skip( this, time - track_sample_count( &this->track_filter ) ); |
411 | } | 411 | } |
412 | 412 | ||
413 | blargg_err_t Track_skip( struct Sgc_Emu* this, int count ) | 413 | blargg_err_t Track_skip( struct Sgc_Emu* this, int count ) |
414 | { | 414 | { |
415 | require( this->current_track >= 0 ); // start_track() must have been called already | 415 | require( this->current_track >= 0 ); // start_track() must have been called already |
416 | return track_skip( &this->track_filter, count ); | 416 | return track_skip( &this->track_filter, count ); |
417 | } | 417 | } |
418 | 418 | ||
419 | blargg_err_t skip_( void* emu, int count ) | 419 | blargg_err_t skip_( void* emu, int count ) |
420 | { | 420 | { |
421 | struct Sgc_Emu* this = (struct Sgc_Emu*) emu; | 421 | struct Sgc_Emu* this = (struct Sgc_Emu*) emu; |
422 | 422 | ||
423 | // for long skip, mute sound | 423 | // for long skip, mute sound |
424 | const int threshold = 32768; | 424 | const int threshold = 32768; |
425 | if ( count > threshold ) | 425 | if ( count > threshold ) |
426 | { | 426 | { |
427 | int saved_mute = this->mute_mask_; | 427 | int saved_mute = this->mute_mask_; |
428 | Sound_mute_voices( this, ~0 ); | 428 | Sound_mute_voices( this, ~0 ); |
429 | 429 | ||
430 | int n = count - threshold/2; | 430 | int n = count - threshold/2; |
431 | n &= ~(2048-1); // round to multiple of 2048 | 431 | n &= ~(2048-1); // round to multiple of 2048 |
432 | count -= n; | 432 | count -= n; |
433 | RETURN_ERR( skippy_( &this->track_filter, n ) ); | 433 | RETURN_ERR( skippy_( &this->track_filter, n ) ); |
434 | 434 | ||
435 | Sound_mute_voices( this, saved_mute ); | 435 | Sound_mute_voices( this, saved_mute ); |
436 | } | 436 | } |
437 | 437 | ||
438 | return skippy_( &this->track_filter, count ); | 438 | return skippy_( &this->track_filter, count ); |
439 | } | 439 | } |
440 | 440 | ||
441 | void Track_set_fade( struct Sgc_Emu* this, int start_msec, int length_msec ) | 441 | void Track_set_fade( struct Sgc_Emu* this, int start_msec, int length_msec ) |
442 | { | 442 | { |
443 | track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), | 443 | track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), |
444 | length_msec * this->sample_rate / (1000 / stereo) ); | 444 | length_msec * this->sample_rate / (1000 / stereo) ); |
445 | } | 445 | } |
446 | 446 | ||
447 | blargg_err_t Sgc_play( struct Sgc_Emu* this, int out_count, sample_t* out ) | 447 | blargg_err_t Sgc_play( struct Sgc_Emu* this, int out_count, sample_t* out ) |
448 | { | 448 | { |
449 | require( this->current_track >= 0 ); | 449 | require( this->current_track >= 0 ); |
450 | require( out_count % stereo == 0 ); | 450 | require( out_count % stereo == 0 ); |
451 | return track_play( &this->track_filter, out_count, out ); | 451 | return track_play( &this->track_filter, out_count, out ); |
452 | } | 452 | } |
453 | 453 | ||
454 | blargg_err_t play_( void* emu, int count, sample_t out [] ) | 454 | blargg_err_t play_( void* emu, int count, sample_t out [] ) |
455 | { | 455 | { |
456 | struct Sgc_Emu* this = (struct Sgc_Emu*) emu; | 456 | struct Sgc_Emu* this = (struct Sgc_Emu*) emu; |
457 | 457 | ||
458 | int remain = count; | 458 | int remain = count; |
459 | while ( remain ) | 459 | while ( remain ) |
460 | { | 460 | { |
461 | Buffer_disable_immediate_removal( &this->stereo_buf ); | 461 | Buffer_disable_immediate_removal( &this->stereo_buf ); |
462 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); | 462 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); |
463 | if ( remain ) | 463 | if ( remain ) |
464 | { | 464 | { |
465 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) | 465 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) |
466 | { | 466 | { |
467 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 467 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
468 | 468 | ||
469 | // Remute voices | 469 | // Remute voices |
470 | Sound_mute_voices( this, this->mute_mask_ ); | 470 | Sound_mute_voices( this, this->mute_mask_ ); |
471 | } | 471 | } |
472 | int msec = Buffer_length( &this->stereo_buf ); | 472 | int msec = Buffer_length( &this->stereo_buf ); |
473 | blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; | 473 | blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; |
474 | RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); | 474 | RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); |
475 | assert( clocks_emulated ); | 475 | assert( clocks_emulated ); |
476 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); | 476 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); |
477 | } | 477 | } |
478 | } | 478 | } |
479 | return 0; | 479 | return 0; |
480 | } | 480 | } |