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