37 #include <QStringList> 38 #include <QTextStream> 54 m_mainModelSampleRate(mainModelSampleRate),
60 QFile *file =
new QFile(path);
63 if (!file->exists()) {
64 m_error = QFile::tr(
"File \"%1\" does not exist").arg(path);
65 }
else if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
66 m_error = QFile::tr(
"Failed to open file \"%1\"").arg(path);
99 SVDEBUG <<
"CSVFileReader::~CSVFileReader: device is " <<
m_device << endl;
102 SVDEBUG <<
"CSVFileReader::CSVFileReader: Closing device" << endl;
126 QRegExp nonNumericRx(
"[^0-9eE.,+-]");
135 numeric.remove(nonNumericRx);
139 double time = numeric.toDouble(&ok);
141 calculatedFrame =
sv_frame_t(time * sampleRate + 0.5);
145 double time = numeric.toDouble(&ok);
147 calculatedFrame =
sv_frame_t((time / 1000.0) * sampleRate + 0.5);
151 long n = numeric.toLong(&ok);
152 if (n >= 0) calculatedFrame = n;
155 calculatedFrame *= windowSize;
161 SVCERR <<
"WARNING: CSVFileReader::load: " 162 <<
"Bad time format (\"" << s
163 <<
"\") in data line " 166 SVCERR <<
"WARNING: Too many warnings" << endl;
171 return calculatedFrame;
209 Model *model =
nullptr;
213 unsigned int warnings = 0, warnLimit = 10;
214 unsigned int lineno = 0;
216 float min = 0.0, max = 0.0;
222 bool haveAnyValue =
false;
223 bool haveEndTime =
false;
224 bool pitchLooksLikeMIDI =
true;
227 bool firstEverValue =
true;
229 int valueColumns = 0;
236 int audioChannels = 0;
237 float **audioSamples =
nullptr;
238 float sampleShift = 0.f;
239 float sampleScale = 1.f;
243 audioChannels = valueColumns;
246 breakfastquay::allocate_and_zero_channels<float>
256 sampleShift = -128.f;
257 sampleScale = 1.f / 128.f;
261 sampleScale = 1.f / 32768.f;
266 map<QString, int> labelCountMap;
269 bool abandoned =
false;
271 while (!in.atEnd() && !abandoned) {
284 QString chunk = in.readLine();
285 QStringList lines = chunk.split(
'\r', QString::SkipEmptyParts);
307 for (
int li = 0; li < lines.size(); ++li) {
309 QString line = lines[li];
310 if (line.startsWith(
"#"))
continue;
327 SVDEBUG <<
"CSVFileReader: Creating sparse one-dimensional model" << endl;
333 SVDEBUG <<
"CSVFileReader: Creating sparse time-value model" << endl;
339 SVDEBUG <<
"CSVFileReader: Creating region model" << endl;
340 model2a =
new RegionModel(sampleRate, windowSize,
false);
345 SVDEBUG <<
"CSVFileReader: Creating note model" << endl;
346 model2b =
new NoteModel(sampleRate, windowSize,
false);
351 SVDEBUG <<
"CSVFileReader: Creating box model" << endl;
352 model2c =
new BoxModel(sampleRate, windowSize,
false);
357 SVDEBUG <<
"CSVFileReader: Creating editable dense three-dimensional model" << endl;
359 (sampleRate, windowSize, valueColumns);
365 SVDEBUG <<
"CSVFileReader: Creating writable wave-file model" << endl;
370 (path, sampleRate, valueColumns,
374 modelName = QFileInfo(path).fileName();
380 if (model && model->
isOK()) {
381 if (modelName !=
"") {
382 model->setObjectName(modelName);
387 if (!model || !model->
isOK()) {
388 SVCERR <<
"Failed to create model to load CSV file into" 393 model1 =
nullptr; model2 =
nullptr;
394 model2a =
nullptr; model2b =
nullptr; model2c =
nullptr;
395 model3 =
nullptr; modelW =
nullptr;
402 float otherValue = 0.f;
410 for (
int i = 0; i < list.size(); ++i) {
449 if (pitch < 0.f || pitch > 127.f) {
450 pitchLooksLikeMIDI =
false;
464 ++labelCountMap[label];
467 if (endFrame > frameNo) {
468 duration = endFrame - frameNo;
474 Event point(frameNo, label);
479 Event point(frameNo, value, label);
484 Event region(frameNo, value, duration, label);
485 model2a->
add(region);
489 float level = ((value >= 0.f && value <= 1.f) ? value : 1.f);
490 Event note(frameNo, pitch, duration, level, label);
496 if (value > otherValue) {
497 level = value - otherValue;
500 level = otherValue - value;
502 Event box(frameNo, value, duration, level, label);
509 for (
int i = 0; i < list.size(); ++i) {
516 float value = list[i].toFloat(&ok);
518 values.push_back(value);
520 if (firstEverValue || value < min) min = value;
521 if (firstEverValue || value > max) max = value;
523 if (firstEverValue) {
524 startFrame = frameNo;
526 }
else if (lineno == 1 &&
531 firstEverValue =
false;
534 if (warnings < warnLimit) {
535 SVCERR <<
"WARNING: CSVFileReader::load: " 536 <<
"Non-numeric value \"" 538 <<
"\" in data line " << lineno+1
542 }
else if (warnings == warnLimit) {
558 i < list.size() && channel < audioChannels;
567 float value = list[i].toFloat(&ok);
572 value += sampleShift;
573 value *= sampleScale;
575 audioSamples[channel][0] = value;
580 while (channel < audioChannels) {
581 audioSamples[channel][0] = 0.f;
585 bool ok = modelW->
addSamples(audioSamples, 1);
588 if (warnings < warnLimit) {
589 SVCERR <<
"WARNING: CSVFileReader::load: " 590 <<
"Unable to add sample to wave-file model" 601 frameNo += windowSize;
611 map<int, map<QString, float> > countLabelValueMap;
612 for (map<QString, int>::iterator i = labelCountMap.begin();
613 i != labelCountMap.end(); ++i) {
614 countLabelValueMap[i->second][i->first] = -1.f;
618 for (map<
int, map<QString, float> >::iterator i =
619 countLabelValueMap.end(); i != countLabelValueMap.begin(); ) {
621 SVCERR <<
"count -> " << i->first << endl;
622 for (map<QString, float>::iterator j = i->second.begin();
623 j != i->second.end(); ++j) {
625 SVCERR <<
"label -> " << j->first <<
", value " << v << endl;
630 map<Event, Event> eventMap;
633 for (
const Event &e: allEvents) {
634 int count = labelCountMap[e.getLabel()];
635 v = countLabelValueMap[count][e.getLabel()];
639 eventMap[e] =
Event(e.getFrame(), v,
640 e.getDuration(), e.getLabel());
643 for (
const auto &i: eventMap) {
648 if (i.first.getValue() == i.second.getValue()) {
653 model2a->
add(i.second);
660 if (pitchLooksLikeMIDI) {
673 breakfastquay::deallocate_channels(audioSamples, audioChannels);
685 base.replace(QRegExp(
"[/\\,.:;~<>\"'|?%*]+"),
"_");
688 if (convertedFileDir ==
"") {
689 SVCERR <<
"WARNING: CSVFileReader::getConvertedAudioFilePath: Failed to retrieve converted audio directory" << endl;
693 auto ms = QDateTime::currentDateTime().toMSecsSinceEpoch();
697 return QDir(convertedFileDir).filePath
698 (QString(
"%1-%2.wav").arg(base).arg(s));
double sv_samplerate_t
Sample rate.
virtual void setMinimumLevel(float sz)
Set the minimum value of the value in a bin.
int64_t sv_frame_t
Frame index, the unit of our time axis.
void writeComplete()
Indicate that writing is complete.
virtual void setDefinite(bool definite)=0
static QStringList split(QString s, QChar separator, bool quoted)
Split a string at the given separator character.
QString getConvertedAudioFilePath() const
void add(Event e) override
Editing methods.
EventVector getAllEvents() const
void add(Event e) override
Editing methods.
CSVFileReader(QString path, CSVFormat format, sv_samplerate_t mainModelSampleRate, ProgressReporter *reporter=0)
Construct a CSVFileReader to read the CSV file at the given path, with the given format.
ProgressReporter * m_reporter
bool isOK() const override
Return true if the file appears to be of the correct type.
virtual bool isOK() const =0
Return true if the model was constructed successfully.
bool containsEvent(const Event &e) const
void add(Event e) override
Editing methods.
sv_samplerate_t m_mainModelSampleRate
Model is the base class for all data models that represent any sort of data on a time scale based on ...
bool convertTimeValue(QString, int lineno, sv_samplerate_t sampleRate, int windowSize, sv_frame_t &calculatedFrame) const
virtual void setMaximumLevel(float sz)
Set the maximum value of the value in a bin.
BoxModel – a model for annotations having start time, duration, and a value range.
Model * load() const override
Read the file and return the corresponding data model.
QString getError() const override
static QString getConvertedAudioDirectory()
Return the directory in which an audio file converted from a data file should be saved.
virtual void setProgress(int percentage)=0
A model representing a wiggly-line plot with points at arbitrary intervals of the model resolution...
RegionModel – a model for intervals associated with a value, which we call regions for no very compe...
void setScaleUnits(QString units)
An immutable(-ish) type used for point and event representation in sparse models, as well as for inte...
virtual void setStartFrame(sv_frame_t)
Set the frame offset of the first column.
void updateModel()
Tell the model to update its own (read) view of the (written) file.
void add(Event e) override
Editing methods.
virtual void setResolution(int sz)
Set the number of sample frames covered by each set of bins.
A model representing a series of time instants with optional labels but without values.
std::vector< Event > EventVector
void remove(Event e) override
void add(Event e) override
Editing methods.
virtual bool addSamples(const float *const *samples, sv_frame_t count)
Call addSamples to append a block of samples to the end of the file.
virtual void setColumn(int x, const Column &values)
Set the entire set of bin values at the given column.
virtual bool wasCancelled() const =0
static double stringToDoubleLocaleFree(QString s, bool *ok=0)
Convert a string to a double using basic "C"-locale syntax, i.e.