/* z80em.c: Routines for handling Z80Em raw audio files Copyright (c) 2002 Darren Salt Based on tap.c, copyright (c) 2001 Philip Kendall $Id: z80em.c,v 1.1 2005/12/20 13:20:49 pak21 Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Author contact information: E-mail: linux@youmustbejoking.demon.co.uk */ #include #include #include "internals.h" #include "tape_block.h" 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; libspectrum_error error; 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; } /* Claim memory for the block */ block = malloc( sizeof( *block ) ); if( !block ) { libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY, "libspectrum_z80em_read: out of memory" ); return LIBSPECTRUM_ERROR_MEMORY; } /* Set the block type */ block->type = 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 = malloc( length ); if( !z80em_block->data ) { free( block ); libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY, "libspectrum_z80em_read: out of memory" ); return LIBSPECTRUM_ERROR_MEMORY; } /* Copy the data across */ memcpy( z80em_block->data, buffer, length ); /* Put the block into the block list */ error = libspectrum_tape_append_block( tape, block ); if( error ) { free( z80em_block->data ); libspectrum_tape_block_free( block ); return error; } return LIBSPECTRUM_ERROR_NONE; } 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; libspectrum_error error; int compressed; static const char id[23] = "Compressed Square Wave\x1a"; if( length < sizeof( id ) + 2 ) goto csw_short; if( memcmp( id, buffer, sizeof( id ) ) ) { libspectrum_print_error( LIBSPECTRUM_ERROR_SIGNATURE, "libspectrum_csw_read: wrong signature" ); return LIBSPECTRUM_ERROR_SIGNATURE; } /* Claim memory for the block */ block = malloc( sizeof( *block ) ); if( !block ) goto csw_nomem; /* Set the block type */ block->type = LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE; csw_block = &block->types.rle_pulse; buffer += sizeof( id ); length -= sizeof( id ); 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; length -= 29 - buffer[12]; if( length < 0 ) goto csw_short; 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( compressed ) { /* Compressed data... */ #ifdef HAVE_ZLIB_H 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 = malloc( length ); if( !csw_block->data ) goto csw_nomem; /* Copy the data across */ memcpy( csw_block->data, buffer, length ); } /* Put the block into the block list */ error = libspectrum_tape_append_block( tape, block ); if( error ) { free (csw_block->data); libspectrum_tape_block_free( block ); return error; } /* Successful completion */ return LIBSPECTRUM_ERROR_NONE; /* Error returns */ csw_bad_compress: free( block ); libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY, "libspectrum_csw_read: unknown compression type" ); return LIBSPECTRUM_ERROR_CORRUPT; csw_nomem: free( block ); libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY, "libspectrum_csw_read: out of memory" ); return LIBSPECTRUM_ERROR_MEMORY; csw_short: free( block ); libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "libspectrum_csw_read: not enough data in buffer" ); return LIBSPECTRUM_ERROR_CORRUPT; }