summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2012-05-23 07:22:13 +0000
committer Miodrag Milanovic <mmicko@gmail.com>2012-05-23 07:22:13 +0000
commit4580108461881099f6ecb64b0fc581c1dd13a01a (patch)
tree0d8c479c5e71f31600a5265e21cf9b18b058d1ff /src/lib
parent5a9721414e94b4f87874925e4d35e4041c866e5e (diff)
Sync with MESS changes for cassette by S.Ronco (no whatsnew)
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/formats/cassimg.c5
-rw-r--r--src/lib/formats/cassimg.h1
-rw-r--r--src/lib/formats/tvc_cas.c225
-rw-r--r--src/lib/formats/tvc_cas.h16
-rw-r--r--src/lib/formats/wavfile.c2
-rw-r--r--src/lib/lib.mak1
6 files changed, 248 insertions, 2 deletions
diff --git a/src/lib/formats/cassimg.c b/src/lib/formats/cassimg.c
index 809a60ce26a..f17f0f1906f 100644
--- a/src/lib/formats/cassimg.c
+++ b/src/lib/formats/cassimg.c
@@ -549,7 +549,10 @@ casserr_t cassette_put_samples(cassette_image *cassette, int channel,
/* compute the value that we are writing */
switch(waveform_bytes_per_sample(waveform_flags)) {
case 1:
- dest_value = extrapolate8(*((INT8 *) source_ptr));
+ if (waveform_flags & CASSETTE_WAVEFORM_UNSIGNED)
+ dest_value = extrapolate8((INT8)(*source_ptr - 128));
+ else
+ dest_value = extrapolate8(*((INT8 *) source_ptr));
break;
case 2:
word = *((INT16 *) source_ptr);
diff --git a/src/lib/formats/cassimg.h b/src/lib/formats/cassimg.h
index cdbaff04ca6..9f665ff0d42 100644
--- a/src/lib/formats/cassimg.h
+++ b/src/lib/formats/cassimg.h
@@ -34,6 +34,7 @@
#define CASSETTE_WAVEFORM_32BIT 4
#define CASSETTE_WAVEFORM_32BIT_FLIP 5
#define CASSETTE_WAVEFORM_ENDIAN_FLIP 1
+#define CASSETTE_WAVEFORM_UNSIGNED 8
#define CASSETTE_MODULATION_SQUAREWAVE 0
#define CASSETTE_MODULATION_SINEWAVE 1
diff --git a/src/lib/formats/tvc_cas.c b/src/lib/formats/tvc_cas.c
new file mode 100644
index 00000000000..5b7e6f8a422
--- /dev/null
+++ b/src/lib/formats/tvc_cas.c
@@ -0,0 +1,225 @@
+/********************************************************************
+
+ Support for Videoton TVC .cas files
+
+ http://tvc.homeserver.hu/html/konvertformatum.html
+
+********************************************************************/
+
+#include "tvc_cas.h"
+
+#define TVC64_BIT0_FREQ 1812
+#define TVC64_BIT1_FREQ 2577
+#define TVC64_PRE_FREQ 2128
+#define TVC64_SYNC_FREQ 1359
+
+#define WAVE_AMPLITUDE 0x3fffffff
+#define TVC64_HEADER_BYTES 0x90
+#define TVC64_HEADER_BYTES 0x90
+
+static void tvc64_emit_level(cassette_image *cass, double &time, int freq, int level)
+{
+ double period = 1.0 / freq;
+ cassette_put_sample(cass, 0, time, period, level * WAVE_AMPLITUDE);
+ time += period;
+}
+
+static casserr_t tvc64_output_byte(cassette_image *cass, double &time, UINT8 byte)
+{
+ for (int i=0; i<8; i++)
+ {
+ if ((byte>>i) & 0x01)
+ {
+ tvc64_emit_level(cass, time, TVC64_BIT1_FREQ*2, +1);
+ tvc64_emit_level(cass, time, TVC64_BIT1_FREQ*2, -1);
+ }
+ else
+ {
+ tvc64_emit_level(cass, time, TVC64_BIT0_FREQ*2, +1);
+ tvc64_emit_level(cass, time, TVC64_BIT0_FREQ*2, -1);
+ }
+ }
+
+ return CASSETTE_ERROR_SUCCESS;
+}
+
+static int tvc64_output_predata(cassette_image *cass, double &time, int number)
+{
+ for (int i=0; i<number; i++)
+ {
+ tvc64_emit_level(cass, time, TVC64_PRE_FREQ*2, +1);
+ tvc64_emit_level(cass, time, TVC64_PRE_FREQ*2, -1);
+ }
+
+ return CASSETTE_ERROR_SUCCESS;
+}
+
+static UINT16 tvc64_calc_crc(const UINT8 *bytes, int size)
+{
+ UINT16 crc = 0;
+
+ for (int i=0; i<size; i++)
+ {
+ for (int b=0; b<8; b++)
+ {
+ UINT8 al = (bytes[i] & (1<<b)) ? 0x80 : 0x00;
+
+ al ^= ((crc>>8) & 0xff);
+
+ if (al & 0x80)
+ crc ^= 0x0810;
+
+ crc <<= 1;
+
+ if (al & 0x80) crc += 1;
+ }
+ }
+
+ return crc;
+}
+
+static casserr_t tvc64_cassette_load(cassette_image *cassette)
+{
+ UINT8 tmp_buff[512];
+ int buff_idx = 0;
+ double time = 0.0;
+
+ UINT8 header[TVC64_HEADER_BYTES];
+ cassette_image_read(cassette, header, 0, TVC64_HEADER_BYTES);
+ UINT16 cas_size = (header[0x83]<<8) | header[0x82];
+
+ // tape header
+ tmp_buff[buff_idx++] = 0x00;
+ tmp_buff[buff_idx++] = 0x6a;
+ tmp_buff[buff_idx++] = 0xff; // head sector
+ tmp_buff[buff_idx++] = 0x11; // not puffered
+ tmp_buff[buff_idx++] = 0x00; // not write protected
+ tmp_buff[buff_idx++] = 0x01; // 1 sector
+ tmp_buff[buff_idx++] = 0x00; // sector number
+ tmp_buff[buff_idx++] = 0x12; // head size
+ tmp_buff[buff_idx++] = 0x01; // name size
+ tmp_buff[buff_idx++] = ' '; // name
+ tmp_buff[buff_idx++] = 0x00;
+ tmp_buff[buff_idx++] = header[0x81]; // type
+ tmp_buff[buff_idx++] = header[0x82]; // size LSB
+ tmp_buff[buff_idx++] = header[0x83]; // size MSB
+ tmp_buff[buff_idx++] = header[0x84]; // autostart
+
+ // sector fill
+ for (int i=0; i<10 ; i++)
+ tmp_buff[buff_idx++] = 0x00;
+
+ tmp_buff[buff_idx++] = 0x00; // file version
+ tmp_buff[buff_idx++] = 0x00; // no last sector
+
+ // updates the header CRC
+ UINT16 crc = tvc64_calc_crc(tmp_buff, buff_idx);
+ tmp_buff[buff_idx++] = crc & 0xff;
+ tmp_buff[buff_idx++] = (crc>>8) & 0xff;
+
+ // 2 sec silence
+ tvc64_emit_level(cassette, time, 2, 0);
+
+ // 10240 pre data cycles
+ tvc64_output_predata(cassette, time, 10240);
+
+ // 1 synchro cycle
+ tvc64_emit_level(cassette, time, TVC64_SYNC_FREQ*2, +1);
+ tvc64_emit_level(cassette, time, TVC64_SYNC_FREQ*2, -1);
+
+ // header data
+ for (int i=0; i<buff_idx; i++)
+ tvc64_output_byte(cassette, time, tmp_buff[i]);
+
+ // 5 post data cycles
+ tvc64_output_predata(cassette, time, 5);
+
+ // 1 sec silence
+ tvc64_emit_level(cassette, time, 1, 0);
+
+ // 5120 pre data cycles
+ tvc64_output_predata(cassette, time, 5120);
+
+ // 1 synchro cycle
+ tvc64_emit_level(cassette, time, TVC64_SYNC_FREQ*2, +1);
+ tvc64_emit_level(cassette, time, TVC64_SYNC_FREQ*2, -1);
+
+ // first data sector contain the data header
+ buff_idx = 0;
+ tmp_buff[buff_idx++] = 0x00;
+ tmp_buff[buff_idx++] = 0x6a;
+ tmp_buff[buff_idx++] = 0x00; // data sector
+ tmp_buff[buff_idx++] = 0x11; // not puffered
+ tmp_buff[buff_idx++] = 0x00; // not write protected
+ tmp_buff[buff_idx++] = (UINT8)((cas_size / 256) + ((cas_size % 256) > 0 ? 1 : 0)); // number of sectors
+
+ UINT8 sect_num = 1;
+ int sector_num = cas_size / 256;
+ for (int i=0; i<=sector_num; i++)
+ {
+ tmp_buff[buff_idx++] = sect_num++; // sector number
+
+ // sector size
+ if (i == sector_num)
+ tmp_buff[buff_idx++] = cas_size % 256;
+ else
+ tmp_buff[buff_idx++] = 0x00;
+
+ // sector data
+ int sector_size = (i == sector_num) ? (cas_size % 256) : 256;
+ for (int z=0; z < sector_size; z++)
+ cassette_image_read(cassette, &tmp_buff[buff_idx++], TVC64_HEADER_BYTES + i*256 + z, 1);
+
+ if (i == sector_num || ((i+1) == sector_num && (cas_size % 256 ) == 0))
+ tmp_buff[buff_idx++] = 0xff; // last sector
+ else
+ tmp_buff[buff_idx++] = 0x00; // no last sector
+
+ // sector crc
+ crc = tvc64_calc_crc(tmp_buff, buff_idx);
+ tmp_buff[buff_idx++] = crc & 0xff;
+ tmp_buff[buff_idx++] = (crc>>8) & 0xff;
+
+ // output the sector
+ for (int z=0; z<buff_idx; z++)
+ tvc64_output_byte(cassette, time, tmp_buff[z]);
+
+ buff_idx = 0;
+ }
+
+ // 5 post data cycles
+ tvc64_output_predata(cassette, time, 5);
+
+ // 1 sec silence
+ tvc64_emit_level(cassette, time, 1, 0);
+
+ return CASSETTE_ERROR_SUCCESS;
+}
+
+static casserr_t tvc64_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+{
+ UINT8 byte;
+ cassette_image_read(cassette, &byte, 0, 1);
+
+ if (byte == 0x11)
+ {
+ opts->bits_per_sample = 16;
+ opts->channels = 1;
+ opts->sample_frequency = 44100;
+ return CASSETTE_ERROR_SUCCESS;
+ }
+
+ return CASSETTE_ERROR_INVALIDIMAGE;
+}
+
+static const struct CassetteFormat tvc64_cassette_image_format =
+{
+ "cas",
+ tvc64_cassette_identify,
+ tvc64_cassette_load,
+ NULL
+};
+
+CASSETTE_FORMATLIST_START(tvc64_cassette_formats)
+ CASSETTE_FORMAT(tvc64_cassette_image_format)
+CASSETTE_FORMATLIST_END
diff --git a/src/lib/formats/tvc_cas.h b/src/lib/formats/tvc_cas.h
new file mode 100644
index 00000000000..7dc7a67e10c
--- /dev/null
+++ b/src/lib/formats/tvc_cas.h
@@ -0,0 +1,16 @@
+/*********************************************************************
+
+ tvc_cas.h
+
+ Format code for Videoton TVC casette files
+
+*********************************************************************/
+
+#ifndef TVC_CAS_H
+#define TVC_CAS_H
+
+#include "cassimg.h"
+
+CASSETTE_FORMATLIST_EXTERN(tvc64_cassette_formats);
+
+#endif /* TVC_CAS_H */
diff --git a/src/lib/formats/wavfile.c b/src/lib/formats/wavfile.c
index da3615a9382..2577a908025 100644
--- a/src/lib/formats/wavfile.c
+++ b/src/lib/formats/wavfile.c
@@ -119,7 +119,7 @@ static casserr_t wavfile_process(cassette_image *cassette, struct CassetteOption
switch(opts->bits_per_sample)
{
case 8:
- waveform_flags = CASSETTE_WAVEFORM_8BIT;
+ waveform_flags = CASSETTE_WAVEFORM_8BIT | CASSETTE_WAVEFORM_UNSIGNED; // 8-bits wav are stored unsigned
break;
case 16:
waveform_flags = CASSETTE_WAVEFORM_16BITLE;
diff --git a/src/lib/lib.mak b/src/lib/lib.mak
index a2eb8f237c9..3dbe5fcef40 100644
--- a/src/lib/lib.mak
+++ b/src/lib/lib.mak
@@ -155,6 +155,7 @@ FORMATSOBJS = \
$(LIBOBJ)/formats/trd_dsk.o \
$(LIBOBJ)/formats/trs_cas.o \
$(LIBOBJ)/formats/trs_dsk.o \
+ $(LIBOBJ)/formats/tvc_cas.o \
$(LIBOBJ)/formats/tzx_cas.o \
$(LIBOBJ)/formats/uef_cas.o \
$(LIBOBJ)/formats/vg5k_cas.o \