Exemple #1
0
libspectrum_tape_block*
libspectrum_tape_block_internal_init(
                                libspectrum_tape_block_state *it,
				libspectrum_tape *tape )
{
  if( !tape || !tape->blocks )
    return NULL;

  it->current_block = tape->blocks;

  if( libspectrum_tape_block_init( it->current_block->data,
                                   it ) )
    return NULL;

  return libspectrum_tape_iterator_current( it->current_block );
}
Exemple #2
0
libspectrum_error
libspectrum_tape_append_block( libspectrum_tape *tape,
			       libspectrum_tape_block *block )
{
  tape->blocks = g_slist_append( tape->blocks, (gpointer)block );

  /* If we previously didn't have a tape loaded ( implied by
     tape->current_block == NULL ), set up so that we point to the
     start of the tape */
  if( !tape->state.current_block ) {
    tape->state.current_block = tape->blocks;
    libspectrum_tape_block_init( tape->blocks->data, &(tape->state) );
  }

  return LIBSPECTRUM_ERROR_NONE;
}
Exemple #3
0
/* Cause the next block on the tape to be active, initialise it
   and return it */
libspectrum_tape_block*
libspectrum_tape_select_next_block( libspectrum_tape *tape )
{
  libspectrum_tape_block *block;

  if( !tape->state.current_block ) return NULL;

  block = libspectrum_tape_iterator_next( &(tape->state.current_block) );

  if( !block )
    block = libspectrum_tape_iterator_init( &(tape->state.current_block), tape );

  if( libspectrum_tape_block_init( block, &(tape->state) ) )
    return NULL;

  return block;
}
Exemple #4
0
/* Select the nth block on the tape */
libspectrum_error
libspectrum_tape_nth_block( libspectrum_tape *tape, int n )
{
  GSList *new_block;
  libspectrum_error error;

  new_block = g_slist_nth( tape->blocks, n );
  if( !new_block ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "libspectrum_tape_nth_block: tape does not have block %d", n
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  tape->state.current_block = new_block;

  error = libspectrum_tape_block_init( tape->state.current_block->data,
                                       &(tape->state) );
  if( error ) return error;

  return LIBSPECTRUM_ERROR_NONE;
}
Exemple #5
0
libspectrum_error
libspectrum_tape_get_next_edge_internal( libspectrum_dword *tstates,
                                         int *flags,
                                         libspectrum_tape *tape,
                                         libspectrum_tape_block_state *it )
{
  int error;

  libspectrum_tape_block *block =
    libspectrum_tape_iterator_current( it->current_block );

  /* Has this edge ended the block? */
  int end_of_block = 0;

  /* After getting a new block, do we want to advance to the next one? */
  int no_advance = 0;

  /* Assume no special flags by default */
  *flags = 0;

  if( block ) {
    switch( block->type ) {
    case LIBSPECTRUM_TAPE_BLOCK_ROM:
      error = rom_edge( &(block->types.rom), &(it->block_state.rom), tstates,
                        &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_TURBO:
      error = turbo_edge( &(block->types.turbo), &(it->block_state.turbo), tstates,
                          &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
      error = tone_edge( &(block->types.pure_tone), &(it->block_state.pure_tone),
                         tstates, &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PULSES:
      error = pulses_edge( &(block->types.pulses), &(it->block_state.pulses),
                           tstates, &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
      error = pure_data_edge( &(block->types.pure_data),
                              &(it->block_state.pure_data), tstates, &end_of_block);
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
      error = raw_data_edge( &(block->types.raw_data), &(it->block_state.raw_data),
                             tstates, &end_of_block );
      if( error ) return error;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
      error = generalised_data_edge( &(block->types.generalised_data),
                                     &(it->block_state.generalised_data),
                                     tstates, &end_of_block, flags );
      if( error ) return error;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
      *tstates = ( block->types.pause.length * 69888 ) / 20; end_of_block = 1;
      /* 0 ms pause => stop tape */
      if( *tstates == 0 ) { *flags |= LIBSPECTRUM_TAPE_FLAGS_STOP; }
      break;

    case LIBSPECTRUM_TAPE_BLOCK_JUMP:
      error = jump_blocks( tape, block->types.jump.offset );
      if( error ) return error;
      *tstates = 0; end_of_block = 1; no_advance = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
      if( it->current_block->next && block->types.loop_start.count ) {
        it->loop_block = it->current_block->next;
        it->loop_count = block->types.loop_start.count;
      }
      *tstates = 0; end_of_block = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
      if( it->loop_block ) {
        if( --(it->loop_count) ) {
          it->current_block = it->loop_block;
          no_advance = 1;
        } else {
          it->loop_block = NULL;
        }
      }
      *tstates = 0; end_of_block = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_STOP48:
      *tstates = 0; *flags |= LIBSPECTRUM_TAPE_FLAGS_STOP48; end_of_block = 1;
      break;

    /* For blocks which contain no Spectrum-readable data, return zero
       tstates and set end of block set so we instantly get the next block */
    case LIBSPECTRUM_TAPE_BLOCK_GROUP_START: 
    case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
    case LIBSPECTRUM_TAPE_BLOCK_SELECT:
    case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
    case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
    case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
    case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
    case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
      *tstates = 0; end_of_block = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
      error = rle_pulse_edge( &(block->types.rle_pulse),
                              &(it->block_state.rle_pulse), tstates, &end_of_block);
      if( error ) return error;
      break;

    default:
      *tstates = 0;
      libspectrum_print_error(
        LIBSPECTRUM_ERROR_LOGIC,
        "libspectrum_tape_get_next_edge: unknown block type 0x%02x",
        block->type
      );
      return LIBSPECTRUM_ERROR_LOGIC;
    }
  } else {
    *tstates = 0;
    end_of_block = 1;
  }

  /* If that ended the block, move onto the next block */
  if( end_of_block ) {

    *flags |= LIBSPECTRUM_TAPE_FLAGS_BLOCK;

    /* Advance to the next block, unless we've been told not to */
    if( !no_advance ) {

      libspectrum_tape_iterator_next( &(it->current_block) );

      /* If we've just hit the end of the tape, stop the tape (and
	 then `rewind' to the start) */
      if( libspectrum_tape_iterator_current( it->current_block ) == NULL ) {
	*flags |= LIBSPECTRUM_TAPE_FLAGS_STOP;
        libspectrum_tape_iterator_init( &(it->current_block), tape );
      }
    }

    /* Initialise the new block */
    error = libspectrum_tape_block_init(
                      libspectrum_tape_iterator_current( it->current_block ),
                      it );
    if( error ) return error;

  }

  return LIBSPECTRUM_ERROR_NONE;
}
Exemple #6
0
/* Convert RLE block to a TZX DRB as TZX CSW block support is limited :/ */
static libspectrum_error
tzx_write_rle( libspectrum_tape_block *block, libspectrum_byte **buffer,
               libspectrum_byte **ptr, size_t *length,
               libspectrum_tape *tape,
               libspectrum_tape_iterator iterator )
{
  libspectrum_error error;
  libspectrum_tape_block_state it;
  libspectrum_dword scale = libspectrum_tape_block_scale( block );
  libspectrum_dword pulse_tstates = 0;
  libspectrum_dword balance_tstates = 0;
  int flags = 0;

  libspectrum_tape_block *raw_block = 
    libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RAW_DATA );

  libspectrum_tape_block_set_bit_length( raw_block, scale );
  libspectrum_tape_block_set_pause     ( raw_block, 0 );

  rle_state.bits_used = 0;
  rle_state.level = 0;
  rle_state.length = 0;
  rle_state.tape_length = 8192;
  rle_state.tape_buffer = libspectrum_malloc( rle_state.tape_length );

  *rle_state.tape_buffer = 0;

  it.current_block = iterator;
  error = libspectrum_tape_block_init( block, &it );
  if( error != LIBSPECTRUM_ERROR_NONE ) {
    libspectrum_free( rle_state.tape_buffer );
    libspectrum_tape_block_free( raw_block );
    return error;
  }

  while( !(flags & LIBSPECTRUM_TAPE_FLAGS_BLOCK) ) {
    libspectrum_dword pulse_length = 0;

    /* Use internal version of this that doesn't bugger up the
       external tape status */
    error = libspectrum_tape_get_next_edge_internal( &pulse_tstates, &flags,
                                                     tape, &it );
    if( error != LIBSPECTRUM_ERROR_NONE ) {
      libspectrum_free( rle_state.tape_buffer );
      libspectrum_tape_block_free( raw_block );
      return error;
    }

    balance_tstates += pulse_tstates;

    /* next set of pulses is: balance_tstates / scale; */
    pulse_length = balance_tstates / scale;
    balance_tstates = balance_tstates % scale;

    /* write pulse_length bits of the current level into the buffer */
    write_pulse( pulse_length );
  }

  if( rle_state.length || rle_state.bits_used ) {
    if( rle_state.bits_used ) {
      rle_state.length++;
    } else {
      rle_state.bits_used = 8;
    }

    error = libspectrum_tape_block_set_bits_in_last_byte( raw_block,
                                                          rle_state.bits_used );
    if( error != LIBSPECTRUM_ERROR_NONE ) {
      libspectrum_free( rle_state.tape_buffer );
      libspectrum_tape_block_free( raw_block );
      return error;
    }

    error = libspectrum_tape_block_set_data_length( raw_block,
                                                    rle_state.length );
    if( error != LIBSPECTRUM_ERROR_NONE ) {
      libspectrum_free( rle_state.tape_buffer );
      libspectrum_tape_block_free( raw_block );
      return error;
    }

    error = libspectrum_tape_block_set_data( raw_block, rle_state.tape_buffer );
    if( error != LIBSPECTRUM_ERROR_NONE ) {
      libspectrum_free( rle_state.tape_buffer );
      libspectrum_tape_block_free( raw_block );
      return error;
    }

    /* now have tzx_write_raw_data finish the job */
    tzx_write_raw_data( raw_block, buffer, ptr, length );
  } else {
    libspectrum_free( rle_state.tape_buffer );
  }

  return libspectrum_tape_block_free( raw_block );
}