1 // Copyright (c) 2016 The SigViewer Development Team
2 // Licensed under the GNU General Public License (GPL)
3 // https://www.gnu.org/licenses/gpl
4
5
6 #include "biosig_reader.h"
7 #include "biosig_basic_header.h"
8 #include "file_handler_factory_registrator.h"
9 #include "gui/progress_bar.h"
10 #include "base/fixed_data_block.h"
11
12
13 #include <QSettings>
14
15
16
17
18 using namespace std;
19
20 namespace sigviewer
21 {
22
23 //-----------------------------------------------------------------------------
24 FILE_SIGNAL_READER_REGISTRATION(gdf, BioSigReader);
25 FILE_SIGNAL_READER_REGISTRATION(edf, BioSigReader);
26 FILE_SIGNAL_READER_REGISTRATION(bdf, BioSigReader);
27 FILE_SIGNAL_READER_REGISTRATION(dat, BioSigReader);
28 FILE_SIGNAL_READER_REGISTRATION(cnt, BioSigReader);
29 FILE_SIGNAL_READER_REGISTRATION(vhdr, BioSigReader);
30 FILE_SIGNAL_READER_REGISTRATION(bkr, BioSigReader);
31
32 FILE_SIGNAL_READER_REGISTRATION(evt, BioSigReader);
33
34 FILE_SIGNAL_READER_DEFAULT_REGISTRATION(BioSigReader);
35
36 //-----------------------------------------------------------------------------
BioSigReader()37 BioSigReader::BioSigReader() :
38 basic_header_ (0),
39 biosig_header_ (0),
40 buffered_all_channels_ (false),
41 buffered_all_events_ (false)
42 {
43 qDebug () << "Constructed BioSigReader";
44 // nothing to do here
45 }
46
47 //-----------------------------------------------------------------------------
~BioSigReader()48 BioSigReader::~BioSigReader()
49 {
50 doClose();
51 }
52
53 //-----------------------------------------------------------------------------
createInstance(QString const & file_path)54 QPair<FileSignalReader*, QString> BioSigReader::createInstance (QString const& file_path)
55 {
56 BioSigReader* reader (new BioSigReader);
57 if (file_path.section('.', -1) == "evt")
58 reader->buffered_all_channels_ = true;
59 QString error = reader->open (file_path);
60 if (error.size() > 0)
61 {
62 qDebug () << error;
63 return QPair<FileSignalReader*, QString> (0, error);
64 }
65 else
66 return QPair<FileSignalReader*, QString> (reader, "");
67 }
68
69
70 //-----------------------------------------------------------------------------
doClose() const71 void BioSigReader::doClose () const
72 {
73 if (biosig_header_)
74 destructHDR (biosig_header_);
75 biosig_header_ = NULL;
76 }
77
78 //-----------------------------------------------------------------------------
getSignalData(ChannelID channel_id,size_t start_sample,size_t length) const79 QSharedPointer<DataBlock const> BioSigReader::getSignalData (ChannelID channel_id,
80 size_t start_sample,
81 size_t length) const
82 {
83 QMutexLocker lock (&mutex_);
84
85 if (!buffered_all_channels_)
86 bufferAllChannels();
87
88 if (!channel_map_.contains(channel_id))
89 return QSharedPointer<DataBlock const> (0);
90
91 if (length == basic_header_->getNumberOfSamples() &&
92 start_sample == 0)
93 return channel_map_[channel_id];
94 else
95 return channel_map_[channel_id]->createSubBlock (start_sample, length);
96 }
97
98 //-----------------------------------------------------------------------------
getEvents() const99 QList<QSharedPointer<SignalEvent const> > BioSigReader::getEvents () const
100 {
101 QMutexLocker lock (&mutex_);
102 QList<QSharedPointer<SignalEvent const> > empty_list;
103 if (!biosig_header_)
104 return empty_list;
105
106 if (!buffered_all_events_)
107 bufferAllEvents();
108
109 return events_;
110 }
111
112 //-----------------------------------------------------------------------------
open(QString const & file_name)113 QString BioSigReader::open (QString const& file_name)
114 {
115
116 QMutexLocker lock (&mutex_);
117 return loadFixedHeader (file_name);
118 }
119
120 //-----------------------------------------------------------------------------
loadFixedHeader(const QString & file_name)121 QString BioSigReader::loadFixedHeader(const QString& file_name)
122 {
123 QMutexLocker locker (&biosig_access_lock_);
124 tzset();
125
126 if(biosig_header_==NULL)
127 {
128 biosig_header_ = constructHDR (0,0);
129 biosig_header_->FLAG.UCAL = 0;
130 biosig_header_->FLAG.OVERFLOWDETECTION = 1;
131 }
132
133 biosig_header_ = sopen(file_name.toStdString().c_str(), "r", biosig_header_ );
134
135 basic_header_ = QSharedPointer<BasicHeader>
136 (new BiosigBasicHeader (biosig_header_, file_name));
137
138 if (!QFile::exists(file_name))
139 {
140 sclose (biosig_header_);
141 destructHDR(biosig_header_);
142 biosig_header_ = NULL;
143
144 qDebug() << "File doesn't exist.";
145 QMessageBox msgBox;
146 msgBox.setIcon(QMessageBox::Warning);
147 msgBox.setText("File does not exist.");
148 msgBox.setStandardButtons(QMessageBox::Ok);
149 msgBox.exec();
150
151 return "non-exist";
152 }
153
154 #if (BIOSIG_VERSION < 10400)
155 if (biosig_header_ == NULL || serror(biosig_header_))
156 #else
157 if (biosig_header_ == NULL || serror2(biosig_header_))
158 #endif
159 {
160 sclose (biosig_header_);
161 destructHDR(biosig_header_);
162 biosig_header_ = NULL;
163
164 return "file not supported";
165 }
166
167 convert2to4_eventtable(biosig_header_);
168
169 basic_header_->setNumberEvents(biosig_header_->EVENT.N);
170
171 if (biosig_header_->EVENT.SampleRate)
172 basic_header_->setEventSamplerate(biosig_header_->EVENT.SampleRate);
173 else
174 basic_header_->setEventSamplerate(biosig_header_->SampleRate);
175
176 setChannelColors();
177 setEventTypeColors();
178
179 return "";
180 }
181
182 //-----------------------------------------------------------------------------
getBasicHeader()183 QSharedPointer<BasicHeader> BioSigReader::getBasicHeader ()
184 {
185 //QMutexLocker lock (&mutex_);
186 return basic_header_;
187 }
188
189 //-----------------------------------------------------------------------------
setChannelColors()190 int BioSigReader::setChannelColors()
191 {
192 QSharedPointer<ColorManager> colorPicker = ApplicationContextImpl::getInstance()->color_manager_;
193 for (size_t i = 0; i < basic_header_->getNumberChannels(); i++)
194 colorPicker->setChannelColor(i, colorPicker->getDefaultChannelColor());
195
196 colorPicker->saveSettings();
197
198 return 0;
199 }
200
201 //-----------------------------------------------------------------------------
bufferAllChannels() const202 void BioSigReader::bufferAllChannels () const
203 {
204 size_t numberOfSamples = biosig_header_->NRec * biosig_header_->SPR;
205 biosig_data_type* read_data = new biosig_data_type[numberOfSamples * basic_header_->getNumberChannels()];
206
207 biosig_header_->FLAG.ROW_BASED_CHANNELS = 0;
208
209 QString progress_name = QObject::tr("Loading data...");
210
211 sread(read_data, 0, biosig_header_->NRec, biosig_header_);
212
213 for (unsigned channel_id = 0; channel_id < basic_header_->getNumberChannels();
214 ++channel_id)
215 {
216 ProgressBar::instance().increaseValue (1, progress_name);
217
218 QSharedPointer<QVector<float32> > raw_data(new QVector<float32> (numberOfSamples, NAN));
219 for (size_t data_index = 0; data_index < numberOfSamples; data_index++)
220 raw_data->operator [](data_index) = read_data[data_index + channel_id * numberOfSamples];
221
222 QSharedPointer<DataBlock const> data_block(new FixedDataBlock(raw_data, basic_header_->getSampleRate()));
223 channel_map_[channel_id] = data_block;
224 }
225
226 buffered_all_channels_ = true;
227 if (buffered_all_events_)
228 doClose();
229 delete[] read_data;
230 }
231
232 //-------------------------------------------------------------------------
bufferAllEvents() const233 void BioSigReader::bufferAllEvents () const
234 {
235 unsigned number_events = biosig_header_->EVENT.N;
236 // Hack Hack: Transforming Events to have the same sample rate as the signals
237 double rate_transition;
238 if ( ( biosig_header_->EVENT.SampleRate <= 0.0) ||
239 ( biosig_header_->EVENT.SampleRate != biosig_header_->EVENT.SampleRate))
240 rate_transition = 1;
241 else
242 rate_transition = basic_header_->getEventSamplerate() / biosig_header_->EVENT.SampleRate;
243
244 for (unsigned index = 0; index < number_events; index++)
245 {
246 QSharedPointer<SignalEvent> event (new SignalEvent (biosig_header_->EVENT.POS[index] * rate_transition,
247 biosig_header_->EVENT.TYP[index],
248 biosig_header_->EVENT.SampleRate * rate_transition, -1));
249 if (biosig_header_->EVENT.CHN)
250 {
251 if (biosig_header_->EVENT.CHN[index] == 0)
252 event->setChannel (UNDEFINED_CHANNEL);
253 else
254 event->setChannel (biosig_header_->EVENT.CHN[index] - 1);
255
256 if (biosig_header_->EVENT.TYP[index] != 0x7fff)
257 event->setDuration (biosig_header_->EVENT.DUR[index] * rate_transition);
258 else // sparse samples (Typ=0x7fff) do not have a duration, but the duration field is used to store the sample value
259 event->setDuration(0);
260 }
261 else
262 {
263 event->setChannel(UNDEFINED_CHANNEL);
264 event->setDuration (1);
265 }
266 events_.append (event);
267 }
268
269 buffered_all_events_ = true;
270 if (buffered_all_channels_)
271 doClose();
272 }
273
274 }
275