13static constexpr std::array<uint8_t, 10> ASCII_HEADER = { 0xEA,0xEA,0xEA,0xEA,0xEA,0xEA,0xEA,0xEA,0xEA,0xEA };
14static constexpr std::array<uint8_t, 10> BINARY_HEADER = { 0xD0,0xD0,0xD0,0xD0,0xD0,0xD0,0xD0,0xD0,0xD0,0xD0 };
15static constexpr std::array<uint8_t, 10> BASIC_HEADER = { 0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3 };
17static_assert(ASCII_HEADER.size() == BINARY_HEADER.size());
18static_assert(ASCII_HEADER.size() == BASIC_HEADER.size());
32static constexpr unsigned AUDIO_OVERSAMPLE = 4;
34static void append(std::vector<int8_t>& wave,
size_t count, int8_t value)
36 wave.insert(wave.end(), count, value);
39static void writeSilence(std::vector<int8_t>& wave,
unsigned s)
44static bool compare(
const uint8_t* p, std::span<const uint8_t> rhs)
58static constexpr unsigned BAUDRATE = 3744;
59static constexpr unsigned OUTPUT_FREQUENCY = 4 * BAUDRATE;
62static constexpr unsigned SHORT_SILENCE = OUTPUT_FREQUENCY * 1;
63static constexpr unsigned LONG_SILENCE = OUTPUT_FREQUENCY * 2;
66static constexpr unsigned LONG_HEADER = 16000 / 2;
67static constexpr unsigned SHORT_HEADER = 4000 / 2;
70static constexpr std::array<uint8_t, 8> CAS_HEADER = { 0x1F,0xA6,0xDE,0xBA,0xCC,0x13,0x7D,0x74 };
72static void write0(std::vector<int8_t>& wave)
74 static constexpr std::array<int8_t, 4> chunk{127, 127, -127, -127};
75 ::append(wave, chunk);
77static void write1(std::vector<int8_t>& wave)
79 static constexpr std::array<int8_t, 4> chunk{127, -127, 127, -127};
80 ::append(wave, chunk);
83static void writeHeader(std::vector<int8_t>& wave,
unsigned s)
85 repeat(s, [&] { write1(wave); });
88static void writeByte(std::vector<int8_t>& wave, uint8_t b)
106static bool writeData(std::vector<int8_t>& wave, std::span<const uint8_t> cas,
size_t& pos)
109 while ((pos + CAS_HEADER.size()) <= cas.size()) {
110 if (compare(&cas[pos], CAS_HEADER)) {
113 writeByte(wave, cas[pos]);
114 if (cas[pos] == 0x1A) {
119 while (pos < cas.size()) {
120 writeByte(wave, cas[pos++]);
125static CasImage::Data convert(std::span<const uint8_t> cas,
const std::string& filename,
CliComm& cliComm,
130 auto& wave = data.
wave;
133 bool issueWarning =
false;
134 bool headerFound =
false;
135 bool firstFile =
true;
137 while ((pos + CAS_HEADER.size()) <= cas.size()) {
138 if (compare(&cas[pos], CAS_HEADER)) {
143 pos += CAS_HEADER.size();
144 writeSilence(wave, LONG_SILENCE);
145 writeHeader(wave, LONG_HEADER);
146 if ((pos + ASCII_HEADER.size()) <= cas.size()) {
149 if (compare(&cas[pos], ASCII_HEADER)) {
151 }
else if (compare(&cas[pos], BINARY_HEADER)) {
153 }
else if (compare(&cas[pos], BASIC_HEADER)) {
159 if (firstFile) firstFileType = type;
162 writeData(wave, cas, pos);
164 pos += CAS_HEADER.size();
165 writeSilence(wave, SHORT_SILENCE);
166 writeHeader(wave, SHORT_HEADER);
167 bool eof = writeData(wave, cas, pos);
169 }
while ((pos + CAS_HEADER.size()) <= cas.size());
173 writeData(wave, cas, pos);
174 writeSilence(wave, SHORT_SILENCE);
175 writeHeader(wave, SHORT_HEADER);
176 pos += CAS_HEADER.size();
177 writeData(wave, cas, pos);
181 writeData(wave, cas, pos);
186 writeData(wave, cas, pos);
196 throw MSXException(filename,
": not a valid CAS image");
199 cliComm.
printWarning(
"Skipped unhandled data in ", filename);
209static constexpr std::array<uint8_t, 17> header = {
210 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
211 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
215static void writeBit(std::vector<int8_t>& wave,
bool bit)
217 size_t count = bit ? 1 : 2;
218 append(wave, count, 127);
219 append(wave, count, -127);
222static void writeByte(std::vector<int8_t>& wave, uint8_t
byte)
224 for (
int i = 7; i >= 0; --i) {
225 writeBit(wave, (
byte >> i) & 1);
229static void processBlock(std::span<const uint8_t> subBuf, std::vector<int8_t>& wave)
231 writeSilence(wave, 1200);
232 writeBit(wave,
true);
233 repeat(199, [&] { writeByte(wave, 0x55); });
234 writeByte(wave, 0x7f);
235 for (uint8_t val : subBuf) {
236 writeBit(wave,
false);
237 writeByte(wave, val);
246 if (cas.size() >= (header.size() + ASCII_HEADER.size())) {
247 if (compare(&cas[header.size()], ASCII_HEADER)) {
249 }
else if (compare(&cas[header.size()], BINARY_HEADER)) {
251 }
else if (compare(&cas[header.size()], BASIC_HEADER)) {
256 auto prevHeader = cas.begin() + header.size();
258 auto nextHeader = std::search(prevHeader, cas.end(),
259 header.begin(), header.end());
262 processBlock(std::span(&*prevHeader, nextHeader - prevHeader), data.
wave);
263 if (nextHeader == cas.end())
break;
264 prevHeader = nextHeader + header.size();
274 auto cas = file.mmap();
278 if ((cas.size() >= SVI_CAS::header.size()) &&
279 (compare(cas.data(), SVI_CAS::header))) {
280 return SVI_CAS::convert(cas, fileType);
282 return MSX_CAS::convert(cas, filename.
getOriginal(), cliComm, fileType);
294 : data(init(filename, filePool, cliComm))
302 return narrow<int16_t>((pos < data.
wave.size()) ? (data.
wave[pos] * 256) : 0);
308 return EmuTime::zero() + d;
313 return data.
frequency * AUDIO_OVERSAMPLE;
318 size_t nbSamples = data.
wave.size();
319 if ((pos / AUDIO_OVERSAMPLE) < nbSamples) {
320 for (
auto i :
xrange(num)) {
321 bufs[0][i] = ((pos / AUDIO_OVERSAMPLE) < nbSamples)
322 ? narrow_cast<float>(data.
wave[pos / AUDIO_OVERSAMPLE])
333 return 1.0f / 128.0f;
int16_t getSampleAt(EmuTime::param time) const override
unsigned getFrequency() const override
CasImage(const Filename &fileName, FilePool &filePool, CliComm &cliComm)
void fillBuffer(unsigned pos, std::span< float *, 1 > bufs, unsigned num) const override
EmuTime getEndTime() const override
float getAmplificationFactorImpl() const override
void setSha1Sum(const Sha1Sum &sha1sum)
void setFirstFileType(FileType type)
void printWarning(std::string_view message)
static constexpr EmuDuration hz(unsigned x)
constexpr unsigned getTicksAt(unsigned freq) const
Sha1Sum getSha1Sum(File &file)
Calculate sha1sum for the given File object.
This class represents a filename.
const std::string & getOriginal() const
This file implemented 3 utility functions:
bool equal(InputRange1 &&range1, InputRange2 &&range2, Pred pred={}, Proj1 proj1={}, Proj2 proj2={})
std::vector< int8_t > wave
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
constexpr auto xrange(T e)