The following commit has been merged in the master branch:
commit 9c29ce116297dfd1c3df27e380c76e99065dacae
Author: Andrei Zavada <[email protected]>
Date:   Mon Apr 29 01:30:13 2013 +0300

    libsigfile/channel overhaul

diff --git a/src/libsigfile/channel.cc b/src/libsigfile/channel.cc
index bad547c..c7c8e69 100644
--- a/src/libsigfile/channel.cc
+++ b/src/libsigfile/channel.cc
@@ -10,79 +10,115 @@
  */
 
 
+#include <map>
+#include <vector>
 #include "channel.hh"
 
 using namespace std;
+using sigfile::SChannel;
 
+const char* sigfile::edf_annotations_label =
+       "EDF Annotations";
 
-const char* 
sigfile::SChannel::system1020_channels[sigfile::SChannel::n_channels] = {  // 
counted 'em all!
-       "Nz",
-       "Fp1", "Fpz", "Fp2",
-       "AF7", "AF3", "AFz", "AF4", "AF8",
-       "F9",  "F7", "F5", "F3", "F1", "Fz", "F2", "F4", "F6", "F8", "F10",
-       "FT9", "FT7", "FC5", "FC3", "FC1", "FCz", "FC2", "FC4", "FC6", "FCT8", 
"FT10",
-       "A1", "T9", "T7", "C5", "C3", "C1", "Cz", "C2", "C4", "C6", "T8", 
"T10", "A2",
-       "TP9", "TP7", "CP5", "CP3", "CP1", "CPz", "CP2", "CP4", "CP6", "TP8", 
"TP10",
-       "P9", "P7", "P5", "P3", "P1", "Pz", "P2", "P4", "P6", "P8", "P10",
-       "PO7", "PO3", "POz", "PO4", "PO8",
-       "O1", "Oz", "O2",
-       "Iz",
-       // plus a few channels of other signal types
-       "Left", "Right",
-       "Chin",
+
+namespace {
+
+const map<SChannel::TType, vector<const char*>> _CT_ = {
+       {SChannel::TType::eeg,
+        {"(custom)",     // counted 'em all!
+         "Nz",
+         "Fp1", "Fpz", "Fp2",
+         "AF7", "AF3", "AFz", "AF4", "AF8",
+         "F9",  "F7", "F5", "F3", "F1", "Fz", "F2", "F4", "F6", "F8", "F10",
+         "FT9", "FT7", "FC5", "FC3", "FC1", "FCz", "FC2", "FC4", "FC6", 
"FCT8", "FT10",
+         "A1", "T9", "T7", "C5", "C3", "C1", "Cz", "C2", "C4", "C6", "T8", 
"T10", "A2",
+         "TP9", "TP7", "CP5", "CP3", "CP1", "CPz", "CP2", "CP4", "CP6", "TP8", 
"TP10",
+         "P9", "P7", "P5", "P3", "P1", "Pz", "P2", "P4", "P6", "P8", "P10",
+         "PO7", "PO3", "POz", "PO4", "PO8",
+         "O1", "Oz", "O2",
+         "Iz",}
+       },
+       {SChannel::TType::eog,
+        {"(invalid)",
+         "Left", "Right",}
+       },
+       {SChannel::TType::emg,
+        {"(invalid)",
+         "Chin",}
+       },
 };
 
+const map<SChannel::TType, const char*> _ST_ = {
+       {SChannel::TType::embedded_annotation, sigfile::edf_annotations_label},
+       {SChannel::TType::eeg, "EEG"},
+       {SChannel::TType::eog, "EOG"},
+       {SChannel::TType::emg, "EMG"},
+       {SChannel::TType::ecg, "ECG"},
+       {SChannel::TType::erg, "ERG"},
+       {SChannel::TType::nc , "NC" },
+       {SChannel::TType::meg, "MEG"},
+       {SChannel::TType::mcg, "MCG"},
+       {SChannel::TType::ep , "EP" },
+       {SChannel::TType::temp, "Temp"},
+       {SChannel::TType::resp, "Resp"},
+       {SChannel::TType::sao2, "SaO2"},
+       {SChannel::TType::light, "Light"},
+       {SChannel::TType::sound, "Sound"},
+       {SChannel::TType::event, "Event"},
+       {SChannel::TType::freq, "Freq"},
+       {SChannel::TType::other, "(other)"},
+};
 
+} // anonymous namespace
 
 
-const char* 
sigfile::SChannel::kemp_signal_types[sigfile::SChannel::n_kemp_signal_types] = {
-       "EDF Annotations",
-       "EEG", "EOG", "EMG", "ECG", "ERG",
-       "NC",  "MEG", "MCG", "EP",
-       "Temp", "Resp", "SaO2",
-       "Light", "Sound", "Event", "Freq",
-       "(unknown)"
-};
+const char*
+SChannel::
+type_s( SChannel::TType t)
+{
+       return _ST_.at(t);
+}
 
 
-sigfile::SChannel::TType
-sigfile::SChannel::
-signal_type_of_channel( const string& signal)
+template <SChannel::TType t>
+const char*
+SChannel::
+channel_s( int idx)
 {
-       size_t h = 0;
-       for ( ; h <= last_eeg_no; ++h )
-               if ( signal == system1020_channels[h] )
-                       return TType::eeg;
-       for ( ; h <= last_eog_no; ++h )
-               if ( signal == system1020_channels[h] )
-                       return TType::eog;
-       for ( ; h <= last_emg_no; ++h )
-               if ( signal == system1020_channels[h] )
-                       return TType::emg;
-       return TType::other;
+       return _CT_.at(t)[idx];
 }
 
+namespace sigfile {
+template <>
+const char*
+SChannel::
+channel_s<SChannel::TType::invalid>(int)
+{
+       return "(invalid)";
+}
+}
+
+template const char* SChannel::channel_s<SChannel::TType::eeg>( int);
+template const char* SChannel::channel_s<SChannel::TType::eog>( int);
+template const char* SChannel::channel_s<SChannel::TType::emg>( int);
+template const char* SChannel::channel_s<SChannel::TType::ecg>( int);
+template const char* SChannel::channel_s<SChannel::TType::erg>( int);
+
+
 
-bool
-__attribute__ ((pure))
-sigfile::
-SChannel::operator<( const SChannel& rv) const
+tuple<SChannel::TType, int>
+figure_type_and_name( const string& h)
 {
-       size_t ai = 0, bi = 0;
-       while ( ai < n_channels && strcmp(    c_str(), system1020_channels[ai]) 
)
-               ++ai;
-       while ( bi < n_channels && strcmp( rv.c_str(), system1020_channels[bi]) 
)
-               ++bi;
-       if ( ai < n_channels && bi < n_channels ) // both are vlaid 10-20 ones: 
compare by index
-               return (ai < bi);
-       else if ( ai < n_channels )  // whichever is good, wins
-               return false;
-       else if ( bi < n_channels )
-               return true;
-       else
-               return strcmp( c_str(), rv.c_str()) < 0;
+       for ( auto& T : _CT_ )
+               for ( size_t i = 0; i < T.second.size(); ++i )
+                       if ( 0 == strcasecmp( h.c_str(), T.second[i]) )
+                               return make_tuple(T.first, (int)i);
+       return make_tuple(SChannel::TType::invalid, -1);
 }
 
+
+
+
 // Local Variables:
 // Mode: c++
 // indent-tabs-mode: 8
diff --git a/src/libsigfile/channel.hh b/src/libsigfile/channel.hh
index 41ffc08..9883cc4 100644
--- a/src/libsigfile/channel.hh
+++ b/src/libsigfile/channel.hh
@@ -4,7 +4,7 @@
  *          Author:  Andrei Zavada <[email protected]>
  * Initial version:  2011-11-10
  *
- *         Purpose:  a string-based class representing a biosig channel
+ *         Purpose:  representation of a biosig channel
  *
  *         License:  GPL
  */
@@ -13,7 +13,7 @@
 #define _SIGFILE_CHANNEL_H
 
 #include <cstring>
-#include <array>
+#include <tuple>
 #include <string>
 
 #if HAVE_CONFIG_H && !defined(VERSION)
@@ -25,62 +25,158 @@ using namespace std;
 
 namespace sigfile {
 
-struct SChannel
-  : public string {
-       template <typename T>
-       SChannel (const T& h)
-             : string (h)
-               {}
-       SChannel ()
-               {}
 
-       bool follows_system1020() const
-               {
-                       return channel_follows_system1020( c_str());
-               }
-       bool operator<( const SChannel& rv) const;
+// we want scoped enums with basic arith support, so:
+namespace EEG {
+enum E : int {
+       invalid = -1,
+       custom = 0,
+       first,
+
+       Nz = first,
+       Fp1, Fpz, Fp2,
+       AF7, AF3, AFz, AF4, AF8,
+       F9,  F7, F5, F3, F1, Fz, F2, F4, F6, F8, F10,
+       FT9, FT7, FC5, FC3, FC1, FCz, FC2, FC4, FC6, FCT8, FT10,
+       A1, T9, T7, C5, C3, C1, Cz, C2, C4, C6, T8, T10, A2,
+       TP9, TP7, CP5, CP3, CP1, CPz, CP2, CP4, CP6, TP8, TP10,
+       P9, P7, P5, P3, P1, Pz, P2, P4, P6, P8, P10,
+       PO7, PO3, POz, PO4, PO8,
+       O1, Oz, O2,
+       Iz,
+
+       last = Iz,
+       total
+};
+}
+
+namespace EOG {
+enum E : int {
+       invalid = -1,
+       custom = 0,
+       first,
+       left = first, right,
+       last = right,
+       total
+};
+}
+
+namespace EMG {
+enum E : int {
+       invalid = -1,
+       custom = 0,
+       first,
+       chin = first,
+       last = chin,
+       total
+};
+}
+
+namespace ECG {
+enum E : int {
+       invalid = -1,
+       custom = 0,
+       total
+};
+}
+
+namespace ERG {
+enum E : int {
+       invalid = -1,
+       custom = 0,
+       total
+};
+}
+// moar types ...
+
+
+extern const char* edf_annotations_label;
+
 
-      // static members
-       enum TType : int {
+struct SChannel {
+
+       enum class TType {
+               invalid,
                embedded_annotation,
                eeg, eog, emg, ecg, erg,
                nc, meg, mcg, ep, temp, resp, sao2, light, sound, event, freq,
                other
        };
-       static const size_t n_channels = 78;
-       static const size_t last_eeg_no = 74;
-       static const size_t last_eog_no = 76;
-       static const size_t last_emg_no = 77;
-       static const size_t n_kemp_signal_types = 18;
-       static const char* system1020_channels[n_channels];
-       static const char* kemp_signal_types[n_kemp_signal_types];
-       static bool channel_follows_system1020( const char* channel)
+
+       static const char* type_s( TType t);
+
+       template <TType T>
+       static const char* channel_s( int);
+
+       static tuple<TType, int> figure_type_and_name( const string&);
+
+       static bool is_fftable( TType type)
                {
-                       for ( auto &I : system1020_channels )
-                               if ( strcmp( channel, I) == 0 )
-                                       return true;
-                       return false;
+                       return type == TType::eeg;
+               }
+
+      // ctor
+       SChannel (const string& h)
+               {
+                       tie(_type, _idx) = figure_type_and_name(h);
+                       if ( _type == TType::invalid ) {
+                               _type = TType::other;
+                               _idx = 0; // custom
+                               _custom_name = h;
+                       }
                }
-       static TType figure_signal_type( const char* s)
+
+       template <TType T>
+       SChannel (int idx_)
+             : _type (T),
+               _idx (idx_)
+               {}
+
+       TType type() const
+               { return _type; }
+
+       const char* name() const
                {
-                       for ( int i = 0; i < (int)n_kemp_signal_types; ++i )
-                               if ( strcasecmp( kemp_signal_types[i], s) == 0 )
-                                       return (TType)i;
-                       return TType::other;
+                       switch ( _type ) {
+                       case TType::eeg: return channel_s<TType::eeg>( _idx);
+                       case TType::eog: return channel_s<TType::eog>( _idx);
+                       case TType::emg: return channel_s<TType::emg>( _idx);
+                       case TType::ecg: return channel_s<TType::ecg>( _idx);
+                       case TType::erg: return channel_s<TType::erg>( _idx);
+                       default: return _custom_name.c_str();
+                       }
                }
-       static TType signal_type_of_channel( const string&);
-       static bool signal_type_is_fftable( const string& signal_type)
+
+       bool is_fftable()
                {
-                       return signal_type == "EEG";
+                       return is_fftable( _type);
+               }
+    private:
+       string  _custom_name;
+       TType   _type;
+       int     _idx;
+
+    public:
+       // compares by channel actual locations, antero-posteriorly
+       bool operator<( const SChannel& rv) const
+               {
+                       if ( _type == rv._type ) {
+                               if ( _idx > 0 && rv._idx > 0 )
+                                       return _idx < rv._idx;
+                               else if ( _idx > 0 )
+                                       return true;
+                               else
+                                       return _custom_name < rv._custom_name;
+                       } else
+                               return _type < rv._type;
                }
-       static bool signal_type_is_fftable( TType signal_type)
+       bool operator==( const SChannel& rv) const
                {
-                       return signal_type == TType::eeg;
+                       return _type == rv._type && _idx == rv._idx;
                }
-       static bool channel_is_fftable( const string& H)
+       bool operator==( const char* rv) const
                {
-                       return signal_type_is_fftable(
-                               signal_type_of_channel(H));
+                       return 0 == strcasecmp( name(), rv);
                }
 };
 

-- 
Sleep experiment manager

_______________________________________________
debian-med-commit mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/debian-med-commit

Reply via email to