summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/ay_emu.c
diff options
context:
space:
mode:
authorTorne Wuff <torne@wolfpuppy.org.uk>2011-11-06 22:44:25 +0000
committerTorne Wuff <torne@wolfpuppy.org.uk>2011-11-06 22:44:25 +0000
commit569285794b9112f0134ddad4bb886308ea4a7be6 (patch)
treece702cb07829820261a682c471133c76d11c610e /apps/codecs/libgme/ay_emu.c
parentd9b7d58fa6c9ceb136bea429adf6746cc7138208 (diff)
downloadrockbox-569285794b9112f0134ddad4bb886308ea4a7be6.tar.gz
rockbox-569285794b9112f0134ddad4bb886308ea4a7be6.zip
Bulk convert all DOS line endings to UNIX.
For the git migration we want a nice clean repository with UNIX line endings. git does not use svn:eol-style, we just need the file contents to be sane. Sorry everybody. I know this messes up blame. Scumbag *NIX developer says migrating to git will make line ending issues go away; commits giant change to svn which changes line endings anyway. :) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30924 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libgme/ay_emu.c')
-rw-r--r--apps/codecs/libgme/ay_emu.c1198
1 files changed, 599 insertions, 599 deletions
diff --git a/apps/codecs/libgme/ay_emu.c b/apps/codecs/libgme/ay_emu.c
index 42e739f2df..92faba4929 100644
--- a/apps/codecs/libgme/ay_emu.c
+++ b/apps/codecs/libgme/ay_emu.c
@@ -1,599 +1,599 @@
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 "ay_emu.h" 3#include "ay_emu.h"
4 4
5#include "blargg_endian.h" 5#include "blargg_endian.h"
6 6
7/* Copyright (C) 2006-2009 Shay Green. This module is free software; you 7/* Copyright (C) 2006-2009 Shay Green. This module is free software; you
8can redistribute it and/or modify it under the terms of the GNU Lesser 8can redistribute it and/or modify it under the terms of the GNU Lesser
9General Public License as published by the Free Software Foundation; either 9General Public License as published by the Free Software Foundation; either
10version 2.1 of the License, or (at your option) any later version. This 10version 2.1 of the License, or (at your option) any later version. This
11module is distributed in the hope that it will be useful, but WITHOUT ANY 11module is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14details. You should have received a copy of the GNU Lesser General Public 14details. You should have received a copy of the GNU Lesser General Public
15License along with this module; if not, write to the Free Software Foundation, 15License along with this module; if not, write to the Free Software Foundation,
16Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 16Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17 17
18#include "blargg_source.h" 18#include "blargg_source.h"
19 19
20const char* const gme_wrong_file_type = "Wrong file type for this emulator"; 20const char* const gme_wrong_file_type = "Wrong file type for this emulator";
21 21
22// TODO: probably don't need detailed errors as to why file is corrupt 22// TODO: probably don't need detailed errors as to why file is corrupt
23 23
24int const spectrum_clock = 3546900; // 128K Spectrum 24int const spectrum_clock = 3546900; // 128K Spectrum
25int const spectrum_period = 70908; 25int const spectrum_period = 70908;
26 26
27//int const spectrum_clock = 3500000; // 48K Spectrum 27//int const spectrum_clock = 3500000; // 48K Spectrum
28//int const spectrum_period = 69888; 28//int const spectrum_period = 69888;
29 29
30int const cpc_clock = 2000000; 30int const cpc_clock = 2000000;
31 31
32static void clear_track_vars( struct Ay_Emu *this ) 32static void clear_track_vars( struct Ay_Emu *this )
33{ 33{
34 this->current_track = -1; 34 this->current_track = -1;
35 track_stop( &this->track_filter ); 35 track_stop( &this->track_filter );
36} 36}
37 37
38void Ay_init( struct Ay_Emu *this ) 38void Ay_init( struct Ay_Emu *this )
39{ 39{
40 this->sample_rate = 0; 40 this->sample_rate = 0;
41 this->mute_mask_ = 0; 41 this->mute_mask_ = 0;
42 this->tempo = (int)FP_ONE_TEMPO; 42 this->tempo = (int)FP_ONE_TEMPO;
43 this->gain = (int)FP_ONE_GAIN; 43 this->gain = (int)FP_ONE_GAIN;
44 this->track_count = 0; 44 this->track_count = 0;
45 45
46 // defaults 46 // defaults
47 this->tfilter = *track_get_setup( &this->track_filter ); 47 this->tfilter = *track_get_setup( &this->track_filter );
48 this->tfilter.max_initial = 2; 48 this->tfilter.max_initial = 2;
49 this->tfilter.lookahead = 6; 49 this->tfilter.lookahead = 6;
50 this->track_filter.silence_ignored_ = false; 50 this->track_filter.silence_ignored_ = false;
51 51
52 this->beeper_output = NULL; 52 this->beeper_output = NULL;
53 disable_beeper( this ); 53 disable_beeper( this );
54 54
55 Ay_apu_init( &this->apu ); 55 Ay_apu_init( &this->apu );
56 Z80_init( &this->cpu ); 56 Z80_init( &this->cpu );
57 57
58 // clears fields 58 // clears fields
59 this->voice_count = 0; 59 this->voice_count = 0;
60 this->voice_types = 0; 60 this->voice_types = 0;
61 clear_track_vars( this ); 61 clear_track_vars( this );
62} 62}
63 63
64// Track info 64// Track info
65 65
66// Given pointer to 2-byte offset of data, returns pointer to data, or NULL if 66// Given pointer to 2-byte offset of data, returns pointer to data, or NULL if
67// offset is 0 or there is less than min_size bytes of data available. 67// offset is 0 or there is less than min_size bytes of data available.
68static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size ) 68static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size )
69{ 69{
70 int offset = (int16_t) get_be16( ptr ); 70 int offset = (int16_t) get_be16( ptr );
71 int pos = ptr - (byte const*) file->header; 71 int pos = ptr - (byte const*) file->header;
72 int size = file->end - (byte const*) file->header; 72 int size = file->end - (byte const*) file->header;
73 assert( (unsigned) pos <= (unsigned) size - 2 ); 73 assert( (unsigned) pos <= (unsigned) size - 2 );
74 int limit = size - min_size; 74 int limit = size - min_size;
75 if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit ) 75 if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit )
76 return NULL; 76 return NULL;
77 return ptr + offset; 77 return ptr + offset;
78} 78}
79 79
80static blargg_err_t parse_header( byte const in [], int size, struct file_t* out ) 80static blargg_err_t parse_header( byte const in [], int size, struct file_t* out )
81{ 81{
82 if ( size < header_size ) 82 if ( size < header_size )
83 return gme_wrong_file_type; 83 return gme_wrong_file_type;
84 84
85 out->header = (struct header_t const*) in; 85 out->header = (struct header_t const*) in;
86 out->end = in + size; 86 out->end = in + size;
87 struct header_t const* h = (struct header_t const*) in; 87 struct header_t const* h = (struct header_t const*) in;
88 if ( memcmp( h->tag, "ZXAYEMUL", 8 ) ) 88 if ( memcmp( h->tag, "ZXAYEMUL", 8 ) )
89 return gme_wrong_file_type; 89 return gme_wrong_file_type;
90 90
91 out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 ); 91 out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 );
92 if ( !out->tracks ) 92 if ( !out->tracks )
93 return "missing track data"; 93 return "missing track data";
94 94
95 return 0; 95 return 0;
96} 96}
97 97
98// Setup 98// Setup
99 99
100static void change_clock_rate( struct Ay_Emu *this, int rate ) 100static void change_clock_rate( struct Ay_Emu *this, int rate )
101{ 101{
102 this->clock_rate_ = rate; 102 this->clock_rate_ = rate;
103 Buffer_clock_rate( &this->stereo_buf, rate ); 103 Buffer_clock_rate( &this->stereo_buf, rate );
104} 104}
105 105
106blargg_err_t Ay_load_mem( struct Ay_Emu *this, byte const in [], long size ) 106blargg_err_t Ay_load_mem( struct Ay_Emu *this, byte const in [], long size )
107{ 107{
108 // Unload 108 // Unload
109 this->voice_count = 0; 109 this->voice_count = 0;
110 this->track_count = 0; 110 this->track_count = 0;
111 this->m3u.size = 0; 111 this->m3u.size = 0;
112 clear_track_vars( this ); 112 clear_track_vars( this );
113 113
114 assert( offsetof (struct header_t,track_info [2]) == header_size ); 114 assert( offsetof (struct header_t,track_info [2]) == header_size );
115 115
116 RETURN_ERR( parse_header( in, size, &this->file ) ); 116 RETURN_ERR( parse_header( in, size, &this->file ) );
117 117
118 /* if ( file.header->vers > 2 ) 118 /* if ( file.header->vers > 2 )
119 warning( "Unknown file version" ); */ 119 warning( "Unknown file version" ); */
120 120
121 this->voice_count = ay_osc_count + 1; // +1 for beeper 121 this->voice_count = ay_osc_count + 1; // +1 for beeper
122 static int const types [ay_osc_count + 1] = { 122 static int const types [ay_osc_count + 1] = {
123 wave_type+0, wave_type+1, wave_type+2, mixed_type+1 123 wave_type+0, wave_type+1, wave_type+2, mixed_type+1
124 }; 124 };
125 this->voice_types = types; 125 this->voice_types = types;
126 126
127 Ay_apu_volume( &this->apu, this->gain); 127 Ay_apu_volume( &this->apu, this->gain);
128 128
129 // Setup buffer 129 // Setup buffer
130 change_clock_rate( this, spectrum_clock ); 130 change_clock_rate( this, spectrum_clock );
131 RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); 131 RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) );
132 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); 132 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
133 133
134 Sound_set_tempo( this, this->tempo ); 134 Sound_set_tempo( this, this->tempo );
135 Sound_mute_voices( this, this->mute_mask_ ); 135 Sound_mute_voices( this, this->mute_mask_ );
136 136
137 this->track_count = this->file.header->max_track + 1; 137 this->track_count = this->file.header->max_track + 1;
138 return 0; 138 return 0;
139} 139}
140 140
141static void set_beeper_output( struct Ay_Emu *this, struct Blip_Buffer* b ) 141static void set_beeper_output( struct Ay_Emu *this, struct Blip_Buffer* b )
142{ 142{
143 this->beeper_output = b; 143 this->beeper_output = b;
144 if ( b && !this->cpc_mode ) 144 if ( b && !this->cpc_mode )
145 this->beeper_mask = 0x10; 145 this->beeper_mask = 0x10;
146 else 146 else
147 disable_beeper( this ); 147 disable_beeper( this );
148} 148}
149 149
150static void set_voice( struct Ay_Emu *this, int i, struct Blip_Buffer* center ) 150static void set_voice( struct Ay_Emu *this, int i, struct Blip_Buffer* center )
151{ 151{
152 if ( i >= ay_osc_count ) 152 if ( i >= ay_osc_count )
153 set_beeper_output( this, center ); 153 set_beeper_output( this, center );
154 else 154 else
155 Ay_apu_set_output( &this->apu, i, center ); 155 Ay_apu_set_output( &this->apu, i, center );
156} 156}
157 157
158static blargg_err_t run_clocks( struct Ay_Emu *this, blip_time_t* duration, int msec ) 158static blargg_err_t run_clocks( struct Ay_Emu *this, blip_time_t* duration, int msec )
159{ 159{
160#if defined(ROCKBOX) 160#if defined(ROCKBOX)
161 (void) msec; 161 (void) msec;
162#endif 162#endif
163 163
164 cpu_time_t *end = duration; 164 cpu_time_t *end = duration;
165 struct Z80_Cpu* cpu = &this->cpu; 165 struct Z80_Cpu* cpu = &this->cpu;
166 Z80_set_time( cpu, 0 ); 166 Z80_set_time( cpu, 0 );
167 167
168 // Since detection of CPC mode will halve clock rate during the frame 168 // Since detection of CPC mode will halve clock rate during the frame
169 // and thus generate up to twice as much sound, we must generate half 169 // and thus generate up to twice as much sound, we must generate half
170 // as much until mode is known. 170 // as much until mode is known.
171 if ( !(this->spectrum_mode | this->cpc_mode) ) 171 if ( !(this->spectrum_mode | this->cpc_mode) )
172 *end /= 2; 172 *end /= 2;
173 173
174 while ( Z80_time( cpu ) < *end ) 174 while ( Z80_time( cpu ) < *end )
175 { 175 {
176 run_cpu( this, min( *end, this->next_play ) ); 176 run_cpu( this, min( *end, this->next_play ) );
177 177
178 if ( Z80_time( cpu ) >= this->next_play ) 178 if ( Z80_time( cpu ) >= this->next_play )
179 { 179 {
180 // next frame 180 // next frame
181 this->next_play += this->play_period; 181 this->next_play += this->play_period;
182 182
183 if ( cpu->r.iff1 ) 183 if ( cpu->r.iff1 )
184 { 184 {
185 // interrupt enabled 185 // interrupt enabled
186 186
187 if ( this->mem.ram [cpu->r.pc] == 0x76 ) 187 if ( this->mem.ram [cpu->r.pc] == 0x76 )
188 cpu->r.pc++; // advance past HALT instruction 188 cpu->r.pc++; // advance past HALT instruction
189 189
190 cpu->r.iff1 = 0; 190 cpu->r.iff1 = 0;
191 cpu->r.iff2 = 0; 191 cpu->r.iff2 = 0;
192 192
193 this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc >> 8); 193 this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc >> 8);
194 this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc); 194 this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc);
195 195
196 // fixed interrupt 196 // fixed interrupt
197 cpu->r.pc = 0x38; 197 cpu->r.pc = 0x38;
198 Z80_adjust_time( cpu, 12 ); 198 Z80_adjust_time( cpu, 12 );
199 199
200 if ( cpu->r.im == 2 ) 200 if ( cpu->r.im == 2 )
201 { 201 {
202 // vectored interrupt 202 // vectored interrupt
203 addr_t addr = cpu->r.i * 0x100 + 0xFF; 203 addr_t addr = cpu->r.i * 0x100 + 0xFF;
204 cpu->r.pc = this->mem.ram [(addr + 1) & 0xFFFF] * 0x100 + this->mem.ram [addr]; 204 cpu->r.pc = this->mem.ram [(addr + 1) & 0xFFFF] * 0x100 + this->mem.ram [addr];
205 Z80_adjust_time( cpu, 6 ); 205 Z80_adjust_time( cpu, 6 );
206 } 206 }
207 } 207 }
208 } 208 }
209 } 209 }
210 210
211 // End time frame 211 // End time frame
212 *end = Z80_time( cpu ); 212 *end = Z80_time( cpu );
213 this->next_play -= *end; 213 this->next_play -= *end;
214 check( this->next_play >= 0 ); 214 check( this->next_play >= 0 );
215 Z80_adjust_time( cpu, -*end ); 215 Z80_adjust_time( cpu, -*end );
216 Ay_apu_end_frame( &this->apu, *end ); 216 Ay_apu_end_frame( &this->apu, *end );
217 return 0; 217 return 0;
218} 218}
219 219
220// Emulation 220// Emulation
221 221
222void cpu_out_( struct Ay_Emu *this, cpu_time_t time, addr_t addr, int data ) 222void cpu_out_( struct Ay_Emu *this, cpu_time_t time, addr_t addr, int data )
223{ 223{
224 // Spectrum 224 // Spectrum
225 if ( !this->cpc_mode ) 225 if ( !this->cpc_mode )
226 { 226 {
227 switch ( addr & 0xFEFF ) 227 switch ( addr & 0xFEFF )
228 { 228 {
229 case 0xFEFD: 229 case 0xFEFD:
230 this->spectrum_mode = true; 230 this->spectrum_mode = true;
231 Ay_apu_write_addr( &this->apu, data ); 231 Ay_apu_write_addr( &this->apu, data );
232 return; 232 return;
233 233
234 case 0xBEFD: 234 case 0xBEFD:
235 this->spectrum_mode = true; 235 this->spectrum_mode = true;
236 Ay_apu_write_data( &this->apu, time, data ); 236 Ay_apu_write_data( &this->apu, time, data );
237 return; 237 return;
238 } 238 }
239 } 239 }
240 240
241 // CPC 241 // CPC
242 if ( !this->spectrum_mode ) 242 if ( !this->spectrum_mode )
243 { 243 {
244 switch ( addr >> 8 ) 244 switch ( addr >> 8 )
245 { 245 {
246 case 0xF6: 246 case 0xF6:
247 switch ( data & 0xC0 ) 247 switch ( data & 0xC0 )
248 { 248 {
249 case 0xC0: 249 case 0xC0:
250 Ay_apu_write_addr( &this->apu, this->cpc_latch ); 250 Ay_apu_write_addr( &this->apu, this->cpc_latch );
251 goto enable_cpc; 251 goto enable_cpc;
252 252
253 case 0x80: 253 case 0x80:
254 Ay_apu_write_data( &this->apu, time, this->cpc_latch ); 254 Ay_apu_write_data( &this->apu, time, this->cpc_latch );
255 goto enable_cpc; 255 goto enable_cpc;
256 } 256 }
257 break; 257 break;
258 258
259 case 0xF4: 259 case 0xF4:
260 this->cpc_latch = data; 260 this->cpc_latch = data;
261 goto enable_cpc; 261 goto enable_cpc;
262 } 262 }
263 } 263 }
264 264
265 /* dprintf( "Unmapped OUT: $%04X <- $%02X\n", addr, data ); */ 265 /* dprintf( "Unmapped OUT: $%04X <- $%02X\n", addr, data ); */
266 return; 266 return;
267 267
268enable_cpc: 268enable_cpc:
269 if ( !this->cpc_mode ) 269 if ( !this->cpc_mode )
270 { 270 {
271 this->cpc_mode = true; 271 this->cpc_mode = true;
272 disable_beeper( this ); 272 disable_beeper( this );
273 273
274 change_clock_rate( this, cpc_clock ); 274 change_clock_rate( this, cpc_clock );
275 Sound_set_tempo( this, this->tempo ); 275 Sound_set_tempo( this, this->tempo );
276 } 276 }
277} 277}
278 278
279blargg_err_t Ay_set_sample_rate( struct Ay_Emu *this, int rate ) 279blargg_err_t Ay_set_sample_rate( struct Ay_Emu *this, int rate )
280{ 280{
281 require( !this->sample_rate ); // sample rate can't be changed once set 281 require( !this->sample_rate ); // sample rate can't be changed once set
282 Buffer_init( &this->stereo_buf ); 282 Buffer_init( &this->stereo_buf );
283 RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) ); 283 RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) );
284 284
285 // Set buffer bass 285 // Set buffer bass
286 Buffer_bass_freq( &this->stereo_buf, 160 ); 286 Buffer_bass_freq( &this->stereo_buf, 160 );
287 287
288 this->sample_rate = rate; 288 this->sample_rate = rate;
289 RETURN_ERR( track_init( &this->track_filter, this ) ); 289 RETURN_ERR( track_init( &this->track_filter, this ) );
290 this->tfilter.max_silence = 6 * stereo * this->sample_rate; 290 this->tfilter.max_silence = 6 * stereo * this->sample_rate;
291 return 0; 291 return 0;
292} 292}
293 293
294void Sound_mute_voice( struct Ay_Emu *this, int index, bool mute ) 294void Sound_mute_voice( struct Ay_Emu *this, int index, bool mute )
295{ 295{
296 require( (unsigned) index < (unsigned) this->voice_count ); 296 require( (unsigned) index < (unsigned) this->voice_count );
297 int bit = 1 << index; 297 int bit = 1 << index;
298 int mask = this->mute_mask_ | bit; 298 int mask = this->mute_mask_ | bit;
299 if ( !mute ) 299 if ( !mute )
300 mask ^= bit; 300 mask ^= bit;
301 Sound_mute_voices( this, mask ); 301 Sound_mute_voices( this, mask );
302} 302}
303 303
304void Sound_mute_voices( struct Ay_Emu *this, int mask ) 304void Sound_mute_voices( struct Ay_Emu *this, int mask )
305{ 305{
306 require( this->sample_rate ); // sample rate must be set first 306 require( this->sample_rate ); // sample rate must be set first
307 this->mute_mask_ = mask; 307 this->mute_mask_ = mask;
308 308
309 int i; 309 int i;
310 for ( i = this->voice_count; i--; ) 310 for ( i = this->voice_count; i--; )
311 { 311 {
312 if ( mask & (1 << i) ) 312 if ( mask & (1 << i) )
313 { 313 {
314 set_voice( this, i, 0 ); 314 set_voice( this, i, 0 );
315 } 315 }
316 else 316 else
317 { 317 {
318 struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); 318 struct channel_t ch = Buffer_channel( &this->stereo_buf, i );
319 assert( (ch.center && ch.left && ch.right) || 319 assert( (ch.center && ch.left && ch.right) ||
320 (!ch.center && !ch.left && !ch.right) ); // all or nothing 320 (!ch.center && !ch.left && !ch.right) ); // all or nothing
321 set_voice( this, i, ch.center ); 321 set_voice( this, i, ch.center );
322 } 322 }
323 } 323 }
324} 324}
325 325
326void Sound_set_tempo( struct Ay_Emu *this, int t ) 326void Sound_set_tempo( struct Ay_Emu *this, int t )
327{ 327{
328 require( this->sample_rate ); // sample rate must be set first 328 require( this->sample_rate ); // sample rate must be set first
329 int const min = (int)(FP_ONE_TEMPO*0.02); 329 int const min = (int)(FP_ONE_TEMPO*0.02);
330 int const max = (int)(FP_ONE_TEMPO*4.00); 330 int const max = (int)(FP_ONE_TEMPO*4.00);
331 if ( t < min ) t = min; 331 if ( t < min ) t = min;
332 if ( t > max ) t = max; 332 if ( t > max ) t = max;
333 this->tempo = t; 333 this->tempo = t;
334 334
335 int p = spectrum_period; 335 int p = spectrum_period;
336 if ( this->clock_rate_ != spectrum_clock ) 336 if ( this->clock_rate_ != spectrum_clock )
337 p = this->clock_rate_ / 50; 337 p = this->clock_rate_ / 50;
338 338
339 this->play_period = (blip_time_t) ((p * FP_ONE_TEMPO) / t); 339 this->play_period = (blip_time_t) ((p * FP_ONE_TEMPO) / t);
340} 340}
341 341
342blargg_err_t Ay_start_track( struct Ay_Emu *this, int track ) 342blargg_err_t Ay_start_track( struct Ay_Emu *this, int track )
343{ 343{
344 clear_track_vars( this ); 344 clear_track_vars( this );
345 345
346 // Remap track if playlist available 346 // Remap track if playlist available
347 if ( this->m3u.size > 0 ) { 347 if ( this->m3u.size > 0 ) {
348 struct entry_t* e = &this->m3u.entries[track]; 348 struct entry_t* e = &this->m3u.entries[track];
349 track = e->track; 349 track = e->track;
350 } 350 }
351 351
352 this->current_track = track; 352 this->current_track = track;
353 Buffer_clear( &this->stereo_buf ); 353 Buffer_clear( &this->stereo_buf );
354 354
355 byte* const mem = this->mem.ram; 355 byte* const mem = this->mem.ram;
356 356
357 memset( mem + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET 357 memset( mem + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET
358 memset( mem + 0x0100, 0xFF, 0x4000 - 0x100 ); 358 memset( mem + 0x0100, 0xFF, 0x4000 - 0x100 );
359 memset( mem + ram_addr, 0x00, mem_size - ram_addr ); 359 memset( mem + ram_addr, 0x00, mem_size - ram_addr );
360 360
361 // locate data blocks 361 // locate data blocks
362 byte const* const data = get_data( &this->file, this->file.tracks + track * 4 + 2, 14 ); 362 byte const* const data = get_data( &this->file, this->file.tracks + track * 4 + 2, 14 );
363 if ( !data ) 363 if ( !data )
364 return "file data missing"; 364 return "file data missing";
365 365
366 byte const* const more_data = get_data( &this->file, data + 10, 6 ); 366 byte const* const more_data = get_data( &this->file, data + 10, 6 );
367 if ( !more_data ) 367 if ( !more_data )
368 return "file data missing"; 368 return "file data missing";
369 369
370 byte const* blocks = get_data( &this->file, data + 12, 8 ); 370 byte const* blocks = get_data( &this->file, data + 12, 8 );
371 if ( !blocks ) 371 if ( !blocks )
372 return "file data missing"; 372 return "file data missing";
373 373
374 // initial addresses 374 // initial addresses
375 unsigned addr = get_be16( blocks ); 375 unsigned addr = get_be16( blocks );
376 if ( !addr ) 376 if ( !addr )
377 return "file data missing"; 377 return "file data missing";
378 378
379 unsigned init = get_be16( more_data + 2 ); 379 unsigned init = get_be16( more_data + 2 );
380 if ( !init ) 380 if ( !init )
381 init = addr; 381 init = addr;
382 382
383 // copy blocks into memory 383 // copy blocks into memory
384 do 384 do
385 { 385 {
386 blocks += 2; 386 blocks += 2;
387 unsigned len = get_be16( blocks ); blocks += 2; 387 unsigned len = get_be16( blocks ); blocks += 2;
388 if ( addr + len > mem_size ) 388 if ( addr + len > mem_size )
389 { 389 {
390 /* warning( "Bad data block size" ); */ 390 /* warning( "Bad data block size" ); */
391 len = mem_size - addr; 391 len = mem_size - addr;
392 } 392 }
393 check( len ); 393 check( len );
394 byte const* in = get_data( &this->file, blocks, 0 ); blocks += 2; 394 byte const* in = get_data( &this->file, blocks, 0 ); blocks += 2;
395 if ( len > (unsigned) (this->file.end - in) ) 395 if ( len > (unsigned) (this->file.end - in) )
396 { 396 {
397 /* warning( "File data missing" ); */ 397 /* warning( "File data missing" ); */
398 len = this->file.end - in; 398 len = this->file.end - in;
399 } 399 }
400 400
401 memcpy( mem + addr, in, len ); 401 memcpy( mem + addr, in, len );
402 402
403 if ( this->file.end - blocks < 8 ) 403 if ( this->file.end - blocks < 8 )
404 { 404 {
405 /* warning( "File data missing" ); */ 405 /* warning( "File data missing" ); */
406 break; 406 break;
407 } 407 }
408 } 408 }
409 while ( (addr = get_be16( blocks )) != 0 ); 409 while ( (addr = get_be16( blocks )) != 0 );
410 410
411 // copy and configure driver 411 // copy and configure driver
412 static byte const passive [] = { 412 static byte const passive [] = {
413 0xF3, // DI 413 0xF3, // DI
414 0xCD, 0, 0, // CALL init 414 0xCD, 0, 0, // CALL init
415 0xED, 0x5E, // LOOP: IM 2 415 0xED, 0x5E, // LOOP: IM 2
416 0xFB, // EI 416 0xFB, // EI
417 0x76, // HALT 417 0x76, // HALT
418 0x18, 0xFA // JR LOOP 418 0x18, 0xFA // JR LOOP
419 }; 419 };
420 static byte const active [] = { 420 static byte const active [] = {
421 0xF3, // DI 421 0xF3, // DI
422 0xCD, 0, 0, // CALL init 422 0xCD, 0, 0, // CALL init
423 0xED, 0x56, // LOOP: IM 1 423 0xED, 0x56, // LOOP: IM 1
424 0xFB, // EI 424 0xFB, // EI
425 0x76, // HALT 425 0x76, // HALT
426 0xCD, 0, 0, // CALL play 426 0xCD, 0, 0, // CALL play
427 0x18, 0xF7 // JR LOOP 427 0x18, 0xF7 // JR LOOP
428 }; 428 };
429 memcpy( mem, passive, sizeof passive ); 429 memcpy( mem, passive, sizeof passive );
430 int const play_addr = get_be16( more_data + 4 ); 430 int const play_addr = get_be16( more_data + 4 );
431 if ( play_addr ) 431 if ( play_addr )
432 { 432 {
433 memcpy( mem, active, sizeof active ); 433 memcpy( mem, active, sizeof active );
434 mem [ 9] = play_addr; 434 mem [ 9] = play_addr;
435 mem [10] = play_addr >> 8; 435 mem [10] = play_addr >> 8;
436 } 436 }
437 mem [2] = init; 437 mem [2] = init;
438 mem [3] = init >> 8; 438 mem [3] = init >> 8;
439 439
440 mem [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET) 440 mem [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET)
441 441
442 // start at spectrum speed 442 // start at spectrum speed
443 change_clock_rate( this, spectrum_clock ); 443 change_clock_rate( this, spectrum_clock );
444 Sound_set_tempo( this, this->tempo ); 444 Sound_set_tempo( this, this->tempo );
445 445
446 struct registers_t r; 446 struct registers_t r;
447 memset( &r, 0, sizeof(struct registers_t) ); 447 memset( &r, 0, sizeof(struct registers_t) );
448 448
449 r.sp = get_be16( more_data ); 449 r.sp = get_be16( more_data );
450 r.b.a = r.b.b = r.b.d = r.b.h = data [8]; 450 r.b.a = r.b.b = r.b.d = r.b.h = data [8];
451 r.b.flags = r.b.c = r.b.e = r.b.l = data [9]; 451 r.b.flags = r.b.c = r.b.e = r.b.l = data [9];
452 r.alt.w = r.w; 452 r.alt.w = r.w;
453 r.ix = r.iy = r.w.hl; 453 r.ix = r.iy = r.w.hl;
454 454
455 memset( this->mem.padding1, 0xFF, sizeof this->mem.padding1 ); 455 memset( this->mem.padding1, 0xFF, sizeof this->mem.padding1 );
456 456
457 int const mirrored = 0x80; // this much is mirrored after end of memory 457 int const mirrored = 0x80; // this much is mirrored after end of memory
458 memset( this->mem.ram + mem_size + mirrored, 0xFF, sizeof this->mem.ram - mem_size - mirrored ); 458 memset( this->mem.ram + mem_size + mirrored, 0xFF, sizeof this->mem.ram - mem_size - mirrored );
459 memcpy( this->mem.ram + mem_size, this->mem.ram, mirrored ); // some code wraps around (ugh) 459 memcpy( this->mem.ram + mem_size, this->mem.ram, mirrored ); // some code wraps around (ugh)
460 460
461 Z80_reset( &this->cpu, this->mem.padding1, this->mem.padding1 ); 461 Z80_reset( &this->cpu, this->mem.padding1, this->mem.padding1 );
462 Z80_map_mem( &this->cpu, 0, mem_size, this->mem.ram, this->mem.ram ); 462 Z80_map_mem( &this->cpu, 0, mem_size, this->mem.ram, this->mem.ram );
463 this->cpu.r = r; 463 this->cpu.r = r;
464 464
465 this->beeper_delta = (int) ((ay_amp_range*4)/5); 465 this->beeper_delta = (int) ((ay_amp_range*4)/5);
466 this->last_beeper = 0; 466 this->last_beeper = 0;
467 this->next_play = this->play_period; 467 this->next_play = this->play_period;
468 this->spectrum_mode = false; 468 this->spectrum_mode = false;
469 this->cpc_mode = false; 469 this->cpc_mode = false;
470 this->cpc_latch = 0; 470 this->cpc_latch = 0;
471 set_beeper_output( this, this->beeper_output ); 471 set_beeper_output( this, this->beeper_output );
472 Ay_apu_reset( &this->apu ); 472 Ay_apu_reset( &this->apu );
473 473
474 // a few tunes rely on channels having tone enabled at the beginning 474 // a few tunes rely on channels having tone enabled at the beginning
475 Ay_apu_write_addr( &this->apu, 7 ); 475 Ay_apu_write_addr( &this->apu, 7 );
476 Ay_apu_write_data( &this->apu, 0, 0x38 ); 476 Ay_apu_write_data( &this->apu, 0, 0x38 );
477 477
478 // convert filter times to samples 478 // convert filter times to samples
479 struct setup_t s = this->tfilter; 479 struct setup_t s = this->tfilter;
480 s.max_initial *= this->sample_rate * stereo; 480 s.max_initial *= this->sample_rate * stereo;
481 #ifdef GME_DISABLE_SILENCE_LOOKAHEAD 481 #ifdef GME_DISABLE_SILENCE_LOOKAHEAD
482 s.lookahead = 1; 482 s.lookahead = 1;
483 #endif 483 #endif
484 track_setup( &this->track_filter, &s ); 484 track_setup( &this->track_filter, &s );
485 485
486 return track_start( &this->track_filter ); 486 return track_start( &this->track_filter );
487} 487}
488 488
489// Tell/Seek 489// Tell/Seek
490 490
491static int msec_to_samples( int msec, int sample_rate ) 491static int msec_to_samples( int msec, int sample_rate )
492{ 492{
493 int sec = msec / 1000; 493 int sec = msec / 1000;
494 msec -= sec * 1000; 494 msec -= sec * 1000;
495 return (sec * sample_rate + msec * sample_rate / 1000) * stereo; 495 return (sec * sample_rate + msec * sample_rate / 1000) * stereo;
496} 496}
497 497
498int Track_tell( struct Ay_Emu *this ) 498int Track_tell( struct Ay_Emu *this )
499{ 499{
500 int rate = this->sample_rate * stereo; 500 int rate = this->sample_rate * stereo;
501 int sec = track_sample_count( &this->track_filter ) / rate; 501 int sec = track_sample_count( &this->track_filter ) / rate;
502 return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; 502 return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate;
503} 503}
504 504
505blargg_err_t Track_seek( struct Ay_Emu *this, int msec ) 505blargg_err_t Track_seek( struct Ay_Emu *this, int msec )
506{ 506{
507 int time = msec_to_samples( msec, this->sample_rate ); 507 int time = msec_to_samples( msec, this->sample_rate );
508 if ( time < track_sample_count( &this->track_filter ) ) 508 if ( time < track_sample_count( &this->track_filter ) )
509 RETURN_ERR( Ay_start_track( this, this->current_track ) ); 509 RETURN_ERR( Ay_start_track( this, this->current_track ) );
510 return Track_skip( this, time - track_sample_count( &this->track_filter ) ); 510 return Track_skip( this, time - track_sample_count( &this->track_filter ) );
511} 511}
512 512
513blargg_err_t skip_( void *emu, int count ) 513blargg_err_t skip_( void *emu, int count )
514{ 514{
515 struct Ay_Emu* this = (struct Ay_Emu*) emu; 515 struct Ay_Emu* this = (struct Ay_Emu*) emu;
516 516
517 // for long skip, mute sound 517 // for long skip, mute sound
518 const int threshold = 32768; 518 const int threshold = 32768;
519 if ( count > threshold ) 519 if ( count > threshold )
520 { 520 {
521 int saved_mute = this->mute_mask_; 521 int saved_mute = this->mute_mask_;
522 Sound_mute_voices( this, ~0 ); 522 Sound_mute_voices( this, ~0 );
523 523
524 int n = count - threshold/2; 524 int n = count - threshold/2;
525 n &= ~(2048-1); // round to multiple of 2048 525 n &= ~(2048-1); // round to multiple of 2048
526 count -= n; 526 count -= n;
527 RETURN_ERR( skippy_( &this->track_filter, n ) ); 527 RETURN_ERR( skippy_( &this->track_filter, n ) );
528 528
529 Sound_mute_voices( this, saved_mute ); 529 Sound_mute_voices( this, saved_mute );
530 } 530 }
531 531
532 return skippy_( &this->track_filter, count ); 532 return skippy_( &this->track_filter, count );
533} 533}
534 534
535blargg_err_t Track_skip( struct Ay_Emu *this, int count ) 535blargg_err_t Track_skip( struct Ay_Emu *this, int count )
536{ 536{
537 require( this->current_track >= 0 ); // start_track() must have been called already 537 require( this->current_track >= 0 ); // start_track() must have been called already
538 return track_skip( &this->track_filter, count ); 538 return track_skip( &this->track_filter, count );
539} 539}
540 540
541int Track_get_length( struct Ay_Emu* this, int n ) 541int Track_get_length( struct Ay_Emu* this, int n )
542{ 542{
543 int length = 0; 543 int length = 0;
544 544
545 byte const* track_info = get_data( &this->file, this->file.tracks + n * 4 + 2, 6 ); 545 byte const* track_info = get_data( &this->file, this->file.tracks + n * 4 + 2, 6 );
546 if ( track_info ) 546 if ( track_info )
547 length = get_be16( track_info + 4 ) * (1000 / 50); // frames to msec 547 length = get_be16( track_info + 4 ) * (1000 / 50); // frames to msec
548 548
549 if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { 549 if ( (this->m3u.size > 0) && (n < this->m3u.size) ) {
550 struct entry_t* entry = &this->m3u.entries [n]; 550 struct entry_t* entry = &this->m3u.entries [n];
551 length = entry->length; 551 length = entry->length;
552 } 552 }
553 553
554 if ( length <= 0 ) 554 if ( length <= 0 )
555 length = 120 * 1000; /* 2 minutes */ 555 length = 120 * 1000; /* 2 minutes */
556 556
557 return length; 557 return length;
558} 558}
559 559
560void Track_set_fade( struct Ay_Emu *this, int start_msec, int length_msec ) 560void Track_set_fade( struct Ay_Emu *this, int start_msec, int length_msec )
561{ 561{
562 track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), 562 track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ),
563 length_msec * this->sample_rate / (1000 / stereo) ); 563 length_msec * this->sample_rate / (1000 / stereo) );
564} 564}
565 565
566blargg_err_t Ay_play( struct Ay_Emu *this, int out_count, sample_t* out ) 566blargg_err_t Ay_play( struct Ay_Emu *this, int out_count, sample_t* out )
567{ 567{
568 require( this->current_track >= 0 ); 568 require( this->current_track >= 0 );
569 require( out_count % stereo == 0 ); 569 require( out_count % stereo == 0 );
570 return track_play( &this->track_filter, out_count, out ); 570 return track_play( &this->track_filter, out_count, out );
571} 571}
572 572
573blargg_err_t play_( void *emu, int count, sample_t* out ) 573blargg_err_t play_( void *emu, int count, sample_t* out )
574{ 574{
575 struct Ay_Emu* this = (struct Ay_Emu*) emu; 575 struct Ay_Emu* this = (struct Ay_Emu*) emu;
576 576
577 int remain = count; 577 int remain = count;
578 while ( remain ) 578 while ( remain )
579 { 579 {
580 Buffer_disable_immediate_removal( &this->stereo_buf ); 580 Buffer_disable_immediate_removal( &this->stereo_buf );
581 remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); 581 remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain );
582 if ( remain ) 582 if ( remain )
583 { 583 {
584 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) 584 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) )
585 { 585 {
586 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); 586 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
587 587
588 // Remute voices 588 // Remute voices
589 Sound_mute_voices( this, this->mute_mask_ ); 589 Sound_mute_voices( this, this->mute_mask_ );
590 } 590 }
591 int msec = Buffer_length( &this->stereo_buf ); 591 int msec = Buffer_length( &this->stereo_buf );
592 blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; 592 blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100;
593 RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); 593 RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) );
594 assert( clocks_emulated ); 594 assert( clocks_emulated );
595 Buffer_end_frame( &this->stereo_buf, clocks_emulated ); 595 Buffer_end_frame( &this->stereo_buf, clocks_emulated );
596 } 596 }
597 } 597 }
598 return 0; 598 return 0;
599} 599}