summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/tzx_cas.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats/tzx_cas.c')
-rw-r--r--src/lib/formats/tzx_cas.c249
1 files changed, 241 insertions, 8 deletions
diff --git a/src/lib/formats/tzx_cas.c b/src/lib/formats/tzx_cas.c
index 6037c200122..225184b7bd0 100644
--- a/src/lib/formats/tzx_cas.c
+++ b/src/lib/formats/tzx_cas.c
@@ -43,7 +43,8 @@ We are currently using the numbers from the TZX specification...
#include <assert.h>
#include "tzx_cas.h"
-
+#include "formats/imageutl.h"
+#include "emu.h"
#define TZX_WAV_FREQUENCY 44100
#define WAVE_LOW -0x5a9e
@@ -296,6 +297,214 @@ static int tzx_cas_handle_block( INT16 **buffer, const UINT8 *bytes, int pause,
return size;
}
+static int tzx_handle_direct(INT16 **buffer, const UINT8 *bytes, int pause, int data_size, int tstates, int bits_in_last_byte)
+{
+ int size = 0;
+ int samples = tcycles_to_samplecount(tstates);
+
+ /* data */
+ for (int data_index = 0; data_index < data_size; data_index++)
+ {
+ UINT8 byte = bytes[data_index];
+ int bits_to_go = (data_index == (data_size - 1)) ? bits_in_last_byte : 8;
+
+ for ( ; bits_to_go > 0; byte <<= 1, bits_to_go--)
+ {
+ if (byte & 0x80) wave_data = WAVE_HIGH;
+ else wave_data = WAVE_LOW;
+
+ tzx_output_wave(buffer, samples);
+ size += samples;
+
+ }
+ }
+
+ /* pause */
+ if (pause > 0)
+ {
+ int start_pause_samples = millisec_to_samplecount(1);
+ int rest_pause_samples = millisec_to_samplecount(pause - 1);
+
+ tzx_output_wave(buffer, start_pause_samples);
+ size += start_pause_samples;
+ wave_data = WAVE_LOW;
+ tzx_output_wave(buffer, rest_pause_samples);
+ size += rest_pause_samples;
+ }
+ return size;
+}
+
+
+INLINE int tzx_handle_symbol(INT16 **buffer, const UINT8 *symtable, UINT8 symbol, int maxp)
+{
+ int size = 0;
+ const UINT8 *cursymb = symtable + (2 * maxp + 1)*symbol;
+
+ UINT8 starttype = cursymb[0];
+
+// printf("start polarity %01x (max number of symbols is %d)\n", starttype, maxp);
+
+ switch (starttype)
+ {
+ case 0x00:
+ toggle_wave_data();
+ break;
+
+ case 0x01:
+ // don't change
+ break;
+
+ case 0x02:
+ // force low
+ wave_data = WAVE_LOW;
+ break;
+
+ case 0x03:
+ // force high
+ wave_data = WAVE_HIGH;
+ break;
+
+ default:
+ printf("SYMDEF invalid - bad starting polarity");
+ }
+
+ for (int i = 0; i < maxp; i++)
+ {
+ UINT16 pulse_length = cursymb[1 + (i*2)] | (cursymb[2 + (i*2)] << 8);
+ // printf("pulse_length %04x\n", pulse_length);
+
+ // shorter lists can be terminated with a pulse_length of 0
+ if (pulse_length != 0)
+ {
+
+
+ int samples = tcycles_to_samplecount(pulse_length);
+ tzx_output_wave(buffer, samples);
+ size += samples;
+ toggle_wave_data();
+
+ }
+ else
+ {
+ toggle_wave_data();
+ i = maxp;
+ continue;
+ }
+ }
+
+ //toggle_wave_data();
+
+ return size;
+}
+
+INLINE int stream_get_bit(const UINT8 *bytes, UINT8 &stream_bit, UINT32 &stream_byte)
+{
+ // get bit here
+ UINT8 retbit = 0;
+
+ UINT8 byte = bytes[stream_byte];
+ byte = byte << stream_bit;
+
+ if (byte & 0x80) retbit = 1;
+
+
+ stream_bit++;
+
+ if (stream_bit == 8)
+ {
+ stream_bit = 0;
+ stream_byte++;
+ }
+
+ return retbit;
+}
+
+static int tzx_handle_generalized(INT16 **buffer, const UINT8 *bytes, int pause, int data_size, UINT32 totp, int npp, int asp, UINT32 totd, int npd, int asd )
+{
+ int size = 0;
+
+ if (totp > 0)
+ {
+ // printf("pilot block table %04x\n", totp);
+
+ const UINT8 *symtable = bytes;
+ const UINT8 *table2 = symtable + (2 * npp + 1)*asp;
+
+ // the Pilot and sync data stream has an RLE encoding
+ for (int i = 0; i < totp; i+=3)
+ {
+ UINT8 symbol = table2[i + 0];
+ UINT16 repetitions = table2[i + 1] + (table2[i + 2] << 8);
+ //printf("symbol %02x repititions %04x\n", symbol, repetitions); // does 1 mean repeat once, or that it only occurs once?
+
+ for (int j = 0; j < repetitions; j++)
+ {
+ size += tzx_handle_symbol(buffer, symtable, symbol, npp);
+ // toggle_wave_data();
+ }
+
+
+ }
+
+ // advance to after this data
+ bytes += ((2 * npp + 1)*asp) + totp * 3;
+ }
+ else
+ {
+ printf("no pilot block\n");
+ }
+
+ if (totd > 0)
+ {
+ printf("data block table %04x (has %0d symbols, max symbol length is %d)\n", totd, asd, npd);
+
+ const UINT8 *symtable = bytes;
+ const UINT8 *table2 = bytes + (2 * npd + 1)*asd;
+
+ int NB = ceil(compute_log2(asd)); // number of bits needed to represent each symbol
+ printf("NB is %d\n", NB);
+
+ UINT8 stream_bit = 0;
+ UINT32 stream_byte = 0;
+
+ for (int i = 0; i < totd; i++)
+ {
+ UINT8 symbol = 0;
+
+ for (int j = 0; j < NB; j++)
+ {
+ symbol |= stream_get_bit(table2, stream_bit, stream_byte) << j;
+ }
+
+ size += tzx_handle_symbol(buffer, symtable, symbol, npd);
+
+ //toggle_wave_data();
+ }
+ }
+ else
+ {
+ printf("no data block\n");
+ }
+
+
+
+ /* pause */
+ if (pause > 0)
+ {
+ int start_pause_samples = millisec_to_samplecount(1);
+ int rest_pause_samples = millisec_to_samplecount(pause - 1);
+
+ tzx_output_wave(buffer, start_pause_samples);
+ size += start_pause_samples;
+ wave_data = WAVE_LOW;
+ tzx_output_wave(buffer, rest_pause_samples);
+ size += rest_pause_samples;
+ }
+ return size;
+}
+
+
+
static void ascii_block_common_log( const char *block_type_string, UINT8 block_type )
{
LOG_FORMATS("%s (type %02x) encountered.\n", block_type_string, block_type);
@@ -338,12 +547,13 @@ static int tzx_cas_do_work( INT16 **buffer )
while (current_block < block_count)
{
int pause_time;
- int data_size, text_size, total_size, i;
+ UINT32 data_size;
+ int text_size, total_size, i;
int pilot, pilot_length, sync1, sync2;
int bit0, bit1, bits_in_last_byte;
UINT8 *cur_block = blocks[current_block];
UINT8 block_type = cur_block[0];
-
+ UINT16 tstates = 0;
/* Uncomment this to include into error.log a list of the types each block */
LOG_FORMATS("tzx_cas_fill_wave: block %d, block_type %02x\n", current_block, block_type);
@@ -516,9 +726,13 @@ static int tzx_cas_do_work( INT16 **buffer )
current_block++;
break;
- case 0x15: /* Direct Recording */
+ case 0x15: /* Direct Recording */ // used on 'bombscar' in the cpc_cass list
// having this missing is fatal
- printf("Unsupported block type (0x15 - Direct Recording) encountered.\n");
+ tstates = cur_block[1] + (cur_block[2] << 8);
+ pause_time= cur_block[3] + (cur_block[4] << 8);
+ bits_in_last_byte = cur_block[5];
+ data_size = cur_block[6] + (cur_block[7] << 8) + (cur_block[8] << 16);
+ size += tzx_handle_direct(buffer, &cur_block[9], pause_time, data_size, tstates, bits_in_last_byte);
current_block++;
break;
@@ -529,9 +743,28 @@ static int tzx_cas_do_work( INT16 **buffer )
break;
case 0x19: /* Generalized Data Block */
- // having this missing is fatal
- printf("Unsupported block type (0x19 - Generalized Data Block) encountered.\n");
- current_block++;
+ {
+ // having this missing is fatal
+ // used crudely by batmanc in spectrum_cass list (which is just a redundant encoding of batmane ?)
+ printf("Unsupported block type (0x19 - Generalized Data Block) encountered.\n");
+
+ data_size = cur_block[1] + (cur_block[2] << 8) + (cur_block[3] << 16) + (cur_block[4] << 24);
+ pause_time= cur_block[5] + (cur_block[6] << 8);
+
+ UINT32 totp = cur_block[7] + (cur_block[8] << 8) + (cur_block[9] << 16) + (cur_block[10] << 24);
+ int npp = cur_block[11];
+ int asp = cur_block[12];
+ if (asp == 0) asp = 256;
+
+ UINT32 totd = cur_block[13] + (cur_block[14] << 8) + (cur_block[15] << 16) + (cur_block[16] << 24);
+ int npd = cur_block[17];
+ int asd = cur_block[18];
+ if (asd == 0) asd = 256;
+
+ size += tzx_handle_generalized(buffer, &cur_block[19], pause_time, data_size, totp, npp, asp, totd, npd, asd);
+
+ current_block++;
+ }
break;
}