mirror of
https://github.com/holub/mame
synced 2025-05-23 14:19:01 +03:00

Use standard uint64_t, uint32_t, uint16_t or uint8_t instead of UINT64, UINT32, UINT16 or UINT8 also use standard int64_t, int32_t, int16_t or int8_t instead of INT64, INT32, INT16 or INT8
202 lines
4.2 KiB
C++
202 lines
4.2 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Miodrag Milanovic
|
|
/*
|
|
|
|
Tape support for Glaksija GTP format
|
|
|
|
Miodrag Milanovic
|
|
*/
|
|
#include <assert.h>
|
|
|
|
#include "gtp_cas.h"
|
|
|
|
|
|
#define GTP_WAV_FREQUENCY 44100
|
|
#define WAVE_LOW -0x5a9e
|
|
#define WAVE_HIGH 0x5a9e
|
|
#define WAVE_NULL 0
|
|
|
|
#define GTP_BLOCK_STANDARD 0x00
|
|
#define GTP_BLOCK_TURBO 0x01
|
|
#define GTP_BLOCK_NAME 0x10
|
|
|
|
static int16_t wave_data;
|
|
static int16_t len;
|
|
|
|
#define PULSE_WIDTH 30
|
|
#define PERIOD_BASE 150
|
|
#define PERIOD_1 75
|
|
#define PERIOD_0 150
|
|
|
|
#define INTERBYTE_PAUSE 225
|
|
#define INTERBLOCK_PAUSE 100000
|
|
|
|
|
|
static void gtp_output_wave( int16_t **buffer, int length ) {
|
|
if ( buffer == nullptr ) {
|
|
return;
|
|
}
|
|
|
|
for( ; length > 0; length-- ) {
|
|
**buffer = wave_data;
|
|
*buffer = *buffer + 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int gtp_mod_1( int16_t **buffer )
|
|
{
|
|
wave_data = WAVE_LOW;
|
|
gtp_output_wave(buffer,PULSE_WIDTH);
|
|
wave_data = WAVE_HIGH;
|
|
gtp_output_wave(buffer,PULSE_WIDTH);
|
|
wave_data = WAVE_NULL;
|
|
gtp_output_wave(buffer,PERIOD_1 - 2 * PULSE_WIDTH);
|
|
wave_data = WAVE_LOW;
|
|
gtp_output_wave(buffer,PULSE_WIDTH);
|
|
wave_data = WAVE_HIGH;
|
|
gtp_output_wave(buffer,PULSE_WIDTH);
|
|
wave_data = WAVE_NULL;
|
|
gtp_output_wave(buffer,PERIOD_1 - 2 * PULSE_WIDTH);
|
|
|
|
return PERIOD_1 * 2;
|
|
}
|
|
|
|
static int gtp_mod_0( int16_t **buffer )
|
|
{
|
|
wave_data = WAVE_LOW;
|
|
gtp_output_wave(buffer,PULSE_WIDTH);
|
|
wave_data = WAVE_HIGH;
|
|
gtp_output_wave(buffer,PULSE_WIDTH);
|
|
wave_data = WAVE_NULL;
|
|
gtp_output_wave(buffer,PERIOD_0 - 2 * PULSE_WIDTH);
|
|
|
|
return PERIOD_0;
|
|
}
|
|
|
|
static int gtp_byte( int16_t **buffer, uint8_t val )
|
|
{
|
|
uint8_t b;
|
|
int j,size = 0;
|
|
for (j=0;j<8;j++) {
|
|
b = (val >> j) & 1;
|
|
if (b==0) {
|
|
size += gtp_mod_0(buffer);
|
|
} else {
|
|
size += gtp_mod_1(buffer);
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static int gtp_sync( int16_t **buffer )
|
|
{
|
|
int i;
|
|
int size = 0;
|
|
|
|
for(i=0;i<100;i++) {
|
|
if (i!=0) {
|
|
// Interbyte pause
|
|
wave_data = WAVE_NULL;
|
|
gtp_output_wave(buffer,INTERBYTE_PAUSE);
|
|
size += INTERBYTE_PAUSE;
|
|
}
|
|
size += gtp_byte(buffer,0);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static int gtp_cas_to_wav_size( const uint8_t *casdata, int caslen ) {
|
|
int size,n;
|
|
size = 0;
|
|
n = 0;
|
|
if (casdata == nullptr) return -1;
|
|
while(n<caslen) {
|
|
int block_type = casdata[n];
|
|
int block_size = casdata[n+2]*256 + casdata[n+1];
|
|
n+=5;
|
|
if (block_type==GTP_BLOCK_STANDARD) {
|
|
// Interblock pause
|
|
size += INTERBLOCK_PAUSE;
|
|
size += 100 * (PERIOD_0 * 8 + INTERBYTE_PAUSE) - INTERBYTE_PAUSE;
|
|
size += (PERIOD_0 * 8 + INTERBYTE_PAUSE) * block_size;
|
|
}
|
|
n += block_size;
|
|
}
|
|
len = caslen;
|
|
return size;
|
|
}
|
|
|
|
static int gtp_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) {
|
|
int i,size,n;
|
|
size = 0;
|
|
n = 0;
|
|
if (bytes == nullptr) return -1;
|
|
while(n<len)
|
|
{
|
|
int block_type = bytes[n];
|
|
int block_size = bytes[n+2]*256 + bytes[n+1];
|
|
n+=5;
|
|
if (block_type==GTP_BLOCK_STANDARD) {
|
|
// Interblock pause
|
|
wave_data = WAVE_NULL;
|
|
gtp_output_wave(&buffer,INTERBLOCK_PAUSE);
|
|
size += INTERBLOCK_PAUSE;
|
|
size += gtp_sync(&buffer);
|
|
|
|
for (i=0;i<block_size;i++) {
|
|
// Interbyte pause
|
|
wave_data = WAVE_NULL;
|
|
gtp_output_wave(&buffer,INTERBYTE_PAUSE);
|
|
size += INTERBYTE_PAUSE;
|
|
|
|
size += gtp_byte(&buffer,bytes[n]);
|
|
n++;
|
|
}
|
|
} else {
|
|
n += block_size;
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct CassetteLegacyWaveFiller gtp_legacy_fill_wave = {
|
|
gtp_cas_fill_wave, /* fill_wave */
|
|
-1, /* chunk_size */
|
|
0, /* chunk_samples */
|
|
gtp_cas_to_wav_size, /* chunk_sample_calc */
|
|
GTP_WAV_FREQUENCY, /* sample_frequency */
|
|
0, /* header_samples */
|
|
0 /* trailer_samples */
|
|
};
|
|
|
|
|
|
|
|
static cassette_image::error gtp_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
|
|
return cassette_legacy_identify( cassette, opts, >p_legacy_fill_wave );
|
|
}
|
|
|
|
|
|
|
|
static cassette_image::error gtp_cassette_load( cassette_image *cassette ) {
|
|
return cassette_legacy_construct( cassette, >p_legacy_fill_wave );
|
|
}
|
|
|
|
|
|
|
|
static const struct CassetteFormat gtp_cassette_format = {
|
|
"gtp",
|
|
gtp_cassette_identify,
|
|
gtp_cassette_load,
|
|
nullptr
|
|
};
|
|
|
|
|
|
CASSETTE_FORMATLIST_START(gtp_cassette_formats)
|
|
CASSETTE_FORMAT(gtp_cassette_format)
|
|
CASSETTE_FORMATLIST_END
|