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 ::append(wave, {127, 127, -127, -127});
76static void write1(std::vector<int8_t>& wave)
78 ::append(wave, {127, -127, 127, -127});
81static void writeHeader(std::vector<int8_t>& wave,
unsigned s)
83 repeat(s, [&] { write1(wave); });
86static void writeByte(std::vector<int8_t>& wave, uint8_t b)
104static bool writeData(std::vector<int8_t>& wave, std::span<const uint8_t> cas,
size_t& pos)
107 while ((pos + CAS_HEADER.size()) <= cas.size()) {
108 if (compare(&cas[pos], CAS_HEADER)) {
111 writeByte(wave, cas[pos]);
112 if (cas[pos] == 0x1A) {
117 while (pos < cas.size()) {
118 writeByte(wave, cas[pos++]);
123static CasImage::Data convert(std::span<const uint8_t> cas,
const std::string& filename,
CliComm& cliComm,
128 auto& wave = data.
wave;
131 bool issueWarning =
false;
132 bool headerFound =
false;
133 bool firstFile =
true;
135 while ((pos + CAS_HEADER.size()) <= cas.size()) {
136 if (compare(&cas[pos], CAS_HEADER)) {
141 pos += CAS_HEADER.size();
142 writeSilence(wave, LONG_SILENCE);
143 writeHeader(wave, LONG_HEADER);
144 if ((pos + ASCII_HEADER.size()) <= cas.size()) {
147 if (compare(&cas[pos], ASCII_HEADER)) {
149 }
else if (compare(&cas[pos], BINARY_HEADER)) {
151 }
else if (compare(&cas[pos], BASIC_HEADER)) {
157 if (firstFile) firstFileType = type;
160 writeData(wave, cas, pos);
162 pos += CAS_HEADER.size();
163 writeSilence(wave, SHORT_SILENCE);
164 writeHeader(wave, SHORT_HEADER);
165 bool eof = writeData(wave, cas, pos);
167 }
while ((pos + CAS_HEADER.size()) <= cas.size());
171 writeData(wave, cas, pos);
172 writeSilence(wave, SHORT_SILENCE);
173 writeHeader(wave, SHORT_HEADER);
174 pos += CAS_HEADER.size();
175 writeData(wave, cas, pos);
179 writeData(wave, cas, pos);
184 writeData(wave, cas, pos);
194 throw MSXException(filename,
": not a valid CAS image");
197 cliComm.
printWarning(
"Skipped unhandled data in ", filename);
207static constexpr std::array<uint8_t, 17> header = {
208 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
209 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
213static void writeBit(std::vector<int8_t>& wave,
bool bit)
215 size_t count = bit ? 1 : 2;
216 append(wave,
count, 127);
217 append(wave,
count, -127);
220static void writeByte(std::vector<int8_t>& wave, uint8_t
byte)
222 for (
int i = 7; i >= 0; --i) {
223 writeBit(wave, (
byte >> i) & 1);
227static void processBlock(std::span<const uint8_t> subBuf, std::vector<int8_t>& wave)
229 writeSilence(wave, 1200);
230 writeBit(wave,
true);
231 repeat(199, [&] { writeByte(wave, 0x55); });
232 writeByte(wave, 0x7f);
233 for (uint8_t val : subBuf) {
234 writeBit(wave,
false);
235 writeByte(wave, val);
244 if (cas.size() >= (header.size() + ASCII_HEADER.size())) {
245 if (compare(&cas[header.size()], ASCII_HEADER)) {
247 }
else if (compare(&cas[header.size()], BINARY_HEADER)) {
249 }
else if (compare(&cas[header.size()], BASIC_HEADER)) {
254 auto prevHeader = cas.begin() + header.size();
256 auto nextHeader = std::search(prevHeader, cas.end(),
257 header.begin(), header.end());
260 processBlock(std::span(&*prevHeader, nextHeader - prevHeader), data.
wave);
261 if (nextHeader == cas.end())
break;
262 prevHeader = nextHeader + header.size();
272 auto cas = file.mmap();
276 if ((cas.size() >= SVI_CAS::header.size()) &&
277 (compare(cas.data(), SVI_CAS::header))) {
278 return SVI_CAS::convert(cas, fileType);
280 return MSX_CAS::convert(cas, filename.
getOriginal(), cliComm, fileType);
292 : data(init(filename, filePool, cliComm))
300 return narrow<int16_t>((pos < data.
wave.size()) ? (data.
wave[pos] * 256) : 0);
306 return EmuTime::zero() + d;
311 return data.
frequency * AUDIO_OVERSAMPLE;
316 size_t nbSamples = data.
wave.size();
317 if ((pos / AUDIO_OVERSAMPLE) < nbSamples) {
318 for (
auto i :
xrange(num)) {
319 bufs[0][i] = ((pos / AUDIO_OVERSAMPLE) < nbSamples)
320 ? narrow_cast<float>(data.
wave[pos / AUDIO_OVERSAMPLE])
331 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
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
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)