diff --git a/.appveyor.yml b/.appveyor.yml index e5cbfa0f..aefd7714 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -15,7 +15,7 @@ install: build_script: - make - - zip -9 fluxengine.zip fluxengine.exe brother120tool.exe cwftoflux.exe fluxtovcd.exe + - zip -9 fluxengine.zip fluxengine.exe brother120tool.exe cwftoflux.exe fluxtovcd.exe fluxtoau.exe artifacts: - path: fluxengine.zip diff --git a/lib/fluxmap.h b/lib/fluxmap.h index a7a3f54a..14d467ed 100644 --- a/lib/fluxmap.h +++ b/lib/fluxmap.h @@ -21,6 +21,7 @@ public: public: nanoseconds_t duration() const { return _duration; } + unsigned ticks() const { return _ticks; } size_t bytes() const { return _bytes.size(); } const Bytes& rawBytes() const { return _bytes; } diff --git a/mkninja.sh b/mkninja.sh index 6081693d..0e1ed2d1 100644 --- a/mkninja.sh +++ b/mkninja.sh @@ -211,6 +211,14 @@ buildprogram fluxtovcd \ libbackend.a \ libfmt.a \ +buildlibrary libfluxtoau.a \ + tools/fluxtoau.cc \ + +buildprogram fluxtoau \ + libfluxtoau.a \ + libbackend.a \ + libfmt.a \ + runtest dataspec-test tests/dataspec.cc runtest flags-test tests/flags.cc runtest fmmfm-test tests/fmmfm.cc diff --git a/tools/fluxtoau.cc b/tools/fluxtoau.cc new file mode 100644 index 00000000..4e31b512 --- /dev/null +++ b/tools/fluxtoau.cc @@ -0,0 +1,98 @@ +#include "globals.h" +#include "flags.h" +#include "fluxmap.h" +#include "sql.h" +#include "bytes.h" +#include "protocol.h" +#include "dataspec.h" +#include "fluxsource/fluxsource.h" +#include "decoders/fluxmapreader.h" +#include "fmt/format.h" +#include + +FlagGroup flags { &hardwareFluxSourceFlags }; + +static DataSpecFlag source( + { "--source", "-s" }, + "source for data", + ":d=0:t=0:s=0"); + +static StringFlag output( + { "--output", "-o" }, + "output AU file to write", + "output.au"); + +static SettableFlag highDensityFlag( + { "--high-density", "--hd" }, + "set the drive to high density mode"); + +static SettableFlag withIndex( + { "--with-index" }, + "place index markers in the right hand channel"); + +int main(int argc, const char* argv[]) +{ + flags.parseFlags(argc, argv); + + const auto& locations = source.get().locations; + if (locations.size() != 1) + Error() << "the source dataspec must contain exactly one track (two sides count as two tracks)"; + const auto& location = *(locations.begin()); + + std::cerr << "Reading source flux...\n"; + setHardwareFluxSourceDensity(highDensityFlag); + std::shared_ptr fluxsource = FluxSource::create(source); + const auto& fluxmap = fluxsource->readFlux(location.track, location.side); + unsigned totalTicks = fluxmap->ticks() + 2; + unsigned channels = withIndex ? 2 : 1; + + std::cerr << "Writing output file...\n"; + std::ofstream of(output, std::ios::out | std::ios::binary); + if (!of.is_open()) + Error() << "cannot open output file"; + + /* Write header */ + + { + Bytes header; + header.resize(24); + ByteWriter bw(header); + + bw.write_be32(0x2e736e64); + bw.write_be32(24); + bw.write_be32(totalTicks * channels); + bw.write_be32(2); /* 8-bit PCM */ + bw.write_be32(TICK_FREQUENCY); + bw.write_be32(channels); /* channels */ + + of.write((const char*) header.cbegin(), header.size()); + } + + /* Write data */ + + { + Bytes data; + data.resize(totalTicks * channels); + memset(data.begin(), 0x80, data.size()); + + FluxmapReader fmr(*fluxmap); + unsigned timestamp = 0; + while (!fmr.eof()) + { + unsigned ticks; + int op = fmr.readOpcode(ticks); + if (op == -1) + break; + timestamp += ticks; + + if (op == F_OP_PULSE) + data[timestamp*channels + 0] = 0x7f; + if (withIndex && (op == F_OP_INDEX)) + data[timestamp*channels + 1] = 0x7f; + } + + of.write((const char*) data.cbegin(), data.size()); + } + + return 0; +}