[med-svn] [SCM] aghermann branch, master, updated. 99b1d5a023eee9df74b0e0d6f894516fc79435ad
Andrei Zavada
johnhommer at gmail.com
Sun Jul 7 23:04:06 UTC 2013
The following commit has been merged in the master branch:
commit cf860c0627565c8df59a3ee8fca9d82b77f2eeb0
Author: Andrei Zavada <johnhommer at gmail.com>
Date: Thu Jun 27 19:56:51 2013 +0300
WIP
diff --git a/src/libsigfile/edf.cc b/src/libsigfile/edf.cc
index 657d36d..e237229 100644
--- a/src/libsigfile/edf.cc
+++ b/src/libsigfile/edf.cc
@@ -365,6 +365,7 @@ CEDFFile (CEDFFile&& rv)
_mmapping = rv._mmapping;
_fd = rv._fd;
+ rv._fd = -1; // for propriety's sake
rv._mmapping = (void*)-1; // will prevent munmap in ~CEDFFile()
}
diff --git a/src/libsigfile/tsv.cc b/src/libsigfile/tsv.cc
index c6283a7..c770a01 100644
--- a/src/libsigfile/tsv.cc
+++ b/src/libsigfile/tsv.cc
@@ -39,9 +39,9 @@ set_start_time( time_t s)
{
char b[9];
strftime( b, 9, "%d.%m.%y", localtime(&s));
- header.recording_date.assign( b);
+ _recording_date.assign( b);
strftime( b, 9, "%H.%M.%s", localtime(&s));
- header.recording_time.assign( b);
+ _recording_time.assign( b);
return 0;
}
@@ -67,12 +67,15 @@ CTSVFile (const string& fname_, const int flags_)
if ( _parse_header() ) { // creates channels list
if ( not (flags_ & sigfile::CSource::no_field_consistency_check) ) {
close( _fd);
+ _fd = -1;
throw invalid_argument (explain_status(_status)); // _status set in _parse_header()
} else
fprintf( stderr, "CTSVFile::CTSVFile(\"%s\") Warning: parse header failed, but proceeding anyway\n", fname_.c_str());
}
// channels now available
+ _read_data();
+
// ancillary files:
if ( not (flags_ & sigfile::CSource::no_ancillary_files) )
load_ancillary_files();
@@ -97,8 +100,6 @@ CTSVFile (const string& fname_, const TSubtype subtype_, const int flags_,
}
// fill out some essential header fields
- resize_seconds( recording_time_);
-
_subject = {"Fafa_1", "Mr. Fafa"};
set_recording_id( "Zzz");
set_comment( fname_);
@@ -106,85 +107,40 @@ CTSVFile (const string& fname_, const TSubtype subtype_, const int flags_,
size_t hi = 0;
for ( auto& h : channels_ ) {
- auto& H = channels[hi];
+ auto& H = channels[hi++];
H.ucd = h;
}
-}
-
-
+ resize_seconds( recording_time_);
+}
-// uncomment on demand (also un-dnl AC_CHECK_FUNCS(mremap,,) in configure.ac)
-/*
-size_t
-CTSVFile::
-resize( const size_t new_records)
-{
- size_t total_samples_per_record = 0;
- for ( auto& H : channels )
- total_samples_per_record += H.samples_per_record; // total samplerate
- size_t old_records
- = n_data_records;
- auto new_fsize
- = header_length + 2 * total_samples_per_record * (n_data_records = new_records);
-
-#if !HAVE_MREMAP
- _mmapping =
- mremap( _mmapping,
- _fsize,
- new_fsize,
- 0|MREMAP_MAYMOVE);
-#else
- void *_m2 =
- mmap( NULL,
- new_fsize,
- PROT_READ | PROT_WRITE, MAP_SHARED,
- _fd,
- 0);
- memmove( _m2, _mmapping, _fsize);
- munmap( _mmapping, _fsize);
- _mmapping = _m2;
-#endif
-
- if ( _mmapping == (void*)-1 ) {
- close( _fd);
- throw length_error ("CTSVFile::resize(): mmap error");
- }
- _fsize = new_fsize;
- return old_records;
-}
-*/
CTSVFile::
CTSVFile (CTSVFile&& rv)
: CSource (move(rv))
{
- header = rv.header; // no need to re-layout as we don't mremap
- n_data_records = rv.n_data_records;
- data_record_size = rv.data_record_size;
+ swap( _patient_id, rv._patient_id);
+ swap( _recording_id, rv._recording_id);
+ swap( _recording_date, rv._recording_date);
+ swap( _recording_time, rv._recording_time);
+ swap( _episode, rv._episode);
+ swap( _session, rv._session);
+ swap( _comment, rv._comment);
+
+ swap( metadata, rv.metadata);
_subtype = rv._subtype;
_start_time = rv._start_time;
_end_time = rv._end_time;
- swap( _patient_id, rv._patient_id);
- swap( _episode, rv._episode);
- swap( _session, rv._session);
swap( channels, rv.channels);
swap( common_annotations, rv.common_annotations);
- header_length = rv.header_length;
- _fsize = rv._fsize;
- _fld_pos = rv._fld_pos;
- _total_samples_per_record =
- rv._total_samples_per_record;
- _mmapping = rv._mmapping;
- _fd = rv._fd;
-
- rv._mmapping = (void*)-1; // will prevent munmap in ~CTSVFile()
+ _fd = rv._fd;
+ rv._fd = -1;
}
@@ -208,273 +164,47 @@ CTSVFile::
_parse_header()
{
size_t n_channels;
- try {
- _fld_pos = 0;
- _get_next_field( header.version_number, 8);
- _get_next_field( header.patient_id, 80);
- _get_next_field( header.recording_id, 80);
- _get_next_field( header.recording_date, 8);
- _get_next_field( header.recording_time, 8);
- _get_next_field( header.header_length, 8);
- _get_next_field( header.reserved, 44);
- _get_next_field( header.n_data_records, 8);
- _get_next_field( header.data_record_size, 8);
- _get_next_field( header.n_channels, 4);
-
- if ( strncmp( header.version_number, version_string, 8) ) {
- _status |= (bad_version | inoperable);
- return -2;
- }
-
- _subtype =
- (strncasecmp( header.reserved, "edf+c", 5) == 0)
- ? edfplus_c
- : (strncasecmp( header.reserved, "edf+d", 5) == 0)
- ? edfplus_d
- : edf;
-
- size_t header_length;
-
- header_length = n_data_records = data_record_size = n_channels = 0;
- sscanf( header.header_length, "%8zu", &header_length);
- sscanf( header.n_data_records, "%8zu", &n_data_records);
- sscanf( header.data_record_size, "%8lg", &data_record_size); // edf+ supports fractions
- sscanf( header.n_channels, "%4zu", &n_channels);
-
- if ( !header_length || !n_data_records || !data_record_size || !n_channels ) {
- _status |= bad_numfld;
- if ( not (flags() & no_field_consistency_check) )
- return -2;
- }
- if ( n_channels == 0 ) {
- _status |= inoperable;
- return -2;
- }
-
- _patient_id = trim( string (header.patient_id, 80));
-
- // sub-parse patient_id into SSubjectId struct
- {
- auto subfields = tokens( _patient_id, " ");
- if ( unlikely (_patient_id.empty()) ) {
- _status |= missing_patient_id;
- } else if ( subfields.size() < 4 ) {
- _subject.id = subfields.front();
- _status |= nonconforming_patient_id;
- } else {
- if ( subfields.size() > 4 )
- _status |= extra_patientid_subfields;
- auto i = subfields.begin();
- _subject.id = *i++;
- _subject.gender = agh::SSubjectId::char_to_gender((*i++)[0]);
- _subject.dob = agh::SSubjectId::str_to_dob(*i++);
- _subject.name = join( tokens(*i++, "_"), " ");
- if ( not _subject.valid() )
- _status |= invalid_subject_details;
- }
- }
+ _subtype = TSubtype::tsv;
- // deal with episode and session
- {
- // (a) parsed from RecordingID_raw
- char int_session[81], int_episode[81];
- string rec_id_isolated (trim( string (header.recording_id, 80)));
+ // deal with episode and session
+ {
+ // (a) parsed from RecordingID_raw
+ char int_session[81], int_episode[81];
+ string rec_id_isolated (trim( _recording_id));
#define T "%80[-a-zA-Z0-9 _]"
- if ( sscanf( rec_id_isolated.c_str(), T ", " T, int_episode, int_session) == 2 ||
- sscanf( rec_id_isolated.c_str(), T ": " T, int_session, int_episode) == 2 ||
- sscanf( rec_id_isolated.c_str(), T "/" T, int_session, int_episode) == 2 ||
- sscanf( rec_id_isolated.c_str(), T " (" T ")", int_session, int_episode) == 2 )
- ;
- else
- _status |= (nosession | noepisode);
+ if ( sscanf( rec_id_isolated.c_str(), T ", " T, int_episode, int_session) == 2 ||
+ sscanf( rec_id_isolated.c_str(), T ": " T, int_session, int_episode) == 2 ||
+ sscanf( rec_id_isolated.c_str(), T "/" T, int_session, int_episode) == 2 ||
+ sscanf( rec_id_isolated.c_str(), T " (" T ")", int_session, int_episode) == 2 )
+ ;
+ else
+ _status |= (nosession | noepisode);
#undef T
- // (b) identified from file name
- string fn_episode;
- size_t basename_start = _filename.rfind( '/');
- fn_episode =
- _filename.substr(
- basename_start + 1,
- _filename.size() - basename_start - 4 /* strlen(".edf") */ - 1);
- // chip away '-1' if present
- if ( fn_episode.size() >= 3 /* strlen("a-1") */ ) {
- size_t sz = fn_episode.size();
- if ( fn_episode[sz-2] == '-' && isdigit(fn_episode[sz-1]) )
- fn_episode.erase( sz-2, 2);
- }
-
- if ( _status & noepisode ) { // (a) failed
- _episode.assign( fn_episode); // use RecordingID_raw as Session
- _session.assign( rec_id_isolated);
- } else {
- _episode.assign( int_episode);
- _session.assign( int_session);
- }
- }
-
- {
- struct tm ts;
- char *p;
- //memset( &ts, 0, sizeof(struct tm));
- ts.tm_isdst = 0; // importantly
- string tmp (header.recording_date, 8);
- p = strptime( tmp.c_str(), "%d.%m.%y", &ts);
- if ( p == NULL || *p != '\0' ) {
- _status |= date_unparsable;
- if ( not (flags() & no_field_consistency_check) )
- return -2;
- }
- tmp = {string (header.recording_time, 8)};
- p = strptime( tmp.c_str(), "%H.%M.%S", &ts);
- if ( p == NULL || *p != '\0' ) {
- _status |= time_unparsable;
- if ( not (flags() & no_field_consistency_check) )
- return -2;
- }
-
- // if ( ts.tm_year < 50 )
- // ts.tm_year += 100;
- _start_time = mktime( &ts);
- if ( _start_time == (time_t)-1 )
- _status |= (date_unparsable|time_unparsable);
- else
- _end_time = _start_time + n_data_records * data_record_size;
+ // (b) identified from file name
+ string fn_episode;
+ size_t basename_start = _filename.rfind( '/');
+ fn_episode =
+ _filename.substr(
+ basename_start + 1,
+ _filename.size() - basename_start - 4 /* strlen(".edf") */ - 1);
+ // chip away '-1' if present
+ if ( fn_episode.size() >= 3 /* strlen("a-1") */ ) {
+ size_t sz = fn_episode.size();
+ if ( fn_episode[sz-2] == '-' && isdigit(fn_episode[sz-1]) )
+ fn_episode.erase( sz-2, 2);
}
- if ( n_channels > max_channels ) {
- _status |= bad_numfld;
- if ( not (flags() & no_field_consistency_check) )
- return -2;
+ if ( _status & noepisode ) { // (a) failed
+ _episode.assign( fn_episode); // use RecordingID_raw as Session
+ _session.assign( rec_id_isolated);
} else {
- channels.resize( n_channels);
-
- // determine & validate signal types
- for ( auto &H : channels ) {
- _get_next_field( H.header.label, 16);
- string isolated_label = trim( string (H.header.label, 16));
-
- if ( isolated_label == sigfile::edf_annotations_label )
- H.ucd = {sigfile::SChannel::TType::embedded_annotation, 0};
- else {
- auto tt = agh::str::tokens( isolated_label, " ");
- // parse legacy pre 0.9 specs ("EEG F3" etc)
- if ( tt.size() > 1 ) {
- string suggested_type = tt.front();
- H.ucd = {(tt.pop_front(), agh::str::join( tt, " "))};
- if ( suggested_type != H.ucd.type_s() )
- _status |= recognised_channel_conflicting_type;
- } else {
- H.ucd = sigfile::SChannel (isolated_label);
-
- if ( H.ucd.type() == sigfile::SChannel::TType::eeg &&
- H.ucd.idx() == sigfile::EEG::custom )
- _status |= non1020_channel;
- if ( H.ucd.type() == SChannel::SChannel::TType::other )
- _status |= nonkemp_signaltype;
- }
- }
- }
- for ( auto &H : channels )
- H.transducer_type =
- trim( string (_get_next_field( H.header.transducer_type, 80), 80));
-
- for ( auto &H : channels )
- H.physical_dim =
- trim( string (_get_next_field( H.header.physical_dim, 8), 8));
-
- for ( auto &H : channels ) {
- _get_next_field( H.header.physical_min, 8);
- if ( H.ucd.type() == sigfile::SChannel::TType::embedded_annotation )
- continue;
- if ( sscanf( H.header.physical_min, "%8lg",
- &H.physical_min) != 1 ) {
- _status |= bad_numfld;
- if ( not (flags() & no_field_consistency_check) )
- return -2;
- }
- }
- for ( auto &H : channels ) {
- _get_next_field( H.header.physical_max, 8);
- if ( H.ucd.type() == sigfile::SChannel::TType::embedded_annotation )
- continue;
- if ( sscanf( H.header.physical_max, "%8lg",
- &H.physical_max) != 1 ) {
- _status |= bad_numfld;
- if ( not (flags() & no_field_consistency_check) )
- return -2;
- }
- }
-
- for ( auto &H : channels ) {
- _get_next_field( H.header.digital_min, 8);
- if ( H.ucd.type() == sigfile::SChannel::TType::embedded_annotation )
- continue;
- if ( sscanf( H.header.digital_min, "%8d",
- &H.digital_min) != 1 ) {
- _status |= bad_numfld;
- if ( not (flags() & no_field_consistency_check) )
- return -2;
- }
- }
- for ( auto &H : channels ) {
- _get_next_field( H.header.digital_max, 8);
- if ( H.ucd.type() == sigfile::SChannel::TType::embedded_annotation )
- continue;
- if ( sscanf( H.header.digital_max, "%8d",
- &H.digital_max) != 1 ) {
- _status |= bad_numfld;
- if ( not (flags() & no_field_consistency_check) )
- return -2;
- }
- }
-
- for ( auto &H : channels )
- H.filtering_info.assign(
- trim( string (_get_next_field( H.header.filtering_info, 80), 80)));
-
- for ( auto &H : channels ) {
- char *tail;
- string t {trim( string (_get_next_field( H.header.samples_per_record, 8), 8))};
- H.samples_per_record =
- strtoul( t.c_str(), &tail, 10);
- if ( tail == NULL || *tail != '\0' ) {
- _status |= bad_numfld;
- if ( not (flags() & no_field_consistency_check) )
- return -2;
- }
- }
-
- for ( auto &H : channels )
- H.reserved.assign(
- trim( string (_get_next_field( H.header.reserved, 32), 32)));
+ _episode.assign( int_episode);
+ _session.assign( int_session);
}
- } catch (TStatus ex) {
- return -1;
- } catch (invalid_argument ex) {
- _status |= bad_numfld;
- if ( not (flags() & no_field_consistency_check) )
- return -3;
}
- // calculate gain
- for ( auto &H : channels )
- if ( H.ucd.type() != sigfile::SChannel::TType::embedded_annotation ) {
- if ( H.physical_max <= H.physical_min ||
- H.digital_max <= H.digital_min )
- _status |= nogain;
- H.scale =
- (H.physical_max - H.physical_min) /
- (H.digital_max - H.digital_min );
- }
-
- // convenience field
- _total_samples_per_record = 0;
- for ( auto &H : channels ) {
- H._at = _total_samples_per_record;
- _total_samples_per_record += H.samples_per_record;
- }
-
- // are channels unique?
+ // are channels unique?
for ( auto &H : channels )
for ( auto &J : channels ) {
if ( &J != &H && J.ucd == H.ucd ) {
@@ -488,77 +218,11 @@ outer_break:
}
-
-
-
-
-
-
int
CTSVFile::
-_extract_embedded_annotations()
+_read_data()
{
- auto S = find( channels.begin(), channels.end(), sigfile::edf_annotations_label);
- if ( S == channels.end() )
- return 0;
- auto& AH = *S;
-
- size_t alen = AH.samples_per_record * 2;
-
- for ( size_t r = 0; r < n_data_records; ++r ) {
- char *this_a =
- (char*)_mmapping + header_length
- + r * _total_samples_per_record * 2 // full records before
- + AH._at * 2; // offset to our samples
-
- if ( (this_a[0] == '+' || this_a[0] == '-') &&
- (isdigit(this_a[1]) || this_a[1] == '.') ) {
-
- string abuf (this_a, alen); // NULL-terminated, possibly at pos <alen
-
- float offset,
- duration;
- const char
- *offset_p = abuf.c_str(),
- *duration_p,
- *tals_p;
-
- while ( (tals_p = strchr( offset_p, 20)) ) {
- // determine if we have duration
- try {
- if ( (duration = 0.,
- (duration_p = strchr( offset_p, 21))) &&
- duration_p < tals_p ) {
- offset = stof( string (offset_p, duration_p - offset_p));
- if ( *duration_p != 20 )
- duration = stof( string (duration_p, tals_p - duration_p));
- } else {
- offset = stof( string (offset_p, tals_p - offset_p));
- }
- } catch (...) {
- break;
- }
-
- if ( offset_p == this_a && *tals_p == 20 ) // no TALs, it's an explicit record timestamp, not an annotation
- _record_offsets.push_back( offset);
-
- else {
- auto tals = tokens_trimmed( tals_p, (char)20);
- for ( auto& t : tals )
- if ( not t.empty() ) {
- common_annotations.emplace_back(
- offset,
- offset + duration,
- t,
- SAnnotation::TType::plain);
- }
- }
-
- offset_p = tals_p + strlen(tals_p) + 1;
- }
- }
- }
-
+
return 0;
}
@@ -568,6 +232,7 @@ _extract_embedded_annotations()
+
string
CTSVFile::
details( const int which) const
@@ -600,8 +265,8 @@ details( const int which) const
filename(),
subtype_s(),
patient_id(),
- trim( string (header.recording_id, 80)).c_str(),
- trim( string (header.recording_date, 8)).c_str(),
+ recording_id.c_str(),
+ recording_date, 8)).c_str(),
trim( string (header.recording_time, 8)).c_str(),
channels.size(),
n_data_records,
diff --git a/src/libsigfile/tsv.hh b/src/libsigfile/tsv.hh
index c046975..3812e3d 100644
--- a/src/libsigfile/tsv.hh
+++ b/src/libsigfile/tsv.hh
@@ -90,15 +90,15 @@ class CTSVFile
// identification
const char* patient_id() const
- { return header.patient_id.c_str(); }
+ { return _patient_id.c_str(); }
const char* recording_id() const
- { return header.recording_id.c_str(); }
+ { return _recording_id.c_str(); }
const char* comment() const
- { return header.comment.c_str(); }
+ { return _comment.c_str(); }
const char* episode() const
- { return header._episode.c_str(); }
+ { return _episode.c_str(); }
const char* session() const
- { return header._session.c_str(); }
+ { return _session.c_str(); }
// times
time_t start_time() const
@@ -111,27 +111,27 @@ class CTSVFile
// setters
int set_patient_id( const string& s)
{
- header.patient_id = s;
+ _patient_id = s;
return 0;
}
int set_recording_id( const string& s)
{
- header.recording_id = s;
+ _recording_id = s;
return 0;
}
int set_episode( const string& s) // assigning to _episode or _session directly won't have a lasting effect; think again.
{
- header._episode = s;
+ _episode = s;
return 0;
}
int set_session( const string& s)
{
- header._session = s;
+ _session = s;
return 0;
}
int set_comment( const string& s)
{
- header.comment = s;
+ _comment = s;
return 0;
}
@@ -267,19 +267,6 @@ class CTSVFile
sigproc::TWinType af_dampen_window_type; // master copy
- // header
- struct SHeader {
- string patient_id,
- recording_id,
- recording_date,
- recording_time,
- comment;
-
- string _episode,
- _session;
- };
- SHeader header;
-
map<string,string>
metadata;
@@ -373,6 +360,16 @@ class CTSVFile
static string explain_status( int);
private:
+ // header... why is it private?
+ string _patient_id,
+ _recording_id,
+ _recording_date,
+ _recording_time,
+ _comment;
+
+ string _episode,
+ _session;
+
TSubtype _subtype;
size_t _samplerate;
@@ -382,6 +379,7 @@ class CTSVFile
int _fd;
int _parse_header();
+ int _read_data();
};
--
Sleep experiment manager
More information about the debian-med-commit
mailing list