Example #1
0
/* The main function: called with a tape object and returns the number of
   t-states until the next edge, and a marker if this was the last edge
   on the tape */
libspectrum_error
libspectrum_tape_get_next_edge( libspectrum_dword *tstates, int *flags,
	                        libspectrum_tape *tape )
{
  return libspectrum_tape_get_next_edge_internal( tstates, flags, tape,
                                                  &(tape->state) );
}
Example #2
0
static libspectrum_error
csw_write_body( libspectrum_byte **buffer, size_t *length,
                libspectrum_tape *tape, libspectrum_dword sample_rate,
                size_t length_offset, libspectrum_byte *ptr )
{
    libspectrum_error error;
    int flags = 0;
    libspectrum_dword pulse_tstates = 0;
    libspectrum_dword balance_tstates = 0;
    libspectrum_byte *data = NULL;
    size_t data_size;
    size_t data_length = 0;
    libspectrum_byte *data_ptr = data;
    long scale = 3500000/sample_rate;
    libspectrum_tape_block_state it;
    libspectrum_byte *length_ptr;

    libspectrum_make_room( &data, 8192, &data_ptr, &data_size );

    if( libspectrum_tape_block_internal_init( &it, tape ) ) {
        while( !(flags & LIBSPECTRUM_TAPE_FLAGS_STOP) ) {
            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 ) return error;

            balance_tstates += pulse_tstates;

            if( flags & LIBSPECTRUM_TAPE_FLAGS_NO_EDGE ) continue;

            /* next RLE value is: balance_tstates / scale; */
            pulse_length = balance_tstates / scale;
            balance_tstates = balance_tstates % scale;

            if( pulse_length ) {
                if( data_size < (data_length + 1 + sizeof(libspectrum_dword) ) )
                    libspectrum_make_room( &data, data_size*2, &data_ptr, &data_size );

                if( pulse_length <= 0xff ) {
                    *data_ptr++ = pulse_length;
                    data_length++;
                } else {
                    *data_ptr++ = 0;
                    data_length++;
                    libspectrum_write_dword( &data_ptr, pulse_length );
                    data_length+=sizeof(libspectrum_dword);
                }
            }
        }
    }

    /* Write the length in */
    length_ptr = *buffer + length_offset;
    libspectrum_write_dword( &length_ptr, data_length );

    /* compression type */
#ifdef HAVE_ZLIB_H
    if( data_length ) {
        libspectrum_byte *compressed_data = NULL;
        size_t compressed_length;

        error = libspectrum_zlib_compress( data, data_length,
                                           &compressed_data, &compressed_length );
        libspectrum_free( data );
        if( error ) return error;

        data = compressed_data;
        data_length = compressed_length;
    }
#endif

    if( data_length ) {
        libspectrum_make_room( buffer, data_length, &ptr, length );
        memcpy( ptr, data, data_length );
        ptr += data_length;
        libspectrum_free( data );
    }

    return LIBSPECTRUM_ERROR_NONE;
}
Example #3
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 );
}