1 /* tape.c: tape handling routines
2    Copyright (c) 1999-2011 Philip Kendall, Darren Salt, Witold Filipczyk
3 
4    $Id: tape.c 4863 2013-01-27 11:28:00Z 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 <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include <libspectrum.h>
34 
35 #include "debugger/debugger.h"
36 #include "event.h"
37 #include "fuse.h"
38 #include "loader.h"
39 #include "machine.h"
40 #include "memory.h"
41 #include "peripherals/ula.h"
42 #include "settings.h"
43 #include "sound.h"
44 #include "settings.h"
45 #include "snapshot.h"
46 #include "tape.h"
47 #include "timer/timer.h"
48 #include "ui/ui.h"
49 #include "utils.h"
50 #include "z80/z80.h"
51 #include "z80/z80_macros.h"
52 
53 /* The current tape */
54 static libspectrum_tape *tape;
55 
56 /* Has the current tape been modified since it was last loaded/saved? */
57 int tape_modified;
58 
59 /* Is the emulated tape deck playing? */
60 int tape_playing;
61 
62 /* Was the tape playing started automatically? */
63 static int tape_autoplay;
64 
65 /* Is there a high input to the EAR socket? */
66 int tape_microphone;
67 
68 /* Debugger events */
69 static const char *event_type_string = "tape";
70 
71 static const char *play_event_detail_string = "play",
72   *stop_event_detail_string = "stop";
73 static int play_event, stop_event = -1;
74 
75 /* Spectrum events */
76 int tape_edge_event;
77 static int record_event;
78 
79 /* Function prototypes */
80 
81 static int tape_autoload( libspectrum_machine hardware );
82 static int trap_load_block( libspectrum_tape_block *block );
83 static int tape_play( int autoplay );
84 static int trap_check_rom( void );
85 static void make_name( unsigned char *name, const unsigned char *data );
86 static void
87 tape_event_record_sample( libspectrum_dword last_tstates, int type,
88 			  void *user_data );
89 
90 /* Function definitions */
91 
92 void
tape_init(void)93 tape_init( void )
94 {
95   tape = libspectrum_tape_alloc();
96 
97   play_event = debugger_event_register( event_type_string,
98 					play_event_detail_string );
99   stop_event = debugger_event_register( event_type_string,
100 					stop_event_detail_string );
101 
102   tape_edge_event = event_register( tape_next_edge, "Tape edge" );
103   record_event = event_register( tape_event_record_sample,
104 				 "Tape sample record" );
105 
106   tape_modified = 0;
107 
108   /* Don't call tape_stop() here as the UI hasn't been initialised yet,
109      so we can't update the statusbar */
110   tape_playing = 0;
111   tape_microphone = 0;
112 }
113 
114 void
tape_end(void)115 tape_end( void )
116 {
117   libspectrum_tape_free( tape );
118   tape = NULL;
119 }
120 
tape_open(const char * filename,int autoload)121 int tape_open( const char *filename, int autoload )
122 {
123   utils_file file;
124   int error;
125 
126   error = utils_read_file( filename, &file );
127   if( error ) return error;
128 
129   error = tape_read_buffer( file.buffer, file.length, LIBSPECTRUM_ID_UNKNOWN,
130 			    filename, autoload );
131   if( error ) { utils_close_file( &file ); return error; }
132 
133   utils_close_file( &file );
134 
135   return 0;
136 }
137 
138 /* Use an already open tape file as the current tape */
139 int
tape_read_buffer(unsigned char * buffer,size_t length,libspectrum_id_t type,const char * filename,int autoload)140 tape_read_buffer( unsigned char *buffer, size_t length, libspectrum_id_t type,
141 		  const char *filename, int autoload )
142 {
143   int error;
144 
145   if( libspectrum_tape_present( tape ) ) {
146     error = tape_close(); if( error ) return error;
147   }
148 
149   error = libspectrum_tape_read( tape, buffer, length, type, filename );
150   if( error ) return error;
151 
152   tape_modified = 0;
153   ui_tape_browser_update( UI_TAPE_BROWSER_NEW_TAPE, NULL );
154 
155   if( autoload ) {
156     error = tape_autoload( machine_current->machine );
157     if( error ) return error;
158   }
159 
160   return 0;
161 }
162 
163 /* Load a snap to start the current tape autoloading */
164 static int
tape_autoload(libspectrum_machine hardware)165 tape_autoload( libspectrum_machine hardware )
166 {
167   int error; const char *id;
168   char filename[80];
169   utils_file snap;
170   libspectrum_id_t type;
171 
172   id = machine_get_id( hardware );
173   if( !id ) {
174     ui_error( UI_ERROR_ERROR, "Unknown machine type %d!", hardware );
175     return 1;
176   }
177 
178   /* Look for an autoload snap. Try .szx first, then .z80 */
179   type = LIBSPECTRUM_ID_SNAPSHOT_SZX;
180   snprintf( filename, sizeof(filename), "tape_%s.szx", id );
181   error = utils_read_auxiliary_file( filename, &snap, UTILS_AUXILIARY_LIB );
182   if( error == -1 ) {
183     type = LIBSPECTRUM_ID_SNAPSHOT_Z80;
184     snprintf( filename, sizeof(filename), "tape_%s.z80", id );
185     error = utils_read_auxiliary_file( filename, &snap, UTILS_AUXILIARY_LIB );
186   }
187 
188   /* If we couldn't find either, give up */
189   if( error == -1 ) {
190     ui_error( UI_ERROR_ERROR,
191 	      "Couldn't find autoload snap for machine type '%s'", id );
192     return 1;
193   }
194   if( error ) return error;
195 
196   error = snapshot_read_buffer( snap.buffer, snap.length, type );
197   if( error ) { utils_close_file( &snap ); return error; }
198 
199   utils_close_file( &snap );
200 
201   return 0;
202 }
203 
204 /* Close the active tape file */
tape_close(void)205 int tape_close( void )
206 {
207   int error;
208   ui_confirm_save_t confirm;
209 
210   /* If the tape has been modified, check if we want to do this */
211   if( tape_modified ) {
212 
213     confirm =
214       ui_confirm_save( "Tape has been modified.\nDo you want to save it?" );
215     switch( confirm ) {
216 
217     case UI_CONFIRM_SAVE_SAVE:
218       error = ui_tape_write(); if( error ) return error;
219       break;
220 
221     case UI_CONFIRM_SAVE_DONTSAVE: break;
222     case UI_CONFIRM_SAVE_CANCEL: return 1;
223 
224     }
225   }
226 
227   /* Stop the tape if it's currently playing */
228   if( tape_playing ) {
229     error = tape_stop();
230     if( error ) return error;
231   }
232 
233   /* And then remove it from memory */
234   error = libspectrum_tape_clear( tape );
235   if( error ) return error;
236 
237   tape_modified = 0;
238   ui_tape_browser_update( UI_TAPE_BROWSER_NEW_TAPE, NULL );
239 
240   return 0;
241 }
242 
243 /* Select the nth block on the tape; 0 => 1st block */
244 int
tape_select_block(size_t n)245 tape_select_block( size_t n )
246 {
247   int error;
248 
249   error = tape_select_block_no_update( n ); if( error ) return error;
250 
251   ui_tape_browser_update( UI_TAPE_BROWSER_SELECT_BLOCK, NULL );
252 
253   return 0;
254 }
255 
256 /* The same, but without updating the browser display */
257 int
tape_select_block_no_update(size_t n)258 tape_select_block_no_update( size_t n )
259 {
260   return libspectrum_tape_nth_block( tape, n );
261 }
262 
263 /* Which block is current? */
264 int
tape_get_current_block(void)265 tape_get_current_block( void )
266 {
267   int n;
268   libspectrum_error error;
269 
270   if( !libspectrum_tape_present( tape ) ) return -1;
271 
272   error = libspectrum_tape_position( &n, tape );
273   if( error ) return -1;
274 
275   return n;
276 }
277 
278 /* Write the current in-memory tape file out to disk */
tape_write(const char * filename)279 int tape_write( const char* filename )
280 {
281   libspectrum_id_t type;
282   libspectrum_class_t class;
283   libspectrum_byte *buffer; size_t length;
284 
285   int error;
286 
287   /* Work out what sort of file we want from the filename; default to
288      .tzx if we couldn't guess */
289   error = libspectrum_identify_file_with_class( &type, &class, filename, NULL,
290 						0 );
291   if( error ) return error;
292 
293   if( class != LIBSPECTRUM_CLASS_TAPE || type == LIBSPECTRUM_ID_UNKNOWN )
294     type = LIBSPECTRUM_ID_TAPE_TZX;
295 
296   length = 0;
297 
298   error = libspectrum_tape_write( &buffer, &length, tape, type );
299   if( error != LIBSPECTRUM_ERROR_NONE ) return error;
300 
301   error = utils_write_file( filename, buffer, length );
302   if( error ) { libspectrum_free( buffer ); return error; }
303 
304   tape_modified = 0;
305   ui_tape_browser_update( UI_TAPE_BROWSER_MODIFIED, NULL );
306 
307   libspectrum_free( buffer );
308 
309   return 0;
310 
311 }
312 
tape_can_autoload(void)313 int tape_can_autoload( void )
314 {
315   return( settings_current.auto_load && !memory_custom_rom() );
316 }
317 
318 /* Load the next tape block into memory; returns 0 if a block was
319    loaded (even if it had an tape loading error or equivalent) or
320    non-zero if there was an error at the emulator level, or tape traps
321    are not active */
tape_load_trap(void)322 int tape_load_trap( void )
323 {
324   libspectrum_tape_block *block, *next_block;
325   int error;
326 
327   /* Do nothing if tape traps aren't active, or the tape is already playing */
328   if( !settings_current.tape_traps || tape_playing ) return 2;
329 
330   /* Do nothing if we're not in the correct ROM */
331   if( ! trap_check_rom() ) return 3;
332 
333   /* Return with error if no tape file loaded */
334   if( !libspectrum_tape_present( tape ) ) return 1;
335 
336   block = libspectrum_tape_current_block( tape );
337 
338   /* Skip over any meta-data blocks */
339   while( libspectrum_tape_block_metadata( block ) ) {
340     block = libspectrum_tape_select_next_block( tape );
341     if( !block ) return 1;
342   }
343 
344   /* If this block isn't a ROM loader, start the block playing. After
345      that, return with `error' so that we actually do whichever
346      instruction it was that caused the trap to hit */
347   if( libspectrum_tape_block_type( block ) != LIBSPECTRUM_TAPE_BLOCK_ROM ||
348       libspectrum_tape_state( tape ) != LIBSPECTRUM_TAPE_STATE_PILOT ) {
349     tape_play( 1 );
350     return -1;
351   }
352 
353   /* We don't properly handle the case of partial loading, so don't run
354      the traps in that situation */
355   if( libspectrum_tape_block_data_length( block ) != DE + 2 ) {
356     tape_play( 1 );
357     return -1;
358   }
359 
360   /* All returns made via the RET at #05E2, except on Timex 2068 at #0136 */
361   if ( machine_current->machine == LIBSPECTRUM_MACHINE_TC2068 ||
362        machine_current->machine == LIBSPECTRUM_MACHINE_TS2068 ) {
363     PC = 0x0136;
364   } else {
365     PC = 0x05e2;
366   }
367 
368   error = trap_load_block( block );
369   if( error ) return error;
370 
371   /* Peek at the next block. If it's a ROM block, move along, initialise
372      the block, and return */
373   next_block = libspectrum_tape_peek_next_block( tape );
374 
375   if( libspectrum_tape_block_type(next_block) == LIBSPECTRUM_TAPE_BLOCK_ROM ) {
376 
377     next_block = libspectrum_tape_select_next_block( tape );
378     if( !next_block ) return 1;
379 
380     ui_tape_browser_update( UI_TAPE_BROWSER_SELECT_BLOCK, NULL );
381 
382     return 0;
383   }
384 
385   /* If the next block isn't a ROM block, set ourselves up such that the
386      next thing to occur is the pause at the end of the current block */
387   libspectrum_tape_set_state( tape, LIBSPECTRUM_TAPE_STATE_PAUSE );
388 
389   return 0;
390 }
391 
392 static int
trap_load_block(libspectrum_tape_block * block)393 trap_load_block( libspectrum_tape_block *block )
394 {
395   libspectrum_byte parity, *data;
396   int i = 0, length, read;
397 
398   /* On exit:
399    *  A = calculated parity byte if parity checked, else 0 (CHECKME)
400    *  F : if parity checked, all flags are modified
401    *      else carry only is modified (FIXME)
402    *  B = 0xB0 (success) or 0x00 (failure)
403    *  C = 0x01 (confirmed), 0x21, 0xFE or 0xDE (CHECKME)
404    * DE : decremented by number of bytes loaded or verified
405    *  H = calculated parity byte or undefined
406    *  L = last byte read, or 1 if none
407    * IX : incremented by number of bytes loaded or verified
408    * A' = unchanged on error + no flag byte, else 0x01
409    * F' = 0x01      on error + no flag byte, else 0x45
410    *  R = no point in altering it :-)
411    * Other registers unchanged.
412    */
413 
414   data = libspectrum_tape_block_data( block );
415   length = libspectrum_tape_block_data_length( block );
416 
417   /* Number of bytes to load or verify */
418   read = length - 1;
419   if( read > DE )
420     read = DE;
421 
422   /* If there's no data in the block (!), set L then error exit.
423    * We don't need to alter H, IX or DE here */
424   if( !length ) {
425     L = F_ = 1;
426     F &= ~FLAG_C;
427     return 0;
428   }
429 
430   i = A_; /* i = A' (flag byte) */
431   AF_ = 0x0145;
432   A = 0;
433 
434   /* Initialise the parity check and L to the block ID byte */
435   L = parity = *data++;
436 
437   /* If the block ID byte != the flag byte, clear carry and return */
438   if( parity != i )
439     goto error_ret;
440 
441   /* Now set L to the *last* byte in the block */
442   L = data[read - 1];
443 
444   /* Loading or verifying determined by the carry flag of F' */
445   if( F_ & FLAG_C ) {
446     for( i = 0; i < read; i++ ) {
447       parity ^= data[i];
448       writebyte_internal( IX+i, data[i] );
449     }
450   } else {		/* verifying */
451     for( i = 0; i < read; i++ ) {
452       parity ^= data[i];
453       if( data[i] != readbyte_internal(IX+i) ) {
454         /* Verification failure */
455         L = data[i];
456 	goto error_ret;
457       }
458     }
459   }
460 
461   /* At this point, i == number of bytes actually read or verified */
462 
463   /* If |DE| bytes have been read and there's more data, do the parity check */
464   if( DE == i && read + 1 < length ) {
465     parity ^= data[read];
466     A = parity;
467     CP( 1 ); /* parity check is successful if A==0 */
468     B = 0xB0;
469   } else {
470     /* Failure to read first bit of the next byte (ref. 48K ROM, 0x5EC) */
471     B = 255;
472     L = 1;
473     INC( B );
474 error_ret:
475     F &= ~FLAG_C;
476   }
477 
478   /* At this point, AF, AF', B and L are already modified */
479   C = 1;
480   H = parity;
481   DE -= i;
482   IX += i;
483   return 0;
484 }
485 
486 /* Append to the current tape file in memory; returns 0 if a block was
487    saved or non-zero if there was an error at the emulator level, or tape
488    traps are not active */
tape_save_trap(void)489 int tape_save_trap( void )
490 {
491   libspectrum_tape_block *block;
492   libspectrum_byte parity, *data;
493   size_t length;
494 
495   int i;
496 
497   /* Do nothing if tape traps aren't active */
498   if( !settings_current.tape_traps || tape_recording ) return 2;
499 
500   /* Check we're in the right ROM */
501   if( ! trap_check_rom() ) return 3;
502 
503   block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_ROM );
504 
505   /* The +2 here is for the flag and parity bytes */
506   length = DE + 2;
507   libspectrum_tape_block_set_data_length( block, length );
508 
509   data = libspectrum_malloc( length * sizeof(libspectrum_byte) );
510   libspectrum_tape_block_set_data( block, data );
511 
512   /* First, store the flag byte (and initialise the parity counter) */
513   data[0] = parity = A;
514 
515   /* then the main body of the data, counting parity along the way */
516   for( i=0; i<DE; i++) {
517     libspectrum_byte b = readbyte_internal( IX+i );
518     parity ^= b;
519     data[i+1] = b;
520   }
521 
522   /* And finally the parity byte */
523   data[ DE+1 ] = parity;
524 
525   /* Give a 1 second pause after this block */
526   libspectrum_tape_block_set_pause( block, 1000 );
527 
528   libspectrum_tape_append_block( tape, block );
529 
530   tape_modified = 1;
531   ui_tape_browser_update( UI_TAPE_BROWSER_NEW_BLOCK, block );
532 
533   /* And then return via the RET at #053E, except on Timex 2068 at #00E4 */
534   if ( machine_current->machine == LIBSPECTRUM_MACHINE_TC2068 ||
535        machine_current->machine == LIBSPECTRUM_MACHINE_TS2068 ) {
536     PC = 0x00e4;
537   } else {
538     PC = 0x053e;
539   }
540 
541   return 0;
542 
543 }
544 
545 /* Check whether we're actually in the right ROM when a tape trap hit */
546 static int
trap_check_rom(void)547 trap_check_rom( void )
548 {
549   if( plusd_available && plusd_active )
550     return 0;		/* +D must not be active */
551 
552   if( disciple_available && disciple_active )
553     return 0;		/* DISCiPLE must not be active */
554 
555   if( opus_available && opus_active )
556     return 0;		/* Opus must not be active */
557 
558   if( memory_custom_rom() )
559     return 0;           /* and we can't be using a custom ROM */
560 
561   switch( machine_current->machine ) {
562   case LIBSPECTRUM_MACHINE_16:
563   case LIBSPECTRUM_MACHINE_48:
564   case LIBSPECTRUM_MACHINE_48_NTSC:
565   case LIBSPECTRUM_MACHINE_SE:
566   case LIBSPECTRUM_MACHINE_TC2048:
567     return 1;		/* Always OK here */
568 
569   case LIBSPECTRUM_MACHINE_TC2068:
570   case LIBSPECTRUM_MACHINE_TS2068:
571     /* OK if we're in the EXROM (location of the tape routines) */
572     return( memory_map_read[0].source == memory_source_exrom );
573 
574   case LIBSPECTRUM_MACHINE_128:
575   case LIBSPECTRUM_MACHINE_PLUS2:
576     /* OK if we're in ROM 1 */
577     return( machine_current->ram.current_rom == 1 );
578 
579   case LIBSPECTRUM_MACHINE_PLUS2A:
580   case LIBSPECTRUM_MACHINE_PLUS3:
581   case LIBSPECTRUM_MACHINE_PLUS3E:
582     /* OK if we're not in a 64Kb RAM configuration and we're in
583        ROM 3 */
584     return( ! machine_current->ram.special &&
585 	    machine_current->ram.current_rom == 3 );
586 
587   case LIBSPECTRUM_MACHINE_128E:
588     /* OK if we're not in a 64Kb RAM configuration and we're in
589        either ROM 1 or ROM 3 (which are the same) */
590     return( ! machine_current->ram.special &&
591 	    ( machine_current->ram.current_rom == 1 ||
592               machine_current->ram.current_rom == 3    ));
593 
594   case LIBSPECTRUM_MACHINE_PENT:
595   case LIBSPECTRUM_MACHINE_PENT512:
596   case LIBSPECTRUM_MACHINE_PENT1024:
597   case LIBSPECTRUM_MACHINE_SCORP:
598     /* OK if we're in ROM 1 and the Beta disk interface is not active */
599     return( machine_current->ram.current_rom == 1 && !beta_active );
600 
601   case LIBSPECTRUM_MACHINE_UNKNOWN:	/* should never happen */
602     ui_error( UI_ERROR_ERROR,
603 	      "trap_check_rom: machine type is LIBSPECTRUM_MACHINE_UNKNOWN" );
604     fuse_abort();
605 
606   }
607 
608   ui_error( UI_ERROR_ERROR, "trap_check_rom: unknown machine type %d",
609 	    machine_current->machine );
610   fuse_abort();
611 }
612 
613 static int
tape_play(int autoplay)614 tape_play( int autoplay )
615 {
616   if( !libspectrum_tape_present( tape ) ) return 1;
617 
618   /* Otherwise, start the tape going */
619   tape_playing = 1;
620   tape_autoplay = autoplay;
621   tape_microphone = 0;
622 
623   /* Update the status bar */
624   ui_statusbar_update( UI_STATUSBAR_ITEM_TAPE, UI_STATUSBAR_STATE_ACTIVE );
625 
626   /* If we're fastloading, turn sound off */
627   if( settings_current.fastload ) sound_pause();
628 
629   loader_tape_play();
630 
631   tape_next_edge( tstates, 0, NULL );
632 
633   debugger_event( play_event );
634 
635   return 0;
636 }
637 
638 int
tape_do_play(int autoplay)639 tape_do_play( int autoplay )
640 {
641   if( !tape_playing ) {
642     return tape_play( autoplay );
643   } else {
644     return 0;
645   }
646 }
647 
tape_toggle_play(int autoplay)648 int tape_toggle_play( int autoplay )
649 {
650   if( tape_playing ) {
651     return tape_stop();
652   } else {
653     return tape_play( autoplay );
654   }
655 }
656 
tape_stop(void)657 int tape_stop( void )
658 {
659   if( tape_playing ) {
660 
661     tape_playing = 0;
662     ui_statusbar_update( UI_STATUSBAR_ITEM_TAPE, UI_STATUSBAR_STATE_INACTIVE );
663     loader_tape_stop();
664 
665     /* If we were fastloading, sound was off, so turn it back on, and
666        reset the speed counter */
667     if( settings_current.fastload ) {
668       sound_unpause();
669       timer_estimate_reset();
670     }
671 
672     event_remove_type( tape_edge_event );
673   }
674 
675   if( stop_event != -1 ) debugger_event( stop_event );
676 
677   return 0;
678 }
679 
680 int
tape_is_playing(void)681 tape_is_playing( void )
682 {
683   return tape_playing;
684 }
685 
686 int
tape_present(void)687 tape_present( void )
688 {
689   return libspectrum_tape_present( tape );
690 }
691 
692 typedef struct
693 {
694   libspectrum_byte *tape_buffer;
695   libspectrum_dword tape_buffer_size;
696   libspectrum_dword tape_buffer_used;
697   int tstates_per_sample;
698   int last_level;
699   int last_level_count;
700 } tape_rec_state;
701 
702 int tape_recording = 0;
703 
704 static tape_rec_state rec_state;
705 
706 void
tape_record_start(void)707 tape_record_start( void )
708 {
709   /* sample rate will be 44.1KHz */
710   rec_state.tstates_per_sample =
711     machine_current->timings.processor_speed/44100;
712 
713   rec_state.tape_buffer_size = 8192;
714   rec_state.tape_buffer = libspectrum_malloc(rec_state.tape_buffer_size);
715   rec_state.tape_buffer_used = 0;
716 
717   /* start scheduling events that record into a buffer that we
718      start allocating here */
719   event_add( tstates + rec_state.tstates_per_sample, record_event );
720 
721   rec_state.last_level = ula_tape_level();
722   rec_state.last_level_count = 1;
723 
724   tape_recording = 1;
725 
726   /* Also want to disable other tape actions */
727   ui_menu_activate( UI_MENU_ITEM_TAPE_RECORDING, 1 );
728 }
729 
730 static int
write_rec_buffer(libspectrum_byte * tape_buffer,libspectrum_dword tape_buffer_used,int last_level_count)731 write_rec_buffer( libspectrum_byte *tape_buffer,
732                   libspectrum_dword tape_buffer_used,
733                   int last_level_count )
734 {
735   if( last_level_count <= 0xff ) {
736     tape_buffer[ tape_buffer_used++ ] = last_level_count;
737   } else {
738     tape_buffer[ tape_buffer_used++ ] = 0;
739     tape_buffer[ tape_buffer_used++ ] = ( last_level_count & 0x000000ff )      ;
740     tape_buffer[ tape_buffer_used++ ] = ( last_level_count & 0x0000ff00 ) >>  8;
741     tape_buffer[ tape_buffer_used++ ] = ( last_level_count & 0x00ff0000 ) >> 16;
742     tape_buffer[ tape_buffer_used++ ] = ( last_level_count & 0xff000000 ) >> 24;
743   }
744 
745   return tape_buffer_used;
746 }
747 
748 void
tape_event_record_sample(libspectrum_dword last_tstates,int type,void * user_data)749 tape_event_record_sample( libspectrum_dword last_tstates, int type,
750 			  void *user_data )
751 {
752   if( rec_state.last_level != (ula_tape_level()) ) {
753     /* put a sample into the recording buffer */
754     rec_state.tape_buffer_used =
755       write_rec_buffer( rec_state.tape_buffer,
756                         rec_state.tape_buffer_used,
757                         rec_state.last_level_count );
758 
759     rec_state.last_level_count = 0;
760     rec_state.last_level = ula_tape_level();
761     /* make sure we can still fit a dword and a flag byte in the buffer */
762     if( rec_state.tape_buffer_used+5 >= rec_state.tape_buffer_size ) {
763       rec_state.tape_buffer_size = rec_state.tape_buffer_size*2;
764       rec_state.tape_buffer = libspectrum_realloc( rec_state.tape_buffer,
765                                                    rec_state.tape_buffer_size );
766     }
767   }
768 
769   rec_state.last_level_count++;
770 
771   /* schedule next timer */
772   event_add( last_tstates + rec_state.tstates_per_sample, record_event );
773 }
774 
775 int
tape_record_stop(void)776 tape_record_stop( void )
777 {
778   libspectrum_tape_block* block;
779 
780   /* put last sample into the recording buffer */
781   rec_state.tape_buffer_used = write_rec_buffer( rec_state.tape_buffer,
782                                                  rec_state.tape_buffer_used,
783                                                  rec_state.last_level_count );
784 
785   /* stop scheduling events and turn buffer into a block and
786      pop into the current tape */
787   event_remove_type( record_event );
788 
789   block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE );
790 
791   libspectrum_tape_block_set_scale( block, rec_state.tstates_per_sample );
792   libspectrum_tape_block_set_data_length( block, rec_state.tape_buffer_used );
793   libspectrum_tape_block_set_data( block, rec_state.tape_buffer );
794 
795   libspectrum_tape_append_block( tape, block );
796 
797   rec_state.tape_buffer = NULL;
798   rec_state.tape_buffer_size = 0;
799   rec_state.tape_buffer_used = 0;
800 
801   tape_modified = 1;
802   ui_tape_browser_update( UI_TAPE_BROWSER_NEW_BLOCK, block );
803 
804   tape_recording = 0;
805 
806   /* Also want to reenable other tape actions */
807   ui_menu_activate( UI_MENU_ITEM_TAPE_RECORDING, 0 );
808 
809   return 0;
810 }
811 
812 void
tape_next_edge(libspectrum_dword last_tstates,int type,void * user_data)813 tape_next_edge( libspectrum_dword last_tstates, int type, void *user_data )
814 {
815   libspectrum_error libspec_error;
816   libspectrum_tape_block *block;
817 
818   libspectrum_dword edge_tstates;
819   int flags;
820 
821   /* If the tape's not playing, just return */
822   if( ! tape_playing ) return;
823 
824   /* Get the time until the next edge */
825   libspec_error = libspectrum_tape_get_next_edge( &edge_tstates, &flags,
826 						  tape );
827   if( libspec_error != LIBSPECTRUM_ERROR_NONE ) return;
828 
829   /* Invert the microphone state */
830   if( edge_tstates ||
831       ( flags & ( LIBSPECTRUM_TAPE_FLAGS_STOP |
832                   LIBSPECTRUM_TAPE_FLAGS_LEVEL_LOW |
833                   LIBSPECTRUM_TAPE_FLAGS_LEVEL_HIGH ) ) ) {
834 
835     if( flags & LIBSPECTRUM_TAPE_FLAGS_NO_EDGE ) {
836       /* Do nothing */
837     } else if( flags & LIBSPECTRUM_TAPE_FLAGS_LEVEL_LOW ) {
838       tape_microphone = 0;
839     } else if( flags & LIBSPECTRUM_TAPE_FLAGS_LEVEL_HIGH ) {
840       tape_microphone = 1;
841     } else {
842       tape_microphone = !tape_microphone;
843     }
844   }
845 
846   /* If we've been requested to stop the tape, do so and then
847      return without stacking another edge */
848   if( ( flags & LIBSPECTRUM_TAPE_FLAGS_STOP ) ||
849       ( ( flags & LIBSPECTRUM_TAPE_FLAGS_STOP48 ) &&
850 	( !( libspectrum_machine_capabilities( machine_current->machine ) &
851 	     LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY
852 	   )
853 	)
854       )
855     )
856   {
857     tape_stop();
858     return;
859   }
860 
861   /* If that was the end of a block, update the browser */
862   if( flags & LIBSPECTRUM_TAPE_FLAGS_BLOCK ) {
863 
864     ui_tape_browser_update( UI_TAPE_BROWSER_SELECT_BLOCK, NULL );
865 
866     /* If the tape was started automatically, tape traps are active
867        and the new block is a ROM loader, stop the tape and return
868        without putting another event into the queue */
869     block = libspectrum_tape_current_block( tape );
870     if( tape_autoplay && settings_current.tape_traps &&
871 	libspectrum_tape_block_type( block ) == LIBSPECTRUM_TAPE_BLOCK_ROM
872       ) {
873       tape_stop();
874       return;
875     }
876   }
877 
878   /* Otherwise, put this into the event queue; remember that this edge
879      should occur 'edge_tstates' after the last edge, not after the
880      current time (these will be slightly different as we only process
881      events between instructions). */
882   event_add( last_tstates + edge_tstates, tape_edge_event );
883 
884   /* Store length flags for acceleration purposes */
885   loader_set_acceleration_flags( flags );
886 }
887 
888 /* Call a user-supplied function for every block in the current tape */
889 int
tape_foreach(void (* function)(libspectrum_tape_block * block,void * user_data),void * user_data)890 tape_foreach( void (*function)( libspectrum_tape_block *block,
891 				void *user_data),
892 	      void *user_data )
893 {
894   libspectrum_tape_block *block;
895   libspectrum_tape_iterator iterator;
896 
897   for( block = libspectrum_tape_iterator_init( &iterator, tape );
898        block;
899        block = libspectrum_tape_iterator_next( &iterator ) )
900     function( block, user_data );
901 
902   return 0;
903 }
904 
905 int
tape_block_details(char * buffer,size_t length,libspectrum_tape_block * block)906 tape_block_details( char *buffer, size_t length,
907 		    libspectrum_tape_block *block )
908 {
909   libspectrum_byte *data;
910   const char *type; unsigned char name[11];
911   int offset;
912 
913   buffer[0] = '\0';
914 
915   switch( libspectrum_tape_block_type( block ) ) {
916 
917   case LIBSPECTRUM_TAPE_BLOCK_ROM:
918     /* See if this looks like a standard Spectrum header and if so
919        display some extra data */
920     if( libspectrum_tape_block_data_length( block ) != 19 ) goto normal;
921 
922     data = libspectrum_tape_block_data( block );
923 
924     /* Flag byte is 0x00 for headers */
925     if( data[0] != 0x00 ) goto normal;
926 
927     switch( data[1] ) {
928     case 0x00: type = "Program"; break;
929     case 0x01: type = "Number array"; break;
930     case 0x02: type = "Character array"; break;
931     case 0x03: type = "Bytes"; break;
932     default: goto normal;
933     }
934 
935     make_name( name, &data[2] );
936 
937     snprintf( buffer, length, "%s: \"%s\"", type, name );
938 
939     break;
940 
941   normal:
942     snprintf( buffer, length, "%lu bytes",
943 	      (unsigned long)libspectrum_tape_block_data_length( block ) );
944     break;
945 
946   case LIBSPECTRUM_TAPE_BLOCK_TURBO:
947   case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
948   case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
949   case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
950     snprintf( buffer, length, "%lu bytes",
951 	      (unsigned long)libspectrum_tape_block_data_length( block ) );
952     break;
953 
954   case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
955     snprintf( buffer, length, "%lu tstates",
956 	      (unsigned long)libspectrum_tape_block_pulse_length( block ) );
957     break;
958 
959   case LIBSPECTRUM_TAPE_BLOCK_PULSES:
960   case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
961     snprintf( buffer, length, "%lu pulses",
962 	      (unsigned long)libspectrum_tape_block_count( block ) );
963     break;
964 
965   case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
966     snprintf( buffer, length, "%lu ms",
967 	      (unsigned long)libspectrum_tape_block_pause( block ) );
968     break;
969 
970   case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
971   case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
972   case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
973   case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
974     snprintf( buffer, length, "%s", libspectrum_tape_block_text( block ) );
975     break;
976 
977   case LIBSPECTRUM_TAPE_BLOCK_JUMP:
978     offset = libspectrum_tape_block_offset( block );
979     if( offset > 0 ) {
980       snprintf( buffer, length, "Forward %d blocks", offset );
981     } else {
982       snprintf( buffer, length, "Backward %d blocks", -offset );
983     }
984     break;
985 
986   case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
987     snprintf( buffer, length, "%lu iterations",
988 	      (unsigned long)libspectrum_tape_block_count( block ) );
989     break;
990 
991   case LIBSPECTRUM_TAPE_BLOCK_SELECT:
992     snprintf( buffer, length, "%lu options",
993 	      (unsigned long)libspectrum_tape_block_count( block ) );
994     break;
995 
996   case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
997     snprintf( buffer, length, "%lu data symbols",
998 	      (unsigned long)libspectrum_tape_generalised_data_symbol_table_symbols_in_block( libspectrum_tape_block_data_table( block ) ) );
999     break;
1000 
1001   case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
1002     /* Could do something better with this one */
1003     break;
1004 
1005   case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
1006   case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
1007   case LIBSPECTRUM_TAPE_BLOCK_STOP48:
1008   case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
1009   case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
1010   case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
1011   case LIBSPECTRUM_TAPE_BLOCK_CONCAT:
1012     break;
1013 
1014   }
1015 
1016   return 0;
1017 }
1018 
1019 static void
make_name(unsigned char * name,const unsigned char * data)1020 make_name( unsigned char *name, const unsigned char *data )
1021 {
1022   size_t i;
1023 
1024   for( i = 0; i < 10; i++, name++, data++ ) {
1025     if( *data >= 32 && *data < 127 ) {
1026       *name = *data;
1027     } else {
1028       *name = '?';
1029     }
1030   }
1031 
1032   *name = '\0';
1033 }
1034