OXYGENHUB
◆ main openmsx / src / cassette / TsxParser.hh
5.0 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
// Based on code written by:
2
//   (2017) NataliaPC aka @ishwin74
3
//   Under GPL License
4
5
#ifndef TSXPARSER_HH
6
#define TSXPARSER_HH
7
8
#include "endian.hh"
9
10
#include <array>
11
#include <cstdint>
12
#include <optional>
13
#include <span>
14
#include <string>
15
#include <vector>
16
17
class TsxParser {
18
public:
19
	// output settings
20
	static constexpr unsigned TZX_Z80_FREQ       = 3500000; // 3.5MHz (according to TZX spec: not 3.579545MHz)
21
	static constexpr unsigned OUTPUT_FREQUENCY   = 58900;   // ~ = Z80_FREQ * 4 / T_STATES_MSX_PULSE
22
	static constexpr float    T_STATES_MSX_PULSE = 238.f;
23
24
	enum class FileType : uint8_t {
25
		ASCII, BINARY, BASIC, UNKNOWN,
26
	};
27
28
public:
29
	explicit TsxParser(std::span<const uint8_t> file);
30
31
	[[nodiscard]] std::vector<int8_t>&& stealOutput() { return std::move(output); }
32
	[[nodiscard]] std::optional<FileType> getFirstFileType() const { return firstFileType; }
33
	[[nodiscard]] const std::vector<std::string>& getMessages() const { return messages; }
34
35
private:
36
	struct Block10 {
37
		Endian::UA_L16  pauseMs;     // Pause after this block in milliseconds
38
		Endian::UA_L16  len;         // Length of data that follow
39
		//uint8_t       data[];      // Data as in .TAP files
40
	};
41
	struct Block11 {
42
		Endian::UA_L16  pilot;       // Length of PILOT pulse {2168}
43
		Endian::UA_L16  sync1;       // Length of SYNC first pulse {667}
44
		Endian::UA_L16  sync2;       // Length of SYNC second pulse {735}
45
		Endian::UA_L16  zero;        // Length of ZERO bit pulse {855}
46
		Endian::UA_L16  one;         // Length of ONE bit pulse {1710}
47
		Endian::UA_L16  pilotLen;    // Length of PILOT tone (number of pulses) {8063 header (flag<128), 3223 data (flag>=128)}
48
		uint8_t         lastBits;    // Used bits in the last byte (other bits should be 0) {8}
49
		Endian::UA_L16  pauseMs;     // Pause after this block (ms.) {1000}
50
		Endian::UA_L24  len;         // Length of data that follow
51
		//uint8_t       data[];      // Data as in .TAP files
52
	};
53
	struct Block12 {
54
		Endian::UA_L16  len;         // Length of one pulse in T-states
55
		Endian::UA_L16  pulses;      // Number of pulses
56
	};
57
	struct Block13 {
58
		uint8_t         num;         // Number of pulses
59
		//Endian::UA_L16 pulses[];   // [Array] Pulses' lengths
60
	};
61
	struct Block15 {
62
		Endian::UA_L16  bitTstates;  // Number of T-states per sample (bit of data)
63
		Endian::UA_L16  pauseMs;     // Pause after this block (ms.) {1000}
64
		uint8_t         lastBits;    // Used bits (samples) in last byte of data (1-8)
65
		Endian::UA_L24  len;         // Length of samples data
66
		//uint8_t       samples[];   // [Array] Samples data. Each bit represents a state on the EAR port (i.e. one sample). MSb is played first.
67
	};
68
	struct Block20 {
69
		Endian::UA_L16  pauseMs;     // Silence pause in milliseconds
70
	};
71
	struct Block21 {
72
		uint8_t         len;         // Length of the group name string
73
		//char          name[];      // The group name (ASCII)
74
	};
75
	struct Block30 {
76
		uint8_t         len;         // Length of the text description
77
		//char          text[];      // [Array] Text description in ASCII format
78
	};
79
	struct Block32 {
80
		Endian::UA_L16  blockLen;    // Length of the whole block (without these two bytes)
81
		uint8_t         num;         // Number of text strings
82
		//uint8_t       list[];      // [Array] List of text strings
83
	};
84
	struct Block35 {
85
		std::array<char, 0x10> label;// Identification string (in ASCII)
86
		Endian::UA_L32  len;         // Length of the custom info
87
		//uint8_t       data[];      // [Array] Custom info
88
	};
89
	struct Block4B {
90
		Endian::UA_L32  blockLen;    // Block length without these four bytes
91
		Endian::UA_L16  pauseMs;     // Pause after this block in milliseconds
92
		Endian::UA_L16  pilot;       // Duration of a PILOT pulse in T-states {same as ONE pulse}
93
		Endian::UA_L16  pulses;      // Number of pulses in the PILOT tone
94
		Endian::UA_L16  bit0len;     // Duration of a ZERO pulse in T-states {=2*pilot}
95
		Endian::UA_L16  bit1len;     // Duration of a ONE pulse in T-states {=pilot}
96
		uint8_t         bitCfg;
97
		uint8_t         byteCfg;
98
		//uint8_t       data[];      // [Array]
99
	};
100
101
	void processBlock10(const Block10& b);
102
	void processBlock11(const Block11& b);
103
	void processBlock12(const Block12& b);
104
	void processBlock13(const Block13& b);
105
	void processBlock15(const Block15& b);
106
	void processBlock20(const Block20& b);
107
	void processBlock21(const Block21& b);
108
	void processBlock30(const Block30& b);
109
	void processBlock32(const Block32& b);
110
	void processBlock35(const Block35& b);
111
	void processBlock4B(const Block4B& b);
112
113
	void writeSample(uint32_t tStates, int8_t value);
114
	void writePulse(uint32_t tStates);
115
	void writePulses(uint32_t count, uint32_t tStates);
116
	void writeSilence(int s);
117
118
	template<typename T> std::span<const T> get(size_t count);
119
	template<typename T> const T& get();
120
121
	[[noreturn]] void error(std::string msg) const;
122
123
private:
124
	// The parsed result is stored here
125
	std::vector<int8_t> output;
126
	std::vector<std::string> messages;
127
	std::optional<FileType> firstFileType;
128
129
	// The (remaining) part of the input file
130
	std::span<const uint8_t> buf;
131
132
	// Intermediate state while writing the waveform
133
	float  accumBytes = 0.f;
134
	int8_t currentValue = 127;
135
};
136
137
#endif