Skip to content

Commit

Permalink
formats/h8_cas.cpp: Update H8T to newer cassette handling (#13250)
Browse files Browse the repository at this point in the history
  • Loading branch information
mgarlanger authored Feb 3, 2025
1 parent 1c491a1 commit 3e58355
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 111 deletions.
159 changes: 50 additions & 109 deletions src/lib/formats/h8_cas.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// license:BSD-3-Clause
// copyright-holders:Robbbert
// copyright-holders:Robbbert,Mark Garlanger
/********************************************************************
Support for Heathkit H8 H8T cassette images
Support for Heathkit H8/H88 H8T cassette images
Standard Kansas City format (300 baud)
Expand All @@ -15,138 +15,79 @@ We output a leader, followed by the contents of the H8T file.

#include "h8_cas.h"

#include <algorithm>
#include "coretmpl.h" // BIT


static constexpr uint16_t WAVEENTRY_LOW = -32768;
static constexpr uint16_t WAVEENTRY_HIGH = 32767;
static constexpr uint16_t SILENCE = 0;
namespace {

// using a multiple of 4800 will ensure an integer multiple of samples for each wave.
static constexpr uint16_t H8_WAV_FREQUENCY = 9600;
static constexpr uint16_t TAPE_BAUD_RATE = 300;
static constexpr uint16_t SAMPLES_PER_BIT = H8_WAV_FREQUENCY / TAPE_BAUD_RATE;
static constexpr uint16_t SAMPLES_PER_HALF_WAVE = SAMPLES_PER_BIT / 2;
static constexpr double ONE_FREQ = 1200.0;
static constexpr double ONE_FREQ_VARIANCE = 300.0;
static constexpr double ZERO_FREQ = 2400.0;
static constexpr double ZERO_FREQ_VARIANCE = 600.0;

static constexpr uint16_t ONE_FREQ = 1200;
static constexpr uint16_t ZERO_FREQ = 2400;
static constexpr uint16_t ONE_CYCLES = H8_WAV_FREQUENCY / ONE_FREQ;
static constexpr uint16_t ZERO_CYCLES = H8_WAV_FREQUENCY / ZERO_FREQ;

// image size
static int h8_image_size; // FIXME: global variable prevents multiple instances

static int h8_put_samples(int16_t *buffer, int sample_pos, int count, int level)
static const cassette_image::Modulation heath_h8t_modulation =
{
if (buffer)
{
std::fill_n(&buffer[sample_pos], count, level);
}

return count;
}
cassette_image::MODULATION_SINEWAVE,
ONE_FREQ - ONE_FREQ_VARIANCE, ONE_FREQ, ONE_FREQ + ONE_FREQ_VARIANCE,
ZERO_FREQ - ZERO_FREQ_VARIANCE, ZERO_FREQ, ZERO_FREQ + ZERO_FREQ_VARIANCE
};

static int h8_output_bit(int16_t *buffer, int sample_pos, bool bit)
static cassette_image::error heath_h8t_identify(cassette_image *cassette, cassette_image::Options *opts)
{
int samples = 0;

const int loops = bit ? ONE_CYCLES : ZERO_CYCLES;
const int samplePerValue = SAMPLES_PER_HALF_WAVE / loops;

for (int i = 0; i < loops; i++)
{
samples += h8_put_samples(buffer, sample_pos + samples, samplePerValue, WAVEENTRY_LOW);
samples += h8_put_samples(buffer, sample_pos + samples, samplePerValue, WAVEENTRY_HIGH);
}

return samples;
return cassette->modulation_identify(heath_h8t_modulation, opts);
}

static int h8_output_byte(int16_t *buffer, int sample_pos, uint8_t data)
{
int samples = 0;

// start bit
samples += h8_output_bit(buffer, sample_pos + samples, 0);

// data bits
for (int i = 0; i < 8; i++)
{
samples += h8_output_bit(buffer, sample_pos + samples, data & 1);
data >>= 1;
#define MODULATE(_value) \
for (int i = 0; i < (_value ? 8 : 4); i++) { \
err = cassette->put_modulated_data_bit(0, time_index, _value, heath_h8t_modulation, &time_displacement); \
if (err != cassette_image::error::SUCCESS) return err; \
time_index += time_displacement; \
}

// stop bit
samples += h8_output_bit(buffer, sample_pos + samples, 1);

return samples;
}

static int h8_handle_cassette(int16_t *buffer, const uint8_t *bytes)
static cassette_image::error heath_h8t_load(cassette_image *cassette)
{
int sample_count = 0;
cassette_image::error err = cassette_image::error::SUCCESS;
uint64_t image_size = cassette->image_size();
double time_index = 0.0;
double time_displacement;

// leader - 1 second
for (int i = 0; i < TAPE_BAUD_RATE; i++)
sample_count += h8_output_bit(buffer, sample_count, 1);

// data
for (int i = 0; i < h8_image_size; i++)
sample_count += h8_output_byte(buffer, sample_count, bytes[i]);

return sample_count;
}


/*******************************************************************
Generate samples for the tape image
********************************************************************/

static int h8_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes)
{
return h8_handle_cassette(buffer, bytes);
}

/*******************************************************************
Calculate the number of samples needed for this tape image
********************************************************************/
while (time_index < 1.0)
{
MODULATE(1);
}

static int h8_cassette_calculate_size_in_samples(const uint8_t *bytes, int length)
{
h8_image_size = length;
for (uint64_t image_pos = 0; image_pos < image_size; image_pos++)
{
uint8_t data = cassette->image_read_byte(image_pos);

return h8_handle_cassette(nullptr, bytes);
}
// start bit
MODULATE(0);

static const cassette_image::LegacyWaveFiller h8_legacy_fill_wave =
{
h8_cassette_fill_wave, // fill_wave
-1, // chunk_size
0, // chunk_samples
h8_cassette_calculate_size_in_samples, // chunk_sample_calc
H8_WAV_FREQUENCY, // sample_frequency
0, // header_samples
0 // trailer_samples
};
// data bits
for (int bit = 0; bit < 8; bit++)
{
MODULATE(util::BIT(data, bit));
}

static cassette_image::error h8_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
return cassette->legacy_identify(opts, &h8_legacy_fill_wave);
}
// stop bit
MODULATE(1);
}

static cassette_image::error h8_cassette_load(cassette_image *cassette)
{
return cassette->legacy_construct(&h8_legacy_fill_wave);
return err;
}

static const cassette_image::Format h8_cassette_image_format =
const cassette_image::Format heath_h8t_format =
{
"h8t",
h8_cassette_identify,
h8_cassette_load,
heath_h8t_identify,
heath_h8t_load,
nullptr
};

CASSETTE_FORMATLIST_START(h8_cassette_formats)
CASSETTE_FORMAT(h8_cassette_image_format)
}

CASSETTE_FORMATLIST_START( h8_cassette_formats )
CASSETTE_FORMAT( heath_h8t_format )
CASSETTE_FORMATLIST_END
4 changes: 2 additions & 2 deletions src/lib/formats/h8_cas.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// license:BSD-3-Clause
// copyright-holders:Robbbert
// copyright-holders:Robbbert,Mark Garlanger
/*********************************************************************
h8_cas.h
Format code for Heathkit H8 H8T cassette images
Format code for Heathkit H8/H88 H8T cassette images
*********************************************************************/
#ifndef MAME_FORMATS_H8_CAS_H
Expand Down

0 comments on commit 3e58355

Please sign in to comment.