CSVStreamWriter.h
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2017 Queen Mary, University of London.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #ifndef SV_CSV_STREAM_WRITER_H
17 #define SV_CSV_STREAM_WRITER_H
18 
19 #include "base/BaseTypes.h"
20 #include "base/Selection.h"
21 #include "base/ProgressReporter.h"
22 #include "base/DataExportOptions.h"
23 #include "base/StringBits.h"
24 #include "data/model/Model.h"
25 
26 #include <QString>
27 #include <algorithm>
28 #include <numeric>
29 
30 namespace CSVStreamWriter
31 {
32 
33 template <class OutStream>
34 bool
35 writeInChunks(OutStream& oss,
36  const Model& model,
37  const MultiSelection& regions,
38  ProgressReporter* reporter = nullptr,
39  QString delimiter = ",",
41  const sv_frame_t blockSize = 16384)
42 {
43  const auto selections = regions.getSelections();
44  if (blockSize <= 0 || selections.empty()) return false;
45 
46  // TODO, some form of checking validity of selections?
47  const auto nFramesToWrite = std::accumulate(
48  selections.begin(),
49  selections.end(),
50  0,
51  [](sv_frame_t acc, const Selection& current) -> sv_frame_t {
52  return acc + (current.getEndFrame() - current.getStartFrame());
53  }
54  );
55 
56  const auto wasCancelled = [&reporter]() {
57  return reporter && reporter->wasCancelled();
58  };
59 
60  sv_frame_t nFramesWritten = 0;
61  int previousProgress = 0;
62  bool started = false;
63 
64  for (const auto& extents : selections) {
65  const auto startFrame = extents.getStartFrame();
66  const auto endFrame = extents.getEndFrame();
67  auto readPtr = startFrame;
68  while (readPtr < endFrame) {
69  if (wasCancelled()) return false;
70 
71  const auto start = readPtr;
72  const auto end = std::min(start + blockSize, endFrame);
73  const auto data = model.toStringExportRows(
74  options,
75  start,
76  end - start
77  );
78 
79  if (!data.empty()) {
80  for (const auto &row: data) {
81  if (started) {
82  oss << "\n";
83  } else {
84  started = true;
85  }
86  oss << StringBits::joinDelimited(row, delimiter);
87  }
88  }
89 
90  nFramesWritten += end - start;
91  const int currentProgress =
92  int(100 * nFramesWritten / nFramesToWrite);
93  const bool hasIncreased = currentProgress > previousProgress;
94  if (hasIncreased) {
95  if (reporter) reporter->setProgress(currentProgress);
96  previousProgress = currentProgress;
97  }
98  readPtr = end;
99  }
100  }
101  return !wasCancelled(); // setProgress could process event loop
102 }
103 
104 template <class OutStream>
105 bool
106 writeInChunks(OutStream& oss,
107  const Model& model,
108  const Selection& extents,
109  ProgressReporter* reporter = nullptr,
110  QString delimiter = ",",
112  const sv_frame_t blockSize = 16384)
113 {
114  const auto startFrame = extents.isEmpty() ?
115  model.getStartFrame() : extents.getStartFrame();
116  const auto endFrame = extents.isEmpty() ?
117  model.getEndFrame() : extents.getEndFrame();
118  const auto hasValidExtents = startFrame >= 0 && endFrame > startFrame;
119  if (!hasValidExtents) return false;
120  Selection all {
121  startFrame,
122  endFrame
123  };
124  MultiSelection regions;
125  regions.addSelection(all);
126  return writeInChunks(
127  oss,
128  model,
129  regions,
130  reporter,
131  delimiter,
132  options,
133  blockSize
134  );
135 }
136 
137 template <class OutStream>
138 bool
139 writeInChunks(OutStream& oss,
140  const Model& model,
141  ProgressReporter* reporter = nullptr,
142  QString delimiter = ",",
144  const sv_frame_t blockSize = 16384)
145 {
146  const Selection empty;
147  return writeInChunks(
148  oss,
149  model,
150  empty,
151  reporter,
152  delimiter,
153  options,
154  blockSize
155  );
156 }
157 } // namespace CSVStreamWriter
158 #endif
sv_frame_t getEndFrame() const
Definition: Selection.cpp:69
const SelectionList & getSelections() const
Definition: Selection.cpp:111
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
A selection object simply represents a range in time, via start and end frame.
Definition: Selection.h:40
bool isEmpty() const
Definition: Selection.cpp:57
sv_frame_t getEndFrame() const
Return the audio frame at the end of the model, i.e.
Definition: Model.h:87
void addSelection(const Selection &selection)
Definition: Selection.cpp:124
virtual QVector< QVector< QString > > toStringExportRows(DataExportOptions options, sv_frame_t startFrame, sv_frame_t duration) const =0
Emit events starting within the given range as string rows ready for conversion to an e...
Model is the base class for all data models that represent any sort of data on a time scale based on ...
Definition: Model.h:51
virtual sv_frame_t getStartFrame() const =0
Return the first audio frame spanned by the model.
static QString joinDelimited(QVector< QString > row, QString delimiter)
Join a vector of strings into a single string, with the delimiter as the joining string.
Definition: StringBits.cpp:172
sv_frame_t getStartFrame() const
Definition: Selection.cpp:63
bool writeInChunks(OutStream &oss, const Model &model, const MultiSelection &regions, ProgressReporter *reporter=nullptr, QString delimiter=",", DataExportOptions options=DataExportDefaults, const sv_frame_t blockSize=16384)
int DataExportOptions