예제 #1
0
파일: tape.c 프로젝트: twinaphex/sdcell
/* Append to the current tape file in memory; returns 0 if a block was
   saved or non-zero if there was an error at the emulator level, or tape
   traps are not active */
int tape_save_trap( void )
{
  libspectrum_tape_block *block;
  libspectrum_byte parity, *data;
  size_t length;

  int i;

  /* Do nothing if tape traps aren't active */
  if( !settings_current.tape_traps || tape_recording ) return 2;

  /* Check we're in the right ROM */
  if( ! trap_check_rom() ) return 3;

  block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_ROM );
  
  /* The +2 here is for the flag and parity bytes */
  length = DE + 2;
  libspectrum_tape_block_set_data_length( block, length );

  data = malloc( length * sizeof(libspectrum_byte) );
  if( !data ) { free( block ); return 1; }
  libspectrum_tape_block_set_data( block, data );

  /* First, store the flag byte (and initialise the parity counter) */
  data[0] = parity = A;

  /* then the main body of the data, counting parity along the way */
  for( i=0; i<DE; i++) {
    libspectrum_byte b = readbyte_internal( IX+i );
    parity ^= b;
    data[i+1] = b;
  }

  /* And finally the parity byte */
  data[ DE+1 ] = parity;

  /* Give a 1 second pause after this block */
  libspectrum_tape_block_set_pause( block, 1000 );

  libspectrum_tape_append_block( tape, block );

  tape_modified = 1;
  ui_tape_browser_update( UI_TAPE_BROWSER_NEW_BLOCK, block );

  /* And then return via the RET at #053E, except on Timex 2068 at #00E4 */
  if ( machine_current->machine == LIBSPECTRUM_MACHINE_TC2068 ||
       machine_current->machine == LIBSPECTRUM_MACHINE_TS2068 ) {
    PC = 0x00e4;
  } else {
    PC = 0x053e;
  }

  return 0;

}
예제 #2
0
static int
append_inlay_file( char *inlay_file, libspectrum_tape *tape )
{
  libspectrum_tape_block* block;
  char *description;
  libspectrum_byte* jpg_data; size_t jpg_length;
  libspectrum_byte* custom_block_data; size_t custom_block_length;

  block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_CUSTOM );

  /* Get the description */
  description = malloc( DESCRIPTION_BUFFER_LEN );
  memcpy( description, "Picture        ", DESCRIPTION_BUFFER_LEN );
  libspectrum_tape_block_set_text( block, description );

  /* Read in the data */
  if( read_file( inlay_file, &jpg_data, &jpg_length ) ) {
    free( description );
    free( block );
    return 1;
  }

  custom_block_length = jpg_length + 2;
  custom_block_data = malloc( custom_block_length );

  /* Picture format */
  if( is_filetype( inlay_file, ".jpg" ) ) {
    custom_block_data[0] = 1;
  } else if( is_filetype( inlay_file, ".gif" ) ) {
    custom_block_data[0] = 0;
  } else {
    free( custom_block_data );
    return 1;
  }

  /* Picture description length 0 == "Inlay Card" */
  custom_block_data[1] = 0;
  /* and the JPG itself */
  memcpy( custom_block_data + 2, jpg_data, jpg_length );

  libspectrum_tape_block_set_data_length( block, custom_block_length );
  libspectrum_tape_block_set_data( block, custom_block_data );

  /* Finally, put the block into the block list */
  libspectrum_tape_append_block( tape, block );

  return 0;
}
예제 #3
0
libspectrum_error
libspectrum_z80em_read( libspectrum_tape *tape,
			const libspectrum_byte *buffer, size_t length )
{
  libspectrum_tape_block *block;
  libspectrum_tape_rle_pulse_block *z80em_block;

  static const char id[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Raw tape sample";

  if( length < sizeof( id ) ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "libspectrum_z80em_read: not enough data in buffer"
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  if( memcmp( id, buffer, sizeof( id ) ) ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_SIGNATURE,
			     "libspectrum_z80em_read: wrong signature" );
    return LIBSPECTRUM_ERROR_SIGNATURE;
  }

  block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE );

  z80em_block = &block->types.rle_pulse;
  z80em_block->scale = 7; /* 1 time unit == 7 clock ticks */

  buffer += sizeof( id );
  length -= sizeof( id );

  /* Claim memory for the data (it's one big lump) */
  z80em_block->length = length;
  z80em_block->data = libspectrum_new( libspectrum_byte, length );

  /* Copy the data across */
  memcpy( z80em_block->data, buffer, length );

  libspectrum_tape_append_block( tape, block );

  return LIBSPECTRUM_ERROR_NONE;
}
예제 #4
0
static int
append_scr_file( char *scr_file, libspectrum_tape *tape )
{
  libspectrum_tape_block* block;
  char *description;
  libspectrum_byte* scr_data; size_t scr_length;
  libspectrum_byte* custom_block_data; size_t custom_block_length;

  block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_CUSTOM );

  /* Get the description */
  description = malloc( DESCRIPTION_BUFFER_LEN );
  memcpy( description, "Spectrum Screen ", DESCRIPTION_BUFFER_LEN );
  libspectrum_tape_block_set_text( block, description );

  /* Read in the data */
  if( read_file( scr_file, &scr_data, &scr_length ) ) {
    free( description );
    free( block );
    return 1;
  }

  custom_block_length = scr_length + 2;
  custom_block_data = malloc( custom_block_length );

  /* Picture description length 0 == "Loading Screen" */
  custom_block_data[0] = 0;
  /* Border colour 0 == black */
  custom_block_data[1] = 0;
  /* and the SCR itself */
  memcpy( custom_block_data + 2, scr_data, scr_length );

  libspectrum_tape_block_set_data_length( block, custom_block_length );
  libspectrum_tape_block_set_data( block, custom_block_data );

  /* Finally, put the block into the block list */
  libspectrum_tape_append_block( tape, block );

  return 0;
}
예제 #5
0
int
tape_record_stop( void )
{
  libspectrum_tape_block* block;

  /* put last sample into the recording buffer */
  rec_state.tape_buffer_used = write_rec_buffer( rec_state.tape_buffer,
                                                 rec_state.tape_buffer_used,
                                                 rec_state.last_level_count );

  /* stop scheduling events and turn buffer into a block and
     pop into the current tape */
  event_remove_type( record_event );

  block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE );

  libspectrum_tape_block_set_scale( block, rec_state.tstates_per_sample );
  libspectrum_tape_block_set_data_length( block, rec_state.tape_buffer_used );
  libspectrum_tape_block_set_data( block, rec_state.tape_buffer );

  libspectrum_tape_append_block( tape, block );

  rec_state.tape_buffer = NULL;
  rec_state.tape_buffer_size = 0;
  rec_state.tape_buffer_used = 0;

  tape_modified = 1;
  ui_tape_browser_update( UI_TAPE_BROWSER_NEW_BLOCK, block );

  tape_recording = 0;

  /* Also want to reenable other tape actions */
  ui_menu_activate( UI_MENU_ITEM_TAPE_RECORDING, 0 );

  return 0;
}
예제 #6
0
libspectrum_error
libspectrum_wav_read( libspectrum_tape *tape, const char *filename )
{
  libspectrum_byte *buffer; size_t length;
  libspectrum_byte *tape_buffer; size_t tape_length;
  size_t data_length;
  libspectrum_tape_block *block = NULL;
  int frames;

  /* Our filehandle from libaudiofile */
  AFfilehandle handle;

  /* The track we're using in the file */
  int track = AF_DEFAULT_TRACK; 

  if( !filename ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_LOGIC,
      "libspectrum_wav_read: no filename provided - wav files can only be loaded from a file"
    );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  handle = afOpenFile( filename, "r", NULL );
  if( handle == AF_NULL_FILEHANDLE ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_LOGIC,
      "libspectrum_wav_read: audiofile failed to open file:%s", filename
    );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  if( afSetVirtualSampleFormat( handle, track, AF_SAMPFMT_UNSIGNED, 8 ) ) {
    afCloseFile( handle );
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_LOGIC,
      "libspectrum_wav_read: audiofile failed to set virtual sample format"
    );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  if( afSetVirtualChannels( handle, track, 1 ) ) {
    afCloseFile( handle );
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_LOGIC,
      "libspectrum_wav_read: audiofile failed to set virtual channel count"
    );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  length = afGetFrameCount( handle, track );

  tape_length = length;
  if( tape_length%8 ) tape_length += 8 - (tape_length%8);

  buffer = libspectrum_new0( libspectrum_byte,
			     tape_length * afGetChannels(handle, track) );

  frames = afReadFrames( handle, track, buffer, length );
  if( frames == -1 ) {
    libspectrum_free( buffer );
    afCloseFile( handle );
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "libspectrum_wav_read: can't calculate number of frames in audio file"
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  if( !length ) {
    libspectrum_free( buffer );
    afCloseFile( handle );
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "libspectrum_wav_read: empty audio file, nothing to load"
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  if( frames != length ) {
    libspectrum_free( buffer );
    afCloseFile( handle );
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "libspectrum_wav_read: read %d frames, but expected %lu\n", frames,
      (unsigned long)length
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RAW_DATA );

  /* 44100 Hz 79 t-states 22050 Hz 158 t-states */
  libspectrum_tape_block_set_bit_length( block,
                                         3500000/afGetRate( handle, track ) );
  libspectrum_set_pause_ms( block, 0 );
  libspectrum_tape_block_set_bits_in_last_byte( block,
              length % LIBSPECTRUM_BITS_IN_BYTE ?
                length % LIBSPECTRUM_BITS_IN_BYTE : LIBSPECTRUM_BITS_IN_BYTE );
  data_length = tape_length / LIBSPECTRUM_BITS_IN_BYTE;
  libspectrum_tape_block_set_data_length( block, data_length );

  tape_buffer = libspectrum_new0( libspectrum_byte, data_length );

  libspectrum_byte *from = buffer;
  libspectrum_byte *to = tape_buffer;
  length = tape_length;
  do {
    libspectrum_byte val = 0;
    int i;
    for( i = 7; i >= 0; i-- ) {
      if( *from++ > 127 ) val |= 1 << i;
    }
    *to++ = val;
  } while ((length -= 8) > 0);

  libspectrum_tape_block_set_data( block, tape_buffer );

  libspectrum_tape_append_block( tape, block );

  if( afCloseFile( handle ) ) {
    libspectrum_free( buffer );
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_UNKNOWN,
      "libspectrum_wav_read: failed to close audio file"
    );
    return LIBSPECTRUM_ERROR_UNKNOWN;
  }

  libspectrum_free( buffer );

  /* Successful completion */
  return LIBSPECTRUM_ERROR_NONE;
}
예제 #7
0
libspectrum_error
libspectrum_csw_read( libspectrum_tape *tape,
                      const libspectrum_byte *buffer, size_t length )
{
    libspectrum_tape_block *block = NULL;
    libspectrum_tape_rle_pulse_block *csw_block;

    int compressed;

    size_t signature_length = strlen( csw_signature );

    if( length < signature_length + 2 ) goto csw_short;

    if( memcmp( csw_signature, buffer, signature_length ) ) {
        libspectrum_print_error( LIBSPECTRUM_ERROR_SIGNATURE,
                                 "libspectrum_csw_read: wrong signature" );
        return LIBSPECTRUM_ERROR_SIGNATURE;
    }

    /* Claim memory for the block */
    block = libspectrum_new( libspectrum_tape_block, 1 );

    /* Set the block type */
    block->type = LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE;
    csw_block = &block->types.rle_pulse;

    buffer += signature_length;
    length -= signature_length;

    switch( buffer[0] ) {

    case 1:
        if( length < 9 ) goto csw_short;
        csw_block->scale = buffer[2] | buffer[3] << 8;
        if( buffer[4] != 1 ) goto csw_bad_compress;
        compressed = 0;
        buffer += 9;
        length -= 9;
        break;

    case 2:
        if( length < 29 ) goto csw_short;

        csw_block->scale =
            buffer[2]       |
            buffer[3] <<  8 |
            buffer[4] << 16 |
            buffer[5] << 24;
        compressed = buffer[10] - 1;

        if( compressed != 0 && compressed != 1 ) goto csw_bad_compress;

        if( length < 29 - buffer[12] ) goto csw_short;
        length -= 29 - buffer[12];
        buffer += 29 + buffer[12];

        break;

    default:
        libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
                                 "libspectrum_csw_read: unknown CSW version" );
        return LIBSPECTRUM_ERROR_SIGNATURE;
    }

    if (csw_block->scale)
        csw_block->scale = 3500000 / csw_block->scale; /* approximate CPU speed */

    if( csw_block->scale < 0 || csw_block->scale >= 0x80000 ) {
        libspectrum_print_error (LIBSPECTRUM_ERROR_MEMORY,
                                 "libspectrum_csw_read: bad sample rate" );
        return LIBSPECTRUM_ERROR_UNKNOWN;
    }

    if( !length ) goto csw_empty;

    if( compressed ) {
        /* Compressed data... */
#ifdef HAVE_ZLIB_H
        libspectrum_error error;

        csw_block->data = NULL;
        csw_block->length = 0;
        error = libspectrum_zlib_inflate( buffer, length, &csw_block->data,
                                          &csw_block->length );
        if( error != LIBSPECTRUM_ERROR_NONE ) return error;
#else
        libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
                                 "zlib not available to decompress gzipped file" );
        return LIBSPECTRUM_ERROR_UNKNOWN;
#endif
    } else {
        /* Claim memory for the data (it's one big lump) */
        csw_block->length = length;
        csw_block->data = libspectrum_new( libspectrum_byte, length );

        /* Copy the data across */
        memcpy( csw_block->data, buffer, length );
    }

    libspectrum_tape_append_block( tape, block );

    /* Successful completion */
    return LIBSPECTRUM_ERROR_NONE;

    /* Error returns */

csw_bad_compress:
    libspectrum_free( block );
    libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
                             "libspectrum_csw_read: unknown compression type" );
    return LIBSPECTRUM_ERROR_CORRUPT;

csw_short:
    libspectrum_free( block );
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
                             "libspectrum_csw_read: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;

csw_empty:
    libspectrum_free( block );
    /* Successful completion */
    return LIBSPECTRUM_ERROR_NONE;
}