diff options
author | Torne Wuff <torne@wolfpuppy.org.uk> | 2011-11-06 22:44:25 +0000 |
---|---|---|
committer | Torne Wuff <torne@wolfpuppy.org.uk> | 2011-11-06 22:44:25 +0000 |
commit | 569285794b9112f0134ddad4bb886308ea4a7be6 (patch) | |
tree | ce702cb07829820261a682c471133c76d11c610e /apps/codecs/libgme/ay_emu.c | |
parent | d9b7d58fa6c9ceb136bea429adf6746cc7138208 (diff) | |
download | rockbox-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.c | 1198 |
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 |
8 | can redistribute it and/or modify it under the terms of the GNU Lesser | 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 | 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 | 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 | 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 | 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 | 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 | 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, | 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 */ | 16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
17 | 17 | ||
18 | #include "blargg_source.h" | 18 | #include "blargg_source.h" |
19 | 19 | ||
20 | const char* const gme_wrong_file_type = "Wrong file type for this emulator"; | 20 | const 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 | ||
24 | int const spectrum_clock = 3546900; // 128K Spectrum | 24 | int const spectrum_clock = 3546900; // 128K Spectrum |
25 | int const spectrum_period = 70908; | 25 | int 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 | ||
30 | int const cpc_clock = 2000000; | 30 | int const cpc_clock = 2000000; |
31 | 31 | ||
32 | static void clear_track_vars( struct Ay_Emu *this ) | 32 | static 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 | ||
38 | void Ay_init( struct Ay_Emu *this ) | 38 | void 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. |
68 | static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size ) | 68 | static 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 | ||
80 | static blargg_err_t parse_header( byte const in [], int size, struct file_t* out ) | 80 | static 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 | ||
100 | static void change_clock_rate( struct Ay_Emu *this, int rate ) | 100 | static 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 | ||
106 | blargg_err_t Ay_load_mem( struct Ay_Emu *this, byte const in [], long size ) | 106 | blargg_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 | ||
141 | static void set_beeper_output( struct Ay_Emu *this, struct Blip_Buffer* b ) | 141 | static 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 | ||
150 | static void set_voice( struct Ay_Emu *this, int i, struct Blip_Buffer* center ) | 150 | static 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 | ||
158 | static blargg_err_t run_clocks( struct Ay_Emu *this, blip_time_t* duration, int msec ) | 158 | static 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 | ||
222 | void cpu_out_( struct Ay_Emu *this, cpu_time_t time, addr_t addr, int data ) | 222 | void 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 | ||
268 | enable_cpc: | 268 | enable_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 | ||
279 | blargg_err_t Ay_set_sample_rate( struct Ay_Emu *this, int rate ) | 279 | blargg_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 | ||
294 | void Sound_mute_voice( struct Ay_Emu *this, int index, bool mute ) | 294 | void 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 | ||
304 | void Sound_mute_voices( struct Ay_Emu *this, int mask ) | 304 | void 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 | ||
326 | void Sound_set_tempo( struct Ay_Emu *this, int t ) | 326 | void 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 | ||
342 | blargg_err_t Ay_start_track( struct Ay_Emu *this, int track ) | 342 | blargg_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 | ||
491 | static int msec_to_samples( int msec, int sample_rate ) | 491 | static 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 | ||
498 | int Track_tell( struct Ay_Emu *this ) | 498 | int 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 | ||
505 | blargg_err_t Track_seek( struct Ay_Emu *this, int msec ) | 505 | blargg_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 | ||
513 | blargg_err_t skip_( void *emu, int count ) | 513 | blargg_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 | ||
535 | blargg_err_t Track_skip( struct Ay_Emu *this, int count ) | 535 | blargg_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 | ||
541 | int Track_get_length( struct Ay_Emu* this, int n ) | 541 | int 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 | ||
560 | void Track_set_fade( struct Ay_Emu *this, int start_msec, int length_msec ) | 560 | void 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 | ||
566 | blargg_err_t Ay_play( struct Ay_Emu *this, int out_count, sample_t* out ) | 566 | blargg_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 | ||
573 | blargg_err_t play_( void *emu, int count, sample_t* out ) | 573 | blargg_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 | } |