1
1
// license:BSD-3-Clause
2
- // copyright-holders:Robbbert
2
+ // copyright-holders:Robbbert,Mark Garlanger
3
3
/* *******************************************************************
4
4
5
- Support for Heathkit H8 H8T cassette images
5
+ Support for Heathkit H8/H88 H8T cassette images
6
6
7
7
8
8
Standard Kansas City format (300 baud)
@@ -15,138 +15,79 @@ We output a leader, followed by the contents of the H8T file.
15
15
16
16
#include " h8_cas.h"
17
17
18
- #include < algorithm >
18
+ #include " coretmpl.h " // BIT
19
19
20
20
21
- static constexpr uint16_t WAVEENTRY_LOW = -32768 ;
22
- static constexpr uint16_t WAVEENTRY_HIGH = 32767 ;
23
- static constexpr uint16_t SILENCE = 0 ;
21
+ namespace {
24
22
25
- // using a multiple of 4800 will ensure an integer multiple of samples for each wave.
26
- static constexpr uint16_t H8_WAV_FREQUENCY = 9600 ;
27
- static constexpr uint16_t TAPE_BAUD_RATE = 300 ;
28
- static constexpr uint16_t SAMPLES_PER_BIT = H8_WAV_FREQUENCY / TAPE_BAUD_RATE;
29
- static constexpr uint16_t SAMPLES_PER_HALF_WAVE = SAMPLES_PER_BIT / 2 ;
23
+ static constexpr double ONE_FREQ = 1200.0 ;
24
+ static constexpr double ONE_FREQ_VARIANCE = 300.0 ;
25
+ static constexpr double ZERO_FREQ = 2400.0 ;
26
+ static constexpr double ZERO_FREQ_VARIANCE = 600.0 ;
30
27
31
- static constexpr uint16_t ONE_FREQ = 1200 ;
32
- static constexpr uint16_t ZERO_FREQ = 2400 ;
33
- static constexpr uint16_t ONE_CYCLES = H8_WAV_FREQUENCY / ONE_FREQ;
34
- static constexpr uint16_t ZERO_CYCLES = H8_WAV_FREQUENCY / ZERO_FREQ;
35
-
36
- // image size
37
- static int h8_image_size; // FIXME: global variable prevents multiple instances
38
-
39
- static int h8_put_samples (int16_t *buffer, int sample_pos, int count, int level)
28
+ static const cassette_image::Modulation heath_h8t_modulation =
40
29
{
41
- if (buffer)
42
- {
43
- std::fill_n (&buffer[sample_pos], count, level);
44
- }
45
-
46
- return count;
47
- }
30
+ cassette_image::MODULATION_SINEWAVE,
31
+ ONE_FREQ - ONE_FREQ_VARIANCE, ONE_FREQ, ONE_FREQ + ONE_FREQ_VARIANCE,
32
+ ZERO_FREQ - ZERO_FREQ_VARIANCE, ZERO_FREQ, ZERO_FREQ + ZERO_FREQ_VARIANCE
33
+ };
48
34
49
- static int h8_output_bit ( int16_t *buffer, int sample_pos, bool bit )
35
+ static cassette_image::error heath_h8t_identify (cassette_image *cassette, cassette_image::Options *opts )
50
36
{
51
- int samples = 0 ;
52
-
53
- const int loops = bit ? ONE_CYCLES : ZERO_CYCLES;
54
- const int samplePerValue = SAMPLES_PER_HALF_WAVE / loops;
55
-
56
- for (int i = 0 ; i < loops; i++)
57
- {
58
- samples += h8_put_samples (buffer, sample_pos + samples, samplePerValue, WAVEENTRY_LOW);
59
- samples += h8_put_samples (buffer, sample_pos + samples, samplePerValue, WAVEENTRY_HIGH);
60
- }
61
-
62
- return samples;
37
+ return cassette->modulation_identify (heath_h8t_modulation, opts);
63
38
}
64
39
65
- static int h8_output_byte (int16_t *buffer, int sample_pos, uint8_t data)
66
- {
67
- int samples = 0 ;
68
-
69
- // start bit
70
- samples += h8_output_bit (buffer, sample_pos + samples, 0 );
71
40
72
- // data bits
73
- for (int i = 0 ; i < 8 ; i++)
74
- {
75
- samples += h8_output_bit (buffer, sample_pos + samples, data & 1 );
76
- data >>= 1 ;
41
+ # define MODULATE ( _value ) \
42
+ for (int i = 0 ; i < (_value ? 8 : 4 ) ; i++) { \
43
+ err = cassette-> put_modulated_data_bit ( 0 , time_index, _value, heath_h8t_modulation, &time_displacement); \
44
+ if (err != cassette_image::error::SUCCESS) return err; \
45
+ time_index += time_displacement; \
77
46
}
78
47
79
- // stop bit
80
- samples += h8_output_bit (buffer, sample_pos + samples, 1 );
81
-
82
- return samples;
83
- }
84
-
85
- static int h8_handle_cassette (int16_t *buffer, const uint8_t *bytes)
48
+ static cassette_image::error heath_h8t_load (cassette_image *cassette)
86
49
{
87
- int sample_count = 0 ;
50
+ cassette_image::error err = cassette_image::error::SUCCESS;
51
+ uint64_t image_size = cassette->image_size ();
52
+ double time_index = 0.0 ;
53
+ double time_displacement;
88
54
89
55
// leader - 1 second
90
- for (int i = 0 ; i < TAPE_BAUD_RATE; i++)
91
- sample_count += h8_output_bit (buffer, sample_count, 1 );
92
-
93
- // data
94
- for (int i = 0 ; i < h8_image_size; i++)
95
- sample_count += h8_output_byte (buffer, sample_count, bytes[i]);
96
-
97
- return sample_count;
98
- }
99
-
100
-
101
- /* ******************************************************************
102
- Generate samples for the tape image
103
- ********************************************************************/
104
-
105
- static int h8_cassette_fill_wave (int16_t *buffer, int length, const uint8_t *bytes)
106
- {
107
- return h8_handle_cassette (buffer, bytes);
108
- }
109
-
110
- /* ******************************************************************
111
- Calculate the number of samples needed for this tape image
112
- ********************************************************************/
56
+ while (time_index < 1.0 )
57
+ {
58
+ MODULATE (1 );
59
+ }
113
60
114
- static int h8_cassette_calculate_size_in_samples ( const uint8_t *bytes, int length )
115
- {
116
- h8_image_size = length ;
61
+ for ( uint64_t image_pos = 0 ; image_pos < image_size; image_pos++ )
62
+ {
63
+ uint8_t data = cassette-> image_read_byte (image_pos) ;
117
64
118
- return h8_handle_cassette ( nullptr , bytes);
119
- }
65
+ // start bit
66
+ MODULATE ( 0 );
120
67
121
- static const cassette_image::LegacyWaveFiller h8_legacy_fill_wave =
122
- {
123
- h8_cassette_fill_wave, // fill_wave
124
- -1 , // chunk_size
125
- 0 , // chunk_samples
126
- h8_cassette_calculate_size_in_samples, // chunk_sample_calc
127
- H8_WAV_FREQUENCY, // sample_frequency
128
- 0 , // header_samples
129
- 0 // trailer_samples
130
- };
68
+ // data bits
69
+ for (int bit = 0 ; bit < 8 ; bit++)
70
+ {
71
+ MODULATE (util::BIT (data, bit));
72
+ }
131
73
132
- static cassette_image::error h8_cassette_identify (cassette_image *cassette, cassette_image::Options *opts)
133
- {
134
- return cassette->legacy_identify (opts, &h8_legacy_fill_wave);
135
- }
74
+ // stop bit
75
+ MODULATE (1 );
76
+ }
136
77
137
- static cassette_image::error h8_cassette_load (cassette_image *cassette)
138
- {
139
- return cassette->legacy_construct (&h8_legacy_fill_wave);
78
+ return err;
140
79
}
141
80
142
- static const cassette_image::Format h8_cassette_image_format =
81
+ const cassette_image::Format heath_h8t_format =
143
82
{
144
83
" h8t" ,
145
- h8_cassette_identify ,
146
- h8_cassette_load ,
84
+ heath_h8t_identify ,
85
+ heath_h8t_load ,
147
86
nullptr
148
87
};
149
88
150
- CASSETTE_FORMATLIST_START (h8_cassette_formats)
151
- CASSETTE_FORMAT(h8_cassette_image_format)
89
+ }
90
+
91
+ CASSETTE_FORMATLIST_START ( h8_cassette_formats )
92
+ CASSETTE_FORMAT( heath_h8t_format )
152
93
CASSETTE_FORMATLIST_END
0 commit comments