BlackchirpCSV
BlackchirpCSV is the workhorse persistence class for experiment CSV I/O.
It owns the canonical experiment-directory layout and provides the static
write helpers, directory helpers, and format utilities that every storage
class in the persistence subsystem calls directly. The companion
DataStorageBase class holds a BlackchirpCSV instance and delegates
all file access through it.
All CSV files produced by Blackchirp use the semicolon delimiter
(BC::CSV::del); the pipe character (BC::CSV::altDel) is reserved for
QStringList values embedded within a single cell. The full set of
canonical filenames for an experiment directory is enumerated in the
BC::CSV namespace: experiment-root files (versionFile,
validationFile, objectivesFile, hwFile, headerFile,
chirpFile, markersFile, clockFile, auxFile), FID artifacts
(fidparams, fidDir), and LIF artifacts (lifparams, lifDir).
Version-key constants (majver, minver, patchver, relver,
buildver) are written to and read from version.csv. The six
header-column name constants (ok, ak, ai, vk, vv,
vu) define the layout of header.csv.
The class has two construction paths. The default constructor creates an
instance suitable for static-method use and for writing new experiments; the
delimiter defaults to BC::CSV::del. The (num, path) constructor reads
version.csv from the experiment directory identified by num and
path, populating an internal configuration map that the instance-level
readLine and readFidLine methods then use to tokenize subsequent reads
with the correct delimiter. The version accessors (majorVersion,
minorVersion, patchVersion, releaseVersion, buildVersion)
expose the version metadata loaded by this constructor.
API Reference
-
class BlackchirpCSV
Workhorse persistence class for experiment CSV I/O.
BlackchirpCSVowns two complementary roles. In its static form it provides the write helpers, directory helpers, and format utilities that every storage class calls directly — none of those functions require an instance. In its instance form it holds a snapshot of the version metadata read from a saved experiment’sversion.csv, which the loader passes to DataStorageBase subclasses viareadLineandreadFidLine.The on-disk layout that these helpers enforce is described by the canonical filename constants in the
BC::CSVnamespace: experiment-root files (headerFile,chirpFile,clockFile, etc.), FID artifacts in thefidDirsubdirectory, and LIF artifacts in thelifDirsubdirectory. All CSV files use the semicolon delimiter (BC::CSV::del); the alternative pipe delimiter (BC::CSV::altDel) is reserved for QStringList fields embedded within a cell.See
DataStorageBaseand its subclasses for the classes that build on this foundation.Public Types
-
enum class XYFormat
Output format for writeXY().
Semicolon,Comma, andTabwrite a plain two-column file with the corresponding delimiter.Alignedwrites right-justified, whitespace-padded columns for human readability (and is read back with a\s+separator).Values:
-
enumerator Semicolon
-
enumerator Comma
-
enumerator Tab
-
enumerator Aligned
-
enumerator Semicolon
Public Functions
-
BlackchirpCSV()
Constructs a default instance with no version metadata loaded.
-
BlackchirpCSV(const int num, const QString path)
Constructs an instance by reading version metadata from a saved experiment.
Opens
version.csvin the experiment directory and populates the internal configuration map. The delimiter is detected from the first line of that file so that experiments saved with older delimiter conventions are read correctly.- Parameters:
num – Experiment number. Combined with path to locate the experiment directory.
path – Base data path override. When empty, the path stored in
SettingsStorageis used.
-
QVariantList readLine(QIODevice &device)
Reads and tokenizes the next line from device using the loaded delimiter.
The delimiter is the one detected when this instance was constructed from a saved experiment. On the default-constructed instance it is
BC::CSV::del.- Parameters:
device – Open, readable device positioned at the start of a line.
- Returns:
List of field values, one
QVariantper column; empty if the line is blank.
-
QVector<qint64> readFidLine(QIODevice &device)
Reads and decodes a FID data line from device.
- Parameters:
device – Open, readable device positioned at the start of a FID data line.
- Returns:
Vector of raw 64-bit sample values decoded from base-36 encoding.
-
int majorVersion() const
Returns the major version number from the loaded version metadata.
- Returns:
Major version, or
-1if no metadata was loaded.
-
int minorVersion() const
Returns the minor version number from the loaded version metadata.
- Returns:
Minor version, or
-1if no metadata was loaded.
-
int patchVersion() const
Returns the patch version number from the loaded version metadata.
- Returns:
Patch version, or
-1if no metadata was loaded.
-
QString releaseVersion() const
Returns the release label from the loaded version metadata.
- Returns:
Release label string (e.g.,
"alpha"), or an empty string if not present.
-
QString buildVersion() const
Returns the build identifier from the loaded version metadata.
- Returns:
Build identifier string, or an empty string if not present.
Public Static Functions
-
static bool writeXY(QIODevice &device, const QVector<QPointF> d, const QString prefix = "", XYFormat fmt = XYFormat::Semicolon)
Writes a single XY data set to device as a two-column file.
- Parameters:
device – Output device, which must not already be open.
d – Vector of points to write.
prefix – Optional column-name prefix; when non-empty, column headers become
prefix_xandprefix_yinstead ofxandy.fmt – Column delimiter / layout (see
XYFormat).
- Returns:
trueon success.
-
static bool writeMultiple(QIODevice &device, const std::vector<QVector<QPointF>> &l, const std::vector<QString> &n = {})
Writes multiple XY data sets side by side as a multi-column CSV.
- Parameters:
device – Output device, which must not already be open.
l – Vector of point-vectors, one per data set.
n – Optional column-name prefixes, one per data set. Sets without a matching entry receive auto-generated names (
x0/y0,x1/y1, …).
- Returns:
trueon success.
-
template<typename T>
static inline bool writeY(QIODevice &device, const QVector<T> d, QString title = "") Writes a single-column Y-only CSV with an optional title row.
- Template Parameters:
T – Element type; must be convertible via
QVariant::toString.- Parameters:
device – Output device, which must not already be open.
d – Values to write, one per row.
title – Column header text; defaults to
"y".
- Returns:
trueon success.
-
template<typename T>
static inline bool writeYMultiple(QIODevice &device, std::initializer_list<QString> titles, std::initializer_list<QVector<T>> l) Writes multiple single-column Y-only data sets side by side.
- Template Parameters:
T – Element type; must be convertible via
QVariant::toString.- Parameters:
device – Output device, which must not already be open.
titles – Column header labels, one per data set.
l – Data vectors, one per data set. Must match the size of titles.
- Returns:
trueon success;falseif titles and l have different sizes or the device cannot be opened.
-
static bool writeHeader(QIODevice &device, const std::multimap<QString, std::tuple<QString, QString, QString, QString, QString>> header)
Writes a full experiment header map as a six-column CSV.
Column order matches the
BC::CSVconstants:ok,ak,ai,vk,vv,vu.- Parameters:
device – Output device, which must not already be open.
header – Multimap from object key to a tuple of (array key, array index, value key, value, units).
- Returns:
trueon success.
-
static void writeLine(QTextStream &t, const std::vector<QVariant> l)
Writes a single delimited row to an already-open
QTextStream.Appends a newline (
BC::CSV::nl) after the last field.- Parameters:
t – Destination stream.
l – Values to write; each is converted via
QVariant::toString.
-
static QString formatInt64(qint64 n)
Formats a 64-bit integer as a base-36 string.
FID raw sample values are stored in base 36 to keep file sizes compact.
- Parameters:
n – Value to format.
- Returns:
Base-36 string representation, with a leading
"-"for negative values.
-
static void writeFidList(QIODevice &device, const FidList l)
Writes a list of FID objects as a multi-column base-36 CSV.
The header row names columns
fid0,fid1, etc. Sample values are encoded withformatInt64.- Parameters:
device – Output device, which must not already be open.
l – FID list to serialize; each FID becomes one column.
-
static bool writeVersionFile(int num)
Writes the
version.csvfile for the given experiment.Records the Blackchirp version constants (
majver,minver,patchver,relver,buildver) so that future reads can detect the format version.- Parameters:
num – Experiment number.
- Returns:
trueon success.
-
static bool exptDirExists(int num)
Tests whether the directory for the given experiment exists.
- Parameters:
num – Experiment number.
- Returns:
trueif the experiment directory exists on disk.
-
static int scanMaxExptNumOnDisk(const QString &basePath = QString())
Scans the data path for the highest experiment number on disk.
Walks the rightmost branch of the
<basePath>/experiments/mil/th/numhierarchy. Used to keep the storedexptNumreconciled with what is actually on disk so that users who switch acquisition app versions, or modify the data tree outside the program, do not allocate a duplicate experiment number.- Parameters:
basePath – Optional base path. When empty, the active
savePathfrom settings is used.- Returns:
Highest experiment number under
<basePath>/experiments, or 0 if no numeric subdirectory was found.
-
static void mirrorExptNumToV1Settings(int num)
Mirrors the next-experiment counter into the v1.x settings store.
Temporary cross-version coupling for the v2.x pre-release window: users who hit a regression may need to fall back to the v1.x acquisition app, which predates the per-major-version
applicationNameconvention and so reads the unsuffixedBlackchirp.confrather than v2.x’sBlackchirp2.conf. Mirroring the counter prevents v1.x from allocating a number that already exists on disk.The mirror is a no-op when v1.x’s
savePathdiffers from v2.x’s, sinceexptNumis per-tree — writing v2.x’s counter into v1.x’s settings would corrupt v1.x’s own counter for its own data tree.Note
Safe to remove once v1.x is no longer a supported fallback.
- Parameters:
num – Experiment number that v2.x has just allocated.
-
static bool createExptDir(int num)
Creates the directory hierarchy for the given experiment.
The hierarchy follows the pattern
savePath/experiments/mil/th/num, wheremilandthare the million- and thousand-buckets of num.- Parameters:
num – Experiment number.
- Returns:
trueif the directory was created or already existed.
-
static QDir exptDir(int num, QString path = "")
Returns a
QDirpointing to the given experiment’s root directory.- Parameters:
num – Experiment number.
path – Optional base path override. When empty,
SettingsStorageprovides the application data path.
- Returns:
QDirfor the experiment root (may not exist).
-
static QDir logDir()
Returns a
QDirpointing to the application log directory.- Returns:
QDirfor the log directory (may not exist).
-
static QDir textExportDir()
Returns a
QDirpointing to the text-export output directory.- Returns:
QDirfor the text-export directory (may not exist).
-
static QDir trackingDir()
Returns a
QDirpointing to the hardware-tracking data directory.- Returns:
QDirfor the tracking directory (may not exist).
-
enum class XYFormat