mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Archival, non-working checkin of the flux to scp converter (it appears to
produce garbage).
This commit is contained in:
176
src/fe-fluxtoscp.cc
Normal file
176
src/fe-fluxtoscp.cc
Normal file
@@ -0,0 +1,176 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "fluxmap.h"
|
||||
#include "sql.h"
|
||||
#include "bytes.h"
|
||||
#include "protocol.h"
|
||||
#include "dataspec.h"
|
||||
#include "fmt/format.h"
|
||||
#include "decoders/fluxmapreader.h"
|
||||
#include "scp.h"
|
||||
#include <fstream>
|
||||
|
||||
static FlagGroup flags { };
|
||||
|
||||
static SettableFlag fortyTrackMode(
|
||||
{ "--48", "-4" },
|
||||
"set 48 tpi mode; only every other physical track is emitted"
|
||||
);
|
||||
|
||||
static SettableFlag singleSided(
|
||||
{ "--single-sided", "-s" },
|
||||
"only emit side 0"
|
||||
);
|
||||
|
||||
static IntFlag diskType(
|
||||
{ "--disk-type" },
|
||||
"sets the SCP disk type byte",
|
||||
0xff
|
||||
);
|
||||
|
||||
static sqlite3* inputDb;
|
||||
|
||||
static void syntax()
|
||||
{
|
||||
std::cout << "Syntax: fluxengine convert fluxtoscp <fluxfile> <scpfile>\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void write_le32(uint8_t dest[4], uint32_t v)
|
||||
{
|
||||
dest[0] = v;
|
||||
dest[1] = v >> 8;
|
||||
dest[2] = v >> 16;
|
||||
dest[3] = v >> 24;
|
||||
}
|
||||
|
||||
int mainConvertFluxToScp(int argc, const char* argv[])
|
||||
{
|
||||
auto filenames = flags.parseFlagsWithFilenames(argc, argv);
|
||||
if (filenames.size() != 2)
|
||||
syntax();
|
||||
|
||||
inputDb = sqlOpen(filenames[0], SQLITE_OPEN_READONLY);
|
||||
auto tracks = sqlFindFlux(inputDb);
|
||||
|
||||
int maxTrack = 0;
|
||||
for (auto p : tracks)
|
||||
{
|
||||
if (singleSided && (p.second == 1))
|
||||
continue;
|
||||
if (p.first > maxTrack)
|
||||
maxTrack = p.first;
|
||||
}
|
||||
|
||||
std::cout << fmt::format("Writing {} {} SCP file containing {} tracks\n",
|
||||
fortyTrackMode ? "48 tpi" : "96 tpi",
|
||||
singleSided ? "single sided" : "double sided",
|
||||
(fortyTrackMode ? (maxTrack / 2) : maxTrack) + 1
|
||||
);
|
||||
|
||||
ScpHeader fileheader = {0};
|
||||
fileheader.file_id[0] = 'S';
|
||||
fileheader.file_id[1] = 'C';
|
||||
fileheader.file_id[2] = 'P';
|
||||
fileheader.file_id[3] = 0x18; /* Version 1.8 of the spec */
|
||||
fileheader.type = diskType;
|
||||
fileheader.revolutions = 5;
|
||||
fileheader.start_track = 0;
|
||||
fileheader.end_track = maxTrack;
|
||||
fileheader.flags = SCP_FLAG_INDEXED | (fortyTrackMode ? 0 : SCP_FLAG_96TPI);
|
||||
fileheader.cell_width = 0;
|
||||
fileheader.heads = singleSided ? 1 : 0;
|
||||
|
||||
Bytes trackdata;
|
||||
ByteWriter trackdataWriter(trackdata);
|
||||
|
||||
int trackstep = 1 + fortyTrackMode;
|
||||
int maxside = singleSided ? 0 : 1;
|
||||
int strack = 0;
|
||||
for (int track = 0; track <= maxTrack; track += trackstep)
|
||||
{
|
||||
for (int side = 0; side <= maxside; side++)
|
||||
{
|
||||
std::cout << fmt::format("FE track {}.{}, SCP track {}: ", track, side, strack) << std::flush;
|
||||
|
||||
auto fluxmap = sqlReadFlux(inputDb, track, side);
|
||||
ScpTrack trackheader = {0};
|
||||
trackheader.track_id[0] = 'T';
|
||||
trackheader.track_id[1] = 'R';
|
||||
trackheader.track_id[2] = 'K';
|
||||
trackheader.strack = strack;
|
||||
|
||||
FluxmapReader fmr(*fluxmap);
|
||||
Bytes fluxdata;
|
||||
ByteWriter fluxdataWriter(fluxdata);
|
||||
|
||||
int revolution = 0;
|
||||
unsigned revTicks = 0;
|
||||
unsigned totalTicks = 0;
|
||||
unsigned ticksSinceLastPulse = 0;
|
||||
uint32_t startOffset = 0;
|
||||
while (revolution < 5)
|
||||
{
|
||||
unsigned ticks;
|
||||
int opcode = fmr.readOpcode(ticks);
|
||||
if (ticks)
|
||||
{
|
||||
ticksSinceLastPulse += ticks;
|
||||
totalTicks += ticks;
|
||||
revTicks += ticks;
|
||||
}
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case -1: /* end of flux, treat like an index marker */
|
||||
case F_OP_INDEX:
|
||||
{
|
||||
auto* revheader = &trackheader.revolution[revolution];
|
||||
write_le32(revheader->offset, startOffset + sizeof(ScpTrack));
|
||||
write_le32(revheader->length, fluxdataWriter.pos - startOffset);
|
||||
write_le32(revheader->index, revTicks * NS_PER_TICK / 25);
|
||||
revolution++;
|
||||
revheader++;
|
||||
revTicks = 0;
|
||||
startOffset = fluxdataWriter.pos;
|
||||
break;
|
||||
}
|
||||
|
||||
case F_OP_PULSE:
|
||||
{
|
||||
unsigned t = ticksSinceLastPulse * NS_PER_TICK / 25;
|
||||
while (t >= 0x10000)
|
||||
{
|
||||
fluxdataWriter.write_be16(0);
|
||||
t -= 0x10000;
|
||||
}
|
||||
fluxdataWriter.write_be16(t);
|
||||
ticksSinceLastPulse = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write_le32(fileheader.track[strack], trackdataWriter.pos + sizeof(ScpHeader));
|
||||
trackdataWriter += Bytes((uint8_t*)&trackheader, sizeof(trackheader));
|
||||
trackdataWriter += fluxdata;
|
||||
|
||||
std::cout << fmt::format("{} ms in {} bytes\n",
|
||||
totalTicks * MS_PER_TICK,
|
||||
fluxdata.size());
|
||||
strack++;
|
||||
}
|
||||
}
|
||||
|
||||
sqlClose(inputDb);
|
||||
|
||||
std::cout << "Writing output file...\n";
|
||||
std::ofstream of(filenames[1], std::ios::out | std::ios::binary);
|
||||
if (!of.is_open())
|
||||
Error() << "cannot open output file";
|
||||
of.write((const char*) &fileheader, sizeof(fileheader));
|
||||
of.write((const char*) trackdata.begin(), trackdata.size());
|
||||
of.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4,37 +4,9 @@
|
||||
#include "bytes.h"
|
||||
#include "protocol.h"
|
||||
#include "fmt/format.h"
|
||||
#include "scp.h"
|
||||
#include <fstream>
|
||||
|
||||
struct ScpHeader
|
||||
{
|
||||
char file_id[3]; // file ID - 'SCP'
|
||||
uint8_t version; // major/minor in nibbles
|
||||
uint8_t type; // disk type - subclass/class in nibbles
|
||||
uint8_t revolutions; // up to 5
|
||||
uint8_t start_track; // 0..165
|
||||
uint8_t end_track; // 0..165
|
||||
uint8_t flags; // see below
|
||||
uint8_t cell_width; // in bits, 0 meaning 16
|
||||
uint8_t heads; // 0 = both, 1 = side 0 only, 2 = side 1 only
|
||||
uint8_t resolution; // 25ns * (resolution+1)
|
||||
uint8_t checksum[4]; // of data after this point
|
||||
uint8_t track[165][4]; // track offsets, not necessarily 165
|
||||
};
|
||||
|
||||
struct ScpTrack
|
||||
{
|
||||
char track_id[3]; // 'TRK'
|
||||
uint8_t strack; // SCP track number
|
||||
struct
|
||||
{
|
||||
uint8_t index[4]; // time for one revolution
|
||||
uint8_t length[4]; // number of bitcells
|
||||
uint8_t offset[4]; // offset to bitcell data, relative to track header
|
||||
}
|
||||
revolution[5];
|
||||
};
|
||||
|
||||
static std::ifstream inputFile;
|
||||
static sqlite3* outputDb;
|
||||
static ScpHeader header;
|
||||
@@ -133,7 +105,7 @@ static void read_track(int strack)
|
||||
pending = 0;
|
||||
}
|
||||
else
|
||||
pending += interval;
|
||||
pending += 0x10000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ typedef int command_cb(int agrc, const char* argv[]);
|
||||
extern command_cb mainErase;
|
||||
extern command_cb mainConvertCwfToFlux;
|
||||
extern command_cb mainConvertFluxToAu;
|
||||
extern command_cb mainConvertFluxToScp;
|
||||
extern command_cb mainConvertFluxToVcd;
|
||||
extern command_cb mainConvertScpToFlux;
|
||||
extern command_cb mainInspect;
|
||||
@@ -86,6 +87,7 @@ static std::vector<Command> convertables =
|
||||
{ "cwftoflux", mainConvertCwfToFlux, "Converts CatWeasel stream files to flux.", },
|
||||
{ "scptoflux", mainConvertScpToFlux, "Converts Supercard Pro stream files to flux.", },
|
||||
{ "fluxtoau", mainConvertFluxToAu, "Converts (one track of a) flux file to an .au audio file.", },
|
||||
{ "fluxtoscp", mainConvertFluxToScp, "Converrt a flux file to a Supercard Pro file.", },
|
||||
{ "fluxtovcd", mainConvertFluxToVcd, "Converts (one track of a) flux file to a VCD file.", },
|
||||
};
|
||||
|
||||
|
||||
43
src/scp.h
Normal file
43
src/scp.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef SCP_H
|
||||
#define SCP_H
|
||||
|
||||
struct ScpHeader
|
||||
{
|
||||
char file_id[3]; // file ID - 'SCP'
|
||||
uint8_t version; // major/minor in nibbles
|
||||
uint8_t type; // disk type - subclass/class in nibbles
|
||||
uint8_t revolutions; // up to 5
|
||||
uint8_t start_track; // 0..165
|
||||
uint8_t end_track; // 0..165
|
||||
uint8_t flags; // see below
|
||||
uint8_t cell_width; // in bits, 0 meaning 16
|
||||
uint8_t heads; // 0 = both, 1 = side 0 only, 2 = side 1 only
|
||||
uint8_t resolution; // 25ns * (resolution+1)
|
||||
uint8_t checksum[4]; // of data after this point
|
||||
uint8_t track[165][4]; // track offsets, not necessarily 165
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCP_FLAG_INDEXED = (1<<0),
|
||||
SCP_FLAG_96TPI = (1<<1),
|
||||
SCP_FLAG_360RPM = (1<<2),
|
||||
SCP_FLAG_NORMALIZED = (1<<3),
|
||||
SCP_FLAG_READWRITE = (1<<4),
|
||||
SCP_FLAG_FOOTER = (1<<5)
|
||||
};
|
||||
|
||||
struct ScpTrack
|
||||
{
|
||||
char track_id[3]; // 'TRK'
|
||||
uint8_t strack; // SCP track number
|
||||
struct
|
||||
{
|
||||
uint8_t index[4]; // time for one revolution
|
||||
uint8_t length[4]; // number of bitcells
|
||||
uint8_t offset[4]; // offset to bitcell data, relative to track header
|
||||
}
|
||||
revolution[5];
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user