1 /* tape_block.c: one tape block
2 Copyright (c) 2003-2008 Philip Kendall
3
4 $Id: tape_block.c 4433 2011-05-14 05:44:47Z fredm $
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 Author contact information:
21
22 E-mail: philip-fuse@shadowmagic.org.uk
23
24 */
25
26 #include <config.h>
27
28 #include <math.h>
29
30 #include "tape_block.h"
31
32 /* The number of pilot pulses for the standard ROM loader NB: These
33 disagree with the .tzx specification (they're 5 and 1 less
34 respectively), but are correct. Entering the loop at #04D8 in the
35 48K ROM with HL == #0001 will produce the first sync pulse, not a
36 pilot pulse, which gives a difference of one in both cases. The
37 further difference of 4 in the header count is just a screw-up in
38 the .tzx specification AFAICT */
39 static const size_t LIBSPECTRUM_TAPE_PILOTS_HEADER = 0x1f7f;
40 static const size_t LIBSPECTRUM_TAPE_PILOTS_DATA = 0x0c97;
41
42 /* Functions to initialise block types */
43
44 static libspectrum_error
45 rom_init( libspectrum_tape_rom_block *block,
46 libspectrum_tape_rom_block_state *state );
47 static libspectrum_error
48 turbo_init( libspectrum_tape_turbo_block *block,
49 libspectrum_tape_turbo_block_state *state );
50 static libspectrum_error
51 pure_data_init( libspectrum_tape_pure_data_block *block,
52 libspectrum_tape_pure_data_block_state *state );
53 static void
54 raw_data_init( libspectrum_tape_raw_data_block *block,
55 libspectrum_tape_raw_data_block_state *state );
56 static libspectrum_error
57 generalised_data_init( libspectrum_tape_generalised_data_block *block,
58 libspectrum_tape_generalised_data_block_state *state );
59 static libspectrum_error
60 data_block_init( libspectrum_tape_data_block *block,
61 libspectrum_tape_data_block_state *state );
62
63 libspectrum_tape_block*
libspectrum_tape_block_alloc(libspectrum_tape_type type)64 libspectrum_tape_block_alloc( libspectrum_tape_type type )
65 {
66 libspectrum_tape_block *block = libspectrum_malloc( sizeof( *block ) );
67 libspectrum_tape_block_set_type( block, type );
68 return block;
69 }
70
71 static void
free_symbol_table(libspectrum_tape_generalised_data_symbol_table * table)72 free_symbol_table( libspectrum_tape_generalised_data_symbol_table *table )
73 {
74 size_t i;
75
76 if( table->symbols ) {
77 for( i = 0; i < table->symbols_in_table; i++ )
78 libspectrum_free( table->symbols[ i ].lengths );
79
80 libspectrum_free( table->symbols );
81 }
82 }
83
84 /* Free the memory used by one block */
85 libspectrum_error
libspectrum_tape_block_free(libspectrum_tape_block * block)86 libspectrum_tape_block_free( libspectrum_tape_block *block )
87 {
88 size_t i;
89
90 switch( block->type ) {
91
92 case LIBSPECTRUM_TAPE_BLOCK_ROM:
93 libspectrum_free( block->types.rom.data );
94 break;
95 case LIBSPECTRUM_TAPE_BLOCK_TURBO:
96 libspectrum_free( block->types.turbo.data );
97 break;
98 case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
99 break;
100 case LIBSPECTRUM_TAPE_BLOCK_PULSES:
101 libspectrum_free( block->types.pulses.lengths );
102 break;
103 case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
104 libspectrum_free( block->types.pure_data.data );
105 break;
106 case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
107 libspectrum_free( block->types.raw_data.data );
108 break;
109 case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
110 free_symbol_table( &block->types.generalised_data.pilot_table );
111 free_symbol_table( &block->types.generalised_data.data_table );
112 libspectrum_free( block->types.generalised_data.pilot_symbols );
113 libspectrum_free( block->types.generalised_data.pilot_repeats );
114 libspectrum_free( block->types.generalised_data.data );
115 break;
116
117 case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
118 break;
119 case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
120 libspectrum_free( block->types.group_start.name );
121 break;
122 case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
123 break;
124 case LIBSPECTRUM_TAPE_BLOCK_JUMP:
125 break;
126 case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
127 break;
128 case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
129 break;
130
131 case LIBSPECTRUM_TAPE_BLOCK_SELECT:
132 for( i=0; i<block->types.select.count; i++ ) {
133 libspectrum_free( block->types.select.descriptions[i] );
134 }
135 libspectrum_free( block->types.select.descriptions );
136 libspectrum_free( block->types.select.offsets );
137 break;
138
139 case LIBSPECTRUM_TAPE_BLOCK_STOP48:
140 break;
141
142 case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
143 break;
144
145 case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
146 libspectrum_free( block->types.comment.text );
147 break;
148 case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
149 libspectrum_free( block->types.message.text );
150 break;
151 case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
152 for( i=0; i<block->types.archive_info.count; i++ ) {
153 libspectrum_free( block->types.archive_info.strings[i] );
154 }
155 libspectrum_free( block->types.archive_info.ids );
156 libspectrum_free( block->types.archive_info.strings );
157 break;
158 case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
159 libspectrum_free( block->types.hardware.types );
160 libspectrum_free( block->types.hardware.ids );
161 libspectrum_free( block->types.hardware.values );
162 break;
163
164 case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
165 libspectrum_free( block->types.custom.description );
166 libspectrum_free( block->types.custom.data );
167 break;
168
169 /* Block types not present in .tzx follow here */
170
171 case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
172 libspectrum_free( block->types.rle_pulse.data );
173 break;
174
175 case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
176 libspectrum_free( block->types.pulse_sequence.lengths );
177 libspectrum_free( block->types.pulse_sequence.pulse_repeats );
178 break;
179
180 case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
181 libspectrum_free( block->types.data_block.data );
182 libspectrum_free( block->types.data_block.bit0_pulses );
183 libspectrum_free( block->types.data_block.bit1_pulses );
184 break;
185
186 case LIBSPECTRUM_TAPE_BLOCK_CONCAT: /* This should never occur */
187 default:
188 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
189 "%s: unknown block type %d", __func__,
190 block->type );
191 return LIBSPECTRUM_ERROR_LOGIC;
192 }
193
194 libspectrum_free( block );
195
196 return LIBSPECTRUM_ERROR_NONE;
197 }
198
199 libspectrum_tape_type
libspectrum_tape_block_type(libspectrum_tape_block * block)200 libspectrum_tape_block_type( libspectrum_tape_block *block )
201 {
202 return block->type;
203 }
204
205 libspectrum_error
libspectrum_tape_block_set_type(libspectrum_tape_block * block,libspectrum_tape_type type)206 libspectrum_tape_block_set_type( libspectrum_tape_block *block,
207 libspectrum_tape_type type )
208 {
209 block->type = type;
210 return LIBSPECTRUM_ERROR_NONE;
211 }
212
213 /* Called when a new block is started to initialise its internal state */
214 libspectrum_error
libspectrum_tape_block_init(libspectrum_tape_block * block,libspectrum_tape_block_state * state)215 libspectrum_tape_block_init( libspectrum_tape_block *block,
216 libspectrum_tape_block_state *state )
217 {
218 if( !block ) return LIBSPECTRUM_ERROR_NONE;
219
220 switch( libspectrum_tape_block_type( block ) ) {
221
222 case LIBSPECTRUM_TAPE_BLOCK_ROM:
223 return rom_init( &(block->types.rom), &(state->block_state.rom) );
224 case LIBSPECTRUM_TAPE_BLOCK_TURBO:
225 return turbo_init( &(block->types.turbo), &(state->block_state.turbo) );
226 case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
227 state->block_state.pure_tone.edge_count = block->types.pure_tone.pulses;
228 break;
229 case LIBSPECTRUM_TAPE_BLOCK_PULSES:
230 state->block_state.pulses.edge_count = 0;
231 break;
232 case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
233 return pure_data_init( &(block->types.pure_data),
234 &(state->block_state.pure_data) );
235 case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
236 raw_data_init( &(block->types.raw_data), &(state->block_state.raw_data) );
237 return LIBSPECTRUM_ERROR_NONE;
238 case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
239 return generalised_data_init( &(block->types.generalised_data),
240 &(state->block_state.generalised_data) );
241 case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
242 state->block_state.rle_pulse.index = 0;
243 return LIBSPECTRUM_ERROR_NONE;
244 case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
245 state->block_state.pulse_sequence.index = 0;
246 state->block_state.pulse_sequence.pulse_count = 0;
247 state->block_state.pulse_sequence.level = 1;
248 return LIBSPECTRUM_ERROR_NONE;
249 case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
250 return data_block_init( &(block->types.data_block),
251 &(state->block_state.data_block) );
252
253 /* These blocks need no initialisation */
254 case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
255 case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
256 case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
257 case LIBSPECTRUM_TAPE_BLOCK_JUMP:
258 case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
259 case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
260 case LIBSPECTRUM_TAPE_BLOCK_SELECT:
261 case LIBSPECTRUM_TAPE_BLOCK_STOP48:
262 case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
263 case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
264 case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
265 case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
266 case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
267 case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
268 return LIBSPECTRUM_ERROR_NONE;
269
270 default:
271 libspectrum_print_error(
272 LIBSPECTRUM_ERROR_LOGIC,
273 "libspectrum_tape_init_block: unknown block type 0x%02x",
274 block->type
275 );
276 return LIBSPECTRUM_ERROR_LOGIC;
277 }
278
279 return LIBSPECTRUM_ERROR_NONE;
280 }
281
282 static libspectrum_error
rom_init(libspectrum_tape_rom_block * block,libspectrum_tape_rom_block_state * state)283 rom_init( libspectrum_tape_rom_block *block,
284 libspectrum_tape_rom_block_state *state )
285 {
286 /* Initialise the number of pilot pulses */
287 state->edge_count = block->length && block->data[0] & 0x80 ?
288 LIBSPECTRUM_TAPE_PILOTS_DATA :
289 LIBSPECTRUM_TAPE_PILOTS_HEADER;
290
291 /* And that we're just before the start of the data */
292 state->bytes_through_block = -1; state->bits_through_byte = 7;
293 state->state = LIBSPECTRUM_TAPE_STATE_PILOT;
294
295 return LIBSPECTRUM_ERROR_NONE;
296 }
297
298 static libspectrum_error
turbo_init(libspectrum_tape_turbo_block * block,libspectrum_tape_turbo_block_state * state)299 turbo_init( libspectrum_tape_turbo_block *block,
300 libspectrum_tape_turbo_block_state *state )
301 {
302 /* Initialise the number of pilot pulses */
303 state->edge_count = block->pilot_pulses;
304
305 /* And that we're just before the start of the data */
306 state->bytes_through_block = -1; state->bits_through_byte = 7;
307 state->state = LIBSPECTRUM_TAPE_STATE_PILOT;
308
309 return LIBSPECTRUM_ERROR_NONE;
310 }
311
312 static libspectrum_error
pure_data_init(libspectrum_tape_pure_data_block * block,libspectrum_tape_pure_data_block_state * state)313 pure_data_init( libspectrum_tape_pure_data_block *block,
314 libspectrum_tape_pure_data_block_state *state )
315 {
316 libspectrum_error error;
317
318 /* We're just before the start of the data */
319 state->bytes_through_block = -1; state->bits_through_byte = 7;
320 /* Set up the next bit */
321 error = libspectrum_tape_pure_data_next_bit( block, state );
322 if( error ) return error;
323
324 return LIBSPECTRUM_ERROR_NONE;
325 }
326
327 static void
raw_data_init(libspectrum_tape_raw_data_block * block,libspectrum_tape_raw_data_block_state * state)328 raw_data_init( libspectrum_tape_raw_data_block *block,
329 libspectrum_tape_raw_data_block_state *state )
330 {
331 if( block->data ) {
332
333 /* We're just before the start of the data */
334 state->state = LIBSPECTRUM_TAPE_STATE_DATA1;
335 state->bytes_through_block = -1; state->bits_through_byte = 7;
336 state->last_bit = 0x80 & block->data[0];
337 /* Set up the next bit */
338 libspectrum_tape_raw_data_next_bit( block, state );
339
340 } else {
341
342 state->state = LIBSPECTRUM_TAPE_STATE_PAUSE;
343
344 }
345 }
346
347 static libspectrum_error
generalised_data_init(libspectrum_tape_generalised_data_block * block,libspectrum_tape_generalised_data_block_state * state)348 generalised_data_init( libspectrum_tape_generalised_data_block *block,
349 libspectrum_tape_generalised_data_block_state *state )
350 {
351 state->state = LIBSPECTRUM_TAPE_STATE_PILOT;
352
353 state->run = 0;
354 state->symbols_through_run = 0;
355 state->edges_through_symbol = 0;
356
357 return LIBSPECTRUM_ERROR_NONE;
358 }
359
360 static libspectrum_error
data_block_init(libspectrum_tape_data_block * block,libspectrum_tape_data_block_state * state)361 data_block_init( libspectrum_tape_data_block *block,
362 libspectrum_tape_data_block_state *state )
363 {
364 libspectrum_error error;
365
366 state->bit0_flags = 0;
367 state->bit1_flags = 0;
368
369 /* If both bit0 and bit1 are two matching pulses, then assign them to be
370 flagged as short/long pulses respectively */
371 if( block->bit0_pulse_count == 2 && block->bit1_pulse_count == 2 &&
372 block->bit0_pulses[ 0 ] == block->bit0_pulses[ 1 ] &&
373 block->bit1_pulses[ 0 ] == block->bit1_pulses[ 1 ] &&
374 block->bit0_pulses[ 0 ] > 0 && block->bit1_pulses[ 0 ] > 0 ) {
375 if( block->bit0_pulses[ 0 ] < block->bit1_pulses[ 0 ] ) {
376 state->bit0_flags = LIBSPECTRUM_TAPE_FLAGS_LENGTH_SHORT;
377 state->bit1_flags = LIBSPECTRUM_TAPE_FLAGS_LENGTH_LONG;
378 } else if( block->bit0_pulses[ 0 ] > block->bit1_pulses[ 0 ] ) {
379 state->bit0_flags = LIBSPECTRUM_TAPE_FLAGS_LENGTH_LONG;
380 state->bit1_flags = LIBSPECTRUM_TAPE_FLAGS_LENGTH_SHORT;
381 }
382 }
383
384 state->level = block->initial_level;
385
386 /* We're just before the start of the data */
387 state->bytes_through_block = -1; state->bits_through_byte = 7;
388 /* Set up the next bit */
389 error = libspectrum_tape_data_block_next_bit( block, state );
390 if( error ) return error;
391
392 return LIBSPECTRUM_ERROR_NONE;
393 }
394
395 /* Does this block consist solely of metadata? */
396 int
libspectrum_tape_block_metadata(libspectrum_tape_block * block)397 libspectrum_tape_block_metadata( libspectrum_tape_block *block )
398 {
399 switch( block->type ) {
400 case LIBSPECTRUM_TAPE_BLOCK_ROM:
401 case LIBSPECTRUM_TAPE_BLOCK_TURBO:
402 case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
403 case LIBSPECTRUM_TAPE_BLOCK_PULSES:
404 case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
405 case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
406 case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
407 case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
408 case LIBSPECTRUM_TAPE_BLOCK_JUMP:
409 case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
410 case LIBSPECTRUM_TAPE_BLOCK_SELECT:
411 case LIBSPECTRUM_TAPE_BLOCK_STOP48:
412 case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
413 case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
414 case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
415 case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
416 return 0;
417
418 case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
419 case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
420 case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
421 case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
422 case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
423 case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
424 case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
425 case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
426 case LIBSPECTRUM_TAPE_BLOCK_CONCAT:
427 return 1;
428 }
429
430 /* Should never happen */
431 return -1;
432 }
433
434 libspectrum_error
libspectrum_tape_block_read_symbol_table_parameters(libspectrum_tape_block * block,int pilot,const libspectrum_byte ** ptr)435 libspectrum_tape_block_read_symbol_table_parameters(
436 libspectrum_tape_block *block, int pilot, const libspectrum_byte **ptr )
437 {
438 libspectrum_tape_generalised_data_block *generalised =
439 &block->types.generalised_data;
440
441 libspectrum_tape_generalised_data_symbol_table *table =
442 pilot ? &generalised->pilot_table : &generalised->data_table;
443
444 table->symbols_in_block = libspectrum_read_dword( ptr );
445 table->max_pulses = (*ptr)[0];
446
447 table->symbols_in_table = (*ptr)[1];
448 if( !table->symbols_in_table ) table->symbols_in_table = 256;
449
450 (*ptr) += 2;
451
452 return LIBSPECTRUM_ERROR_NONE;
453 }
454
455 libspectrum_error
libspectrum_tape_block_read_symbol_table(libspectrum_tape_generalised_data_symbol_table * table,const libspectrum_byte ** ptr,size_t length)456 libspectrum_tape_block_read_symbol_table(
457 libspectrum_tape_generalised_data_symbol_table *table,
458 const libspectrum_byte **ptr, size_t length )
459 {
460 if( table->symbols_in_block ) {
461
462 libspectrum_tape_generalised_data_symbol *symbol;
463 size_t i, j;
464
465 /* Sanity check */
466 if( length < ( 2 * table->max_pulses + 1 ) * table->symbols_in_table ) {
467 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
468 "%s: not enough data in buffer", __func__ );
469 return LIBSPECTRUM_ERROR_CORRUPT;
470 }
471
472
473 table->symbols = libspectrum_malloc( table->symbols_in_table * sizeof( *table->symbols ) );
474
475 for( i = 0, symbol = table->symbols;
476 i < table->symbols_in_table;
477 i++, symbol++ ) {
478 symbol->edge_type = **ptr; (*ptr)++;
479 symbol->lengths = libspectrum_malloc( table->max_pulses * sizeof( *symbol->lengths ) );
480 for( j = 0; j < table->max_pulses; j++ ) {
481 symbol->lengths[ j ] = (*ptr)[0] + (*ptr)[1] * 0x100;
482 (*ptr) += 2;
483 }
484 }
485
486 }
487
488 return LIBSPECTRUM_ERROR_NONE;
489 }
490
491 void
libspectrum_tape_block_zero(libspectrum_tape_block * block)492 libspectrum_tape_block_zero( libspectrum_tape_block *block )
493 {
494 switch( block->type ) {
495 case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
496 block->types.generalised_data.pilot_table.symbols = NULL;
497 block->types.generalised_data.data_table.symbols = NULL;
498 block->types.generalised_data.pilot_symbols = NULL;
499 block->types.generalised_data.pilot_repeats = NULL;
500 block->types.generalised_data.data = NULL;
501 break;
502 default:
503 break;
504 }
505 }
506
507 /* Give the length of a tape block */
508
509 #define BITS_SET_ARRAY_SIZE 256
510 static int bits_set[ BITS_SET_ARRAY_SIZE ];
511
512 const int LIBSPECTRUM_BITS_IN_BYTE = 8;
513
514 static int
libspectrum_bits_set_n_bits(libspectrum_byte byte,libspectrum_byte bits)515 libspectrum_bits_set_n_bits( libspectrum_byte byte, libspectrum_byte bits )
516 {
517 int i;
518 int retval = 0;
519
520 if( bits > LIBSPECTRUM_BITS_IN_BYTE) bits = LIBSPECTRUM_BITS_IN_BYTE;
521
522 for( i = 0; i < bits; i++ ) {
523 if( byte & 0x80 ) retval++;
524 byte <<= 1;
525 }
526
527 return retval;
528 }
529
530 void
libspectrum_init_bits_set(void)531 libspectrum_init_bits_set( void )
532 {
533 int i;
534
535 /* Not big or clever, but easy to understand */
536 for( i = 0; i < BITS_SET_ARRAY_SIZE; i++ ) {
537 bits_set[ i ] = libspectrum_bits_set_n_bits( (libspectrum_byte)i,
538 LIBSPECTRUM_BITS_IN_BYTE );
539 }
540 }
541
542 static libspectrum_dword
convert_pulses_to_tstates(libspectrum_dword set_bit_length,libspectrum_dword unset_bit_length,int bits_set_in_block,int bit_block_size)543 convert_pulses_to_tstates( libspectrum_dword set_bit_length,
544 libspectrum_dword unset_bit_length,
545 int bits_set_in_block, int bit_block_size )
546 {
547 static const int pulses_in_bit = 2;
548 return ( pulses_in_bit * set_bit_length ) * bits_set_in_block +
549 ( pulses_in_bit * unset_bit_length ) * ( bit_block_size - bits_set_in_block );
550 }
551
552 static libspectrum_dword
rom_block_length(libspectrum_tape_rom_block * rom)553 rom_block_length( libspectrum_tape_rom_block *rom )
554 {
555 libspectrum_dword length = rom->pause_tstates;
556 size_t i;
557
558 size_t edge_count = rom->length && rom->data[0] & 0x80 ?
559 LIBSPECTRUM_TAPE_PILOTS_DATA :
560 LIBSPECTRUM_TAPE_PILOTS_HEADER;
561 length += LIBSPECTRUM_TAPE_TIMING_PILOT * edge_count;
562 length += LIBSPECTRUM_TAPE_TIMING_SYNC1;
563 length += LIBSPECTRUM_TAPE_TIMING_SYNC2;
564
565 for( i = 0; i < rom->length; i++ ) {
566 libspectrum_byte data = rom->data[ i ];
567 length += convert_pulses_to_tstates( LIBSPECTRUM_TAPE_TIMING_DATA1,
568 LIBSPECTRUM_TAPE_TIMING_DATA0,
569 bits_set[ data ],
570 LIBSPECTRUM_BITS_IN_BYTE );
571 }
572
573 return length;
574 }
575
576 static libspectrum_dword
turbo_block_length(libspectrum_tape_turbo_block * turbo)577 turbo_block_length( libspectrum_tape_turbo_block *turbo )
578 {
579 libspectrum_dword length =
580 turbo->pilot_pulses * turbo->pilot_length +
581 turbo->sync1_length + turbo->sync2_length +
582 turbo->pause_tstates;
583 size_t i;
584 if( turbo->length ) {
585 int bits_set_in_last_byte =
586 libspectrum_bits_set_n_bits( turbo->data[ turbo->length-1 ],
587 turbo->bits_in_last_byte );
588
589 for( i = 0; i < turbo->length-1; i++ ) {
590 libspectrum_byte data = turbo->data[ i ];
591 length += convert_pulses_to_tstates( turbo->bit1_length,
592 turbo->bit0_length,
593 bits_set[ data ],
594 LIBSPECTRUM_BITS_IN_BYTE );
595 }
596
597 /* handle bits in last byte correctly */
598 length += convert_pulses_to_tstates( turbo->bit1_length,
599 turbo->bit0_length,
600 bits_set_in_last_byte,
601 turbo->bits_in_last_byte );
602 }
603
604 return length;
605 }
606
607 static libspectrum_dword
pulses_block_length(libspectrum_tape_pulses_block * pulses)608 pulses_block_length( libspectrum_tape_pulses_block *pulses )
609 {
610 libspectrum_dword length = 0;
611 size_t i;
612
613 for( i = 0; i < pulses->count; i++ ) length += pulses->lengths[ i ];
614
615 return length;
616 }
617
618 static libspectrum_dword
pure_data_block_length(libspectrum_tape_pure_data_block * pure_data)619 pure_data_block_length( libspectrum_tape_pure_data_block *pure_data )
620 {
621 libspectrum_dword length = pure_data->pause_tstates;
622 size_t i;
623 if( pure_data->length ) {
624 int bits_set_in_last_byte =
625 libspectrum_bits_set_n_bits( pure_data->data[ pure_data->length-1 ],
626 pure_data->bits_in_last_byte );
627
628 for( i = 0; i < pure_data->length-1; i++ ) {
629 libspectrum_byte data = pure_data->data[ i ];
630 length += convert_pulses_to_tstates( pure_data->bit1_length,
631 pure_data->bit0_length,
632 bits_set[ data ],
633 LIBSPECTRUM_BITS_IN_BYTE );
634 }
635
636 /* handle bits in last byte correctly */
637 length += convert_pulses_to_tstates( pure_data->bit1_length,
638 pure_data->bit0_length,
639 bits_set_in_last_byte,
640 pure_data->bits_in_last_byte );
641 }
642
643 return length;
644 }
645
646 static libspectrum_dword
raw_data_block_length(libspectrum_tape_raw_data_block * raw_data)647 raw_data_block_length( libspectrum_tape_raw_data_block *raw_data )
648 {
649 libspectrum_dword length = raw_data->pause_tstates;
650
651 length += ( LIBSPECTRUM_BITS_IN_BYTE * raw_data->length -
652 ( LIBSPECTRUM_BITS_IN_BYTE - raw_data->bits_in_last_byte ) ) *
653 raw_data->bit_length;
654
655 return length;
656 }
657
658 static libspectrum_dword
rle_pulse_block_length(libspectrum_tape_rle_pulse_block * rle_pulse)659 rle_pulse_block_length( libspectrum_tape_rle_pulse_block *rle_pulse )
660 {
661 libspectrum_dword length = 0;
662 size_t i;
663
664 for( i = 0; i < rle_pulse->length; i++ ) {
665 length += rle_pulse->data[ i ] * rle_pulse->scale;
666 }
667
668 return length;
669 }
670
671 static libspectrum_dword
generalised_data_block_length(libspectrum_tape_generalised_data_block * generalised_data)672 generalised_data_block_length(
673 libspectrum_tape_generalised_data_block *generalised_data )
674 {
675 libspectrum_dword length = 0;
676 libspectrum_tape_generalised_data_block_state state;
677 libspectrum_dword tstates = 0;
678 /* Assume no special flags by default */
679 int flags = 0;
680 /* Has this edge ended the block? */
681 int end_of_block = 0;
682 libspectrum_error error = generalised_data_init( generalised_data, &state );
683
684 if( error ) return -1;
685
686 /* just reuse tape iteration for this as it is so nasty */
687 while( !end_of_block ) {
688 error = generalised_data_edge( generalised_data, &state, &tstates,
689 &end_of_block, &flags );
690 if( error ) return -1;
691
692 length += tstates;
693 }
694
695 return length;
696 }
697
698 static libspectrum_dword
pulse_sequence_block_length(libspectrum_tape_pulse_sequence_block * pulses)699 pulse_sequence_block_length(
700 libspectrum_tape_pulse_sequence_block *pulses )
701 {
702 libspectrum_dword length = 0;
703 size_t i;
704
705 for( i = 0; i < pulses->count; i++ )
706 length += pulses->lengths[ i ] * pulses->pulse_repeats[ i ];
707
708 return length;
709 }
710
711 static libspectrum_dword
data_block_length(libspectrum_tape_data_block * data_block)712 data_block_length( libspectrum_tape_data_block *data_block )
713 {
714 libspectrum_dword length = 0;
715 size_t i;
716 if( data_block->count ) {
717 int bits_set_in_last_byte =
718 libspectrum_bits_set_n_bits( data_block->data[ data_block->length-1 ],
719 data_block->bits_in_last_byte );
720 size_t bit0_length = 0;
721 size_t bit1_length = 0;
722
723 for( i = 0; i < data_block->bit0_pulse_count; i++ ) {
724 bit0_length += data_block->bit0_pulses[ i ];
725 }
726 bit0_length /=
727 data_block->bit0_pulse_count ? data_block->bit0_pulse_count : 1;
728
729 for( i = 0; i < data_block->bit1_pulse_count; i++ ) {
730 bit1_length += data_block->bit1_pulses[ i ];
731 }
732 bit1_length /=
733 data_block->bit1_pulse_count ? data_block->bit1_pulse_count : 1;
734
735 for( i = 0; i < data_block->length-1; i++ ) {
736 libspectrum_byte data = data_block->data[ i ];
737 length += convert_pulses_to_tstates( bit1_length,
738 bit0_length,
739 bits_set[ data ],
740 LIBSPECTRUM_BITS_IN_BYTE );
741 }
742
743 /* handle bits in last byte correctly */
744 length += convert_pulses_to_tstates( bit1_length,
745 bit0_length,
746 bits_set_in_last_byte,
747 data_block->bits_in_last_byte );
748 }
749
750 return length;
751 }
752
753 libspectrum_dword
libspectrum_tape_block_length(libspectrum_tape_block * block)754 libspectrum_tape_block_length( libspectrum_tape_block *block )
755 {
756 libspectrum_tape_pure_tone_block *pure_tone;
757
758 switch( block->type ) {
759 case LIBSPECTRUM_TAPE_BLOCK_ROM:
760 return rom_block_length( &block->types.rom );
761 case LIBSPECTRUM_TAPE_BLOCK_TURBO:
762 return turbo_block_length( &block->types.turbo );
763 case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
764 pure_tone = &block->types.pure_tone;
765 return pure_tone->pulses * pure_tone->length;
766 case LIBSPECTRUM_TAPE_BLOCK_PULSES:
767 return pulses_block_length( &block->types.pulses );
768 case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
769 return pure_data_block_length( &block->types.pure_data );
770 case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
771 return block->types.pause.length_tstates;
772 case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
773 return raw_data_block_length( &block->types.raw_data );
774 case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
775 return rle_pulse_block_length( &block->types.rle_pulse );
776 case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
777 return generalised_data_block_length( &block->types.generalised_data );
778 case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
779 return pulse_sequence_block_length( &block->types.pulse_sequence );
780 case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
781 return data_block_length( &block->types.data_block );
782 case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
783 case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
784 case LIBSPECTRUM_TAPE_BLOCK_JUMP:
785 case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
786 case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
787 case LIBSPECTRUM_TAPE_BLOCK_STOP48:
788 case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
789 case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
790 case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
791 case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
792 case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
793 case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
794 case LIBSPECTRUM_TAPE_BLOCK_CONCAT:
795 case LIBSPECTRUM_TAPE_BLOCK_SELECT:
796 return 0;
797 default:
798 return -1;
799 }
800 }
801