mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-05 02:30:44 +00:00
760 lines
20 KiB
C++
760 lines
20 KiB
C++
/*
|
|
SleepLib Session Implementation
|
|
This stuff contains the base calculation smarts
|
|
Copyright (c)2011 Mark Watkins <jedimark@users.sourceforge.net>
|
|
License: GPL
|
|
*/
|
|
|
|
#include "session.h"
|
|
#include "math.h"
|
|
#include <QDir>
|
|
#include <QDebug>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
|
|
using namespace std;
|
|
|
|
Session::Session(Machine * m,SessionID session)
|
|
{
|
|
if (!session) {
|
|
session=m->CreateSessionID();
|
|
}
|
|
s_machine=m;
|
|
s_session=session;
|
|
s_changed=false;
|
|
s_events_loaded=false;
|
|
s_waves_loaded=false;
|
|
_first_session=true;
|
|
|
|
s_first=s_last=0;
|
|
s_wavefile="";
|
|
s_eventfile="";
|
|
}
|
|
Session::~Session()
|
|
{
|
|
TrashEvents();
|
|
TrashWaveforms();
|
|
}
|
|
double Session::min_event_field(MachineCode mc,int field)
|
|
{
|
|
if (events.find(mc)==events.end()) return 0;
|
|
|
|
bool first=true;
|
|
double min=0;
|
|
vector<Event *>::iterator i;
|
|
|
|
for (i=events[mc].begin(); i!=events[mc].end(); i++) {
|
|
if (field>=(*i)->e_fields) {
|
|
qWarning() << "Invalid Event field in Session::min_event_field";
|
|
return 0;
|
|
}
|
|
if (first) {
|
|
first=false;
|
|
min=(*(*i))[field];
|
|
} else {
|
|
if (min>(*(*i))[field]) min=(*(*i))[field];
|
|
}
|
|
}
|
|
return min;
|
|
}
|
|
double Session::max_event_field(MachineCode mc,int field)
|
|
{
|
|
if (events.find(mc)==events.end()) return 0;
|
|
|
|
bool first=true;
|
|
double max=0;
|
|
vector<Event *>::iterator i;
|
|
for (i=events[mc].begin(); i!=events[mc].end(); i++) {
|
|
if (field>=(*i)->e_fields) {
|
|
qWarning() << "Invalid Event field in Session::max_event_field";
|
|
return 0;
|
|
}
|
|
if (first) {
|
|
first=false;
|
|
max=(*(*i))[field];
|
|
} else {
|
|
if (max<(*(*i))[field]) max=(*(*i))[field];
|
|
}
|
|
}
|
|
return max;
|
|
}
|
|
|
|
double Session::sum_event_field(MachineCode mc,int field)
|
|
{
|
|
if (events.find(mc)==events.end()) return 0;
|
|
|
|
double sum=0;
|
|
vector<Event *>::iterator i;
|
|
|
|
for (i=events[mc].begin(); i!=events[mc].end(); i++) {
|
|
if (field>=(*i)->e_fields) {
|
|
qWarning() << "Invalid Event field in Session::sum_event_field";
|
|
return 0;
|
|
}
|
|
sum+=(*(*i))[field];
|
|
}
|
|
return sum;
|
|
}
|
|
double Session::avg_event_field(MachineCode mc,int field)
|
|
{
|
|
if (events.find(mc)==events.end()) return 0;
|
|
|
|
double sum=0;
|
|
int cnt=0;
|
|
vector<Event *>::iterator i;
|
|
|
|
for (i=events[mc].begin(); i!=events[mc].end(); i++) {
|
|
if (field>=(*i)->e_fields) {
|
|
qWarning() << "Invalid Event field in Session::avg_event_field";
|
|
return 0;
|
|
}
|
|
sum+=(*(*i))[field];
|
|
cnt++;
|
|
}
|
|
|
|
return sum/cnt;
|
|
}
|
|
|
|
bool sortfunction (double i,double j) { return (i<j); }
|
|
|
|
double Session::percentile(MachineCode mc,int field,double percent)
|
|
{
|
|
if (events.find(mc)==events.end()) return 0;
|
|
|
|
vector<EventDataType> array;
|
|
|
|
vector<Event *>::iterator e;
|
|
|
|
for (e=events[mc].begin(); e!=events[mc].end(); e++) {
|
|
Event & ev = *(*e);
|
|
array.push_back(ev[field]);
|
|
}
|
|
std::sort(array.begin(),array.end(),sortfunction);
|
|
int size=array.size();
|
|
double i=size*percent;
|
|
double t;
|
|
double q=modf(i,&t);
|
|
int j=t;
|
|
if (j>=size-1) return array[j];
|
|
|
|
double a=array[j-1];
|
|
double b=array[j];
|
|
if (a==b) return a;
|
|
//double c=(b-a);
|
|
//double d=c*q;
|
|
return array[j]+q;
|
|
}
|
|
|
|
double Session::weighted_avg_event_field(MachineCode mc,int field)
|
|
{
|
|
if (events.find(mc)==events.end()) return 0;
|
|
|
|
int cnt=0;
|
|
|
|
bool first=true;
|
|
qint64 last;
|
|
int lastval=0,val;
|
|
const int max_slots=2600;
|
|
qint64 vtime[max_slots]={0};
|
|
|
|
|
|
double mult;
|
|
if ((mc==CPAP_Pressure) || (mc==CPAP_EAP) || (mc==CPAP_IAP) | (mc==CPAP_PS)) {
|
|
mult=10.0;
|
|
|
|
} else mult=10.0;
|
|
|
|
vector<Event *>::iterator i;
|
|
|
|
for (i=events[mc].begin(); i!=events[mc].end(); i++) {
|
|
Event & e =(*(*i));
|
|
val=e[field]*mult;
|
|
if (field>=(*i)->e_fields) {
|
|
qWarning() << "Invalid Event field in Session::weighted_avg_event_field";
|
|
return 0;
|
|
}
|
|
if (first) {
|
|
first=false;
|
|
} else {
|
|
int d=(e.e_time-last)/1000L;
|
|
if (lastval>max_slots) {
|
|
qWarning("max_slots to small in Session::weighted_avg_event_fied()");
|
|
return 0;
|
|
}
|
|
|
|
vtime[lastval]+=d;
|
|
|
|
}
|
|
cnt++;
|
|
last=e.e_time;
|
|
lastval=val;
|
|
}
|
|
|
|
qint64 total=0;
|
|
for (int i=0; i<max_slots; i++) total+=vtime[i];
|
|
//double hours=total.GetSeconds().GetLo()/3600.0;
|
|
|
|
qint64 s0=0,s1=0,s2=0;
|
|
if (total==0) return 0;
|
|
for (int i=0; i<max_slots; i++) {
|
|
if (vtime[i] > 0) {
|
|
s0=vtime[i];
|
|
s1+=i*s0;
|
|
s2+=s0;
|
|
}
|
|
}
|
|
double j=double(s1)/double(total);
|
|
return j/mult;
|
|
}
|
|
|
|
void Session::AddEvent(Event * e)
|
|
{
|
|
events[e->code()].push_back(e);
|
|
if (s_first) {
|
|
if (e->time()<s_first) s_first=e->time();
|
|
if (e->time()>s_last) s_last=e->time();
|
|
} else {
|
|
s_first=s_last=e->time();
|
|
//_first_session=false;
|
|
}
|
|
}
|
|
void Session::AddWaveform(Waveform *w)
|
|
{
|
|
waveforms[w->code()].push_back(w);
|
|
if (s_last) {
|
|
if (w->start()<s_first) s_first=w->start();
|
|
if (w->end()>s_last) s_last=w->end();
|
|
} else {
|
|
s_first=w->start();
|
|
s_last=w->end();
|
|
}
|
|
|
|
// Could parse the flow data for Breaths per minute info here..
|
|
}
|
|
void Session::TrashEvents()
|
|
// Trash this sessions Events and release memory.
|
|
{
|
|
map<MachineCode,vector<Event *> >::iterator i;
|
|
vector<Event *>:: iterator j;
|
|
for (i=events.begin(); i!=events.end(); i++) {
|
|
for (j=i->second.begin(); j!=i->second.end(); j++) {
|
|
delete *j;
|
|
}
|
|
}
|
|
events.clear();
|
|
}
|
|
void Session::TrashWaveforms()
|
|
// Trash this sessions Waveforms and release memory.
|
|
{
|
|
map<MachineCode,vector<Waveform *> >::iterator i;
|
|
vector<Waveform *>:: iterator j;
|
|
for (i=waveforms.begin(); i!=waveforms.end(); i++) {
|
|
for (j=i->second.begin(); j!=i->second.end(); j++) {
|
|
delete *j;
|
|
}
|
|
}
|
|
waveforms.clear();
|
|
}
|
|
|
|
|
|
//const int max_pack_size=128;
|
|
bool Session::OpenEvents() {
|
|
if(s_events_loaded)
|
|
return true;
|
|
bool b;
|
|
b=LoadEvents(s_eventfile);
|
|
if (!b) {
|
|
qWarning() << "Error Unkpacking Events" << s_eventfile;
|
|
}
|
|
|
|
s_events_loaded=b;
|
|
return b;
|
|
};
|
|
bool Session::OpenWaveforms() {
|
|
if (s_waves_loaded)
|
|
return true;
|
|
bool b;
|
|
b=LoadWaveforms(s_wavefile);
|
|
if (!b) {
|
|
qWarning() << "Error Unkpacking Wavefile" << s_wavefile;
|
|
}
|
|
s_waves_loaded=b;
|
|
return b;
|
|
};
|
|
|
|
bool Session::Store(QString path)
|
|
// Storing Session Data in our format
|
|
// {DataDir}/{MachineID}/{SessionID}.{ext}
|
|
{
|
|
QDir dir(path);
|
|
if (!dir.exists(path))
|
|
dir.mkpath(path);
|
|
|
|
QString base;
|
|
base.sprintf("%08lx",s_session);
|
|
base=path+"/"+base;
|
|
//qDebug() << "Storing Session: " << base;
|
|
bool a;
|
|
a=StoreSummary(base+".000"); // if actually has events
|
|
//qDebug() << " Summary done";
|
|
if (events.size()>0) StoreEvents(base+".001");
|
|
//qDebug() << " Events done";
|
|
if (waveforms.size()>0) StoreWaveforms(base+".002");
|
|
//qDebug() << " Waveform done";
|
|
if (a) {
|
|
s_changed=false;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
const quint32 magic=0xC73216AB;
|
|
|
|
bool IsPlatformLittleEndian()
|
|
{
|
|
quint32 j=1;
|
|
*((char*)&j) = 0;
|
|
return j!=1;
|
|
}
|
|
|
|
bool Session::StoreSummary(QString filename)
|
|
{
|
|
QFile file(filename);
|
|
file.open(QIODevice::WriteOnly);
|
|
|
|
QDataStream out(&file);
|
|
out.setVersion(QDataStream::Qt_4_6);
|
|
|
|
out << (quint32)magic;
|
|
out << (quint32)s_machine->id();
|
|
out << (quint32)s_session;
|
|
out << (quint16)0 << (quint16)0;
|
|
|
|
quint32 starttime=s_first/1000L;
|
|
quint32 duration=(s_last-s_first)/1000L;
|
|
|
|
out << (quint32)starttime; // Session Start Time
|
|
out << (quint32)duration; // Duration of sesion in seconds.
|
|
out << (quint16)summary.size();
|
|
|
|
map<MachineCode,MCDataType> mctype;
|
|
|
|
// First output the Machine Code and type for each summary record
|
|
map<MachineCode,QVariant>::iterator i;
|
|
for (i=summary.begin(); i!=summary.end(); i++) {
|
|
MachineCode mc=i->first;
|
|
|
|
QVariant::Type type=i->second.type(); // Urkk.. this is a mess.
|
|
if (type==QVariant::Bool) {
|
|
mctype[mc]=MC_bool;
|
|
} else if (type==QVariant::Int) {
|
|
mctype[mc]=MC_int;
|
|
} else if (type==QVariant::LongLong) {
|
|
mctype[mc]=MC_long;
|
|
} else if (type==QVariant::Double) {
|
|
mctype[mc]=MC_double;
|
|
} else if (type==QVariant::String) {
|
|
mctype[mc]=MC_string;
|
|
} else if (type==QVariant::DateTime) {
|
|
mctype[mc]=MC_datetime;
|
|
} else {
|
|
QString t=i->second.typeToName(type);
|
|
qWarning() << "Error in Session->StoreSummary: Can't pack variant type " << t;
|
|
return false;
|
|
//exit(1);
|
|
}
|
|
out << (qint16)mc;
|
|
out << (qint8)mctype[mc];
|
|
}
|
|
// Then dump out the actual data, according to format.
|
|
for (i=summary.begin(); i!=summary.end(); i++) {
|
|
MachineCode mc=i->first;
|
|
if (mctype[mc]==MC_bool) {
|
|
out << i->second.toBool();
|
|
} else if (mctype[mc]==MC_int) {
|
|
out << (qint32)i->second.toInt();
|
|
} else if (mctype[mc]==MC_long) {
|
|
out << (qint64)i->second.toLongLong();
|
|
} else if (mctype[mc]==MC_double) {
|
|
out << (double)i->second.toDouble();
|
|
} else if (mctype[mc]==MC_string) {
|
|
out << i->second.toString();
|
|
} else if (mctype[mc]==MC_datetime) {
|
|
out << i->second.toDateTime();
|
|
}
|
|
}
|
|
file.close();
|
|
return true;
|
|
}
|
|
|
|
bool Session::LoadSummary(QString filename)
|
|
{
|
|
if (filename.isEmpty()) return false;
|
|
//qDebug() << "Loading Summary " << filename;
|
|
|
|
QFile file(filename);
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
qDebug() << "Couldn't open file" << filename;
|
|
return false;
|
|
}
|
|
|
|
QDataStream in(&file);
|
|
in.setVersion(QDataStream::Qt_4_6);
|
|
|
|
quint64 t64;
|
|
quint32 t32;
|
|
quint16 t16;
|
|
quint8 t8;
|
|
|
|
qint16 sumsize;
|
|
map<MachineCode,MCDataType> mctype;
|
|
vector<MachineCode> mcorder;
|
|
in >> t32;
|
|
if (t32!=magic) {
|
|
qDebug() << "Wrong magic number in " << filename;
|
|
return false;
|
|
}
|
|
|
|
in >> t32; // MachineID (dont need this result)
|
|
|
|
in >> t32; // Sessionid;
|
|
s_session=t32;
|
|
|
|
in >> t16; // File Type
|
|
if (t16!=0) {
|
|
qDebug() << "Wrong file type"; //wrong file type
|
|
return false;
|
|
}
|
|
|
|
in >> t16; // File Version
|
|
// dont care yet
|
|
|
|
in >> t32; // Start time
|
|
s_first=qint64(t32)*1000L;
|
|
|
|
in >> t32; // Duration // (16bit==Limited to 18 hours)
|
|
s_last=s_first+qint64(t32)*1000L;
|
|
|
|
in >> sumsize; // Summary size (number of Machine Code lists)
|
|
|
|
for (int i=0; i<sumsize; i++) {
|
|
in >> t16; // Machine Code
|
|
MachineCode mc=(MachineCode)t16;
|
|
in >> t8; // Data Type
|
|
mctype[mc]=(MCDataType)t8;
|
|
mcorder.push_back(mc);
|
|
}
|
|
|
|
for (int i=0; i<sumsize; i++) { // Load each summary entry according to type
|
|
MachineCode mc=mcorder[i];
|
|
if (mctype[mc]==MC_bool) {
|
|
bool b;
|
|
in >> b;
|
|
summary[mc]=b;
|
|
} else if (mctype[mc]==MC_int) {
|
|
in >> t32;
|
|
summary[mc]=(qint32)t32;
|
|
} else if (mctype[mc]==MC_long) {
|
|
in >> t64;
|
|
summary[mc]=(qint64)t64;
|
|
} else if (mctype[mc]==MC_double) {
|
|
double dl;
|
|
in >> dl;
|
|
summary[mc]=(double)dl;
|
|
} else if (mctype[mc]==MC_string) {
|
|
QString s;
|
|
in >> s;
|
|
summary[mc]=s;
|
|
} else if (mctype[mc]==MC_datetime) {
|
|
QDateTime dt;
|
|
in >> dt;
|
|
summary[mc]=dt;
|
|
}
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Session::StoreEvents(QString filename)
|
|
{
|
|
QFile file(filename);
|
|
file.open(QIODevice::WriteOnly);
|
|
|
|
QDataStream out(&file);
|
|
out.setVersion(QDataStream::Qt_4_6);
|
|
|
|
out << (quint32)magic; // Magic Number
|
|
out << (quint32)s_machine->id(); // Machine ID
|
|
out << (quint32)s_session; // This session's ID
|
|
out << (quint16)1; // File type 1 == Event
|
|
out << (quint16)0; // File Version
|
|
|
|
quint32 starttime=s_first/1000L;
|
|
quint32 duration=(s_last-s_first)/1000L;
|
|
|
|
out << starttime;
|
|
out << duration;
|
|
|
|
out << (qint16)events.size(); // Number of event categories
|
|
|
|
|
|
map<MachineCode,vector<Event *> >::iterator i;
|
|
vector<Event *>::iterator j;
|
|
|
|
for (i=events.begin(); i!=events.end(); i++) {
|
|
out << (qint16)i->first; // MachineID
|
|
out << (qint16)i->second.size(); // count of events in this category
|
|
j=i->second.begin();
|
|
out << (qint8)(*j)->fields(); // number of data fields in this event type
|
|
}
|
|
bool first;
|
|
EventDataType tf;
|
|
qint64 last=0,eventtime,delta;
|
|
|
|
for (i=events.begin(); i!=events.end(); i++) {
|
|
first=true;
|
|
for (j=i->second.begin(); j!=i->second.end(); j++) {
|
|
eventtime=(*j)->time();
|
|
if (first) {
|
|
out << (*j)->time();
|
|
first=false;
|
|
} else {
|
|
delta=eventtime-last;
|
|
if (delta>0xffffffff) {
|
|
qDebug("StoreEvent: Delta too big.. needed to use bigger value");
|
|
return false;
|
|
}
|
|
out << (quint32)delta;
|
|
}
|
|
for (int k=0; k<(*j)->fields(); k++) {
|
|
tf=(*(*j))[k];
|
|
out << tf;
|
|
}
|
|
last=eventtime;
|
|
}
|
|
}
|
|
//file.close();
|
|
return true;
|
|
}
|
|
bool Session::LoadEvents(QString filename)
|
|
{
|
|
if (filename.isEmpty()) return false;
|
|
|
|
QFile file(filename);
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
qDebug() << "Couldn't open file" << filename;
|
|
return false;
|
|
}
|
|
QDataStream in(&file);
|
|
in.setVersion(QDataStream::Qt_4_6);
|
|
|
|
quint32 t32;
|
|
quint16 t16;
|
|
quint8 t8;
|
|
//qint16 i16;
|
|
|
|
// qint16 sumsize;
|
|
|
|
in >> t32; // Magic Number
|
|
if (t32!=magic) {
|
|
qWarning() << "Wrong Magic number in " << filename;
|
|
return false;
|
|
}
|
|
in >> t32; // MachineID
|
|
|
|
in >> t32; // Sessionid;
|
|
s_session=t32;
|
|
|
|
in >> t16; // File Type
|
|
if (t16!=1) {
|
|
qDebug() << "Wrong File Type in " << filename;
|
|
return false;
|
|
}
|
|
|
|
in >> t16; // File Version
|
|
// dont give a crap yet..
|
|
|
|
in >> t32; // Start time
|
|
s_first=qint64(t32)*1000L;
|
|
in >> t32; // Duration // (16bit==Limited to 18 hours)
|
|
s_last=s_first+qint64(t32)*1000L;
|
|
|
|
qint16 evsize;
|
|
in >> evsize; // Summary size (number of Machine Code lists)
|
|
|
|
map<MachineCode,qint16> mcsize;
|
|
map<MachineCode,qint16> mcfields;
|
|
vector<MachineCode> mcorder;
|
|
|
|
MachineCode mc;
|
|
for (int i=0; i<evsize; i++) {
|
|
in >> t16; // MachineCode
|
|
mc=(MachineCode)t16;
|
|
mcorder.push_back(mc);
|
|
in >> t16; // Count of this Event
|
|
mcsize[mc]=t16;
|
|
in >> t8; // Type
|
|
mcfields[mc]=t8;
|
|
}
|
|
|
|
for (int i=0; i<evsize; i++) {
|
|
mc=mcorder[i];
|
|
bool first=true;
|
|
qint64 d;
|
|
events[mc].clear();
|
|
for (int e=0; e<mcsize[mc]; e++) {
|
|
if (first) {
|
|
in >> d; // Timestamp
|
|
first=false;
|
|
} else {
|
|
in >> t32; // Time Delta
|
|
d=d+t32;
|
|
}
|
|
EventDataType ED[max_number_event_fields];
|
|
for (int c=0; c<mcfields[mc]; c++) {
|
|
in >> ED[c]; // Data Fields in float format
|
|
}
|
|
Event *ev=new Event(d,mc,ED,mcfields[mc]);
|
|
|
|
AddEvent(ev);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Session::StoreWaveforms(QString filename)
|
|
{
|
|
|
|
QFile file(filename);
|
|
file.open(QIODevice::WriteOnly);
|
|
|
|
QDataStream out(&file);
|
|
out.setVersion(QDataStream::Qt_4_6);
|
|
quint16 t16;
|
|
|
|
out << (quint32)magic; // Magic Number
|
|
out << (quint32)s_machine->id(); // Machine ID
|
|
out << (quint32)s_session; // This session's ID
|
|
out << (quint16)2; // File type 2 == Waveform
|
|
out << (quint16)0; // File Version
|
|
|
|
quint32 starttime=s_first/1000L;
|
|
quint32 duration=(s_last-s_first)/1000L;
|
|
|
|
out << starttime;
|
|
out << duration;
|
|
|
|
out << (qint16)waveforms.size(); // Number of different waveforms
|
|
|
|
map<MachineCode,vector<Waveform *> >::iterator i;
|
|
vector<Waveform *>::iterator j;
|
|
for (i=waveforms.begin(); i!=waveforms.end(); i++) {
|
|
//qDebug() << "Storing Waveform" << zz++ << filename;
|
|
out << (quint16)i->first; // Machine Code
|
|
t16=i->second.size();
|
|
out << t16; // Number of (hopefully non-linear) waveform chunks
|
|
for (j=i->second.begin(); j!=i->second.end(); j++) {
|
|
//qDebug() << "Storing Waveform Chunk" << chnk++;
|
|
|
|
Waveform &w=*(*j);
|
|
// 64bit number..
|
|
out << (qint64)w.start(); // Start time of first waveform chunk
|
|
|
|
//qint32 samples;
|
|
//double seconds;
|
|
|
|
out << (qint32)w.samples(); // Total number of samples
|
|
out << (qint64)w.duration(); // Total number of seconds
|
|
out << (SampleFormat)w.min();
|
|
out << (SampleFormat)w.max();
|
|
out << (qint8)sizeof(SampleFormat); // Bytes per sample
|
|
out << (qint8)0; // signed.. all samples for now are signed 16bit.
|
|
//t8=0; // 0=signed, 1=unsigned, 2=float
|
|
|
|
// followed by sample data.
|
|
//qDebug() << "Writing " << (*j)->samples() << "samples";
|
|
for (int k=0; k<(*j)->samples(); k++) out << w[k];
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Session::LoadWaveforms(QString filename)
|
|
{
|
|
if (filename.isEmpty()) return false;
|
|
QFile file(filename);
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
qDebug() << "Couldn't open file" << filename;
|
|
return false;
|
|
}
|
|
QDataStream in(&file);
|
|
in.setVersion(QDataStream::Qt_4_6);
|
|
|
|
quint32 t32;
|
|
quint16 t16;
|
|
quint8 t8;
|
|
|
|
in >>t32; // Magic Number
|
|
if (t32!=magic) {
|
|
qDebug() << "Wrong magic in " << filename;
|
|
return false;
|
|
}
|
|
|
|
in >> t32; // MachineID
|
|
|
|
in >> t32; // Sessionid;
|
|
s_session=t32;
|
|
|
|
in >> t16; // File Type
|
|
if (t16!=2) {
|
|
qDebug() << "Wrong File Type in " << filename;
|
|
return false;
|
|
}
|
|
|
|
in >> t16; // File Version
|
|
// dont give a crap yet..
|
|
|
|
in >> t32; // Start time
|
|
s_first=qint64(t32)*1000;
|
|
|
|
in >> t32; // Duration // (16bit==Limited to 18 hours)
|
|
s_last=s_first+qint64(t32)*1000;
|
|
|
|
quint16 wvsize;
|
|
in >> wvsize; // Number of waveforms
|
|
|
|
MachineCode mc;
|
|
qint64 date;
|
|
qint64 seconds;
|
|
qint32 samples;
|
|
int chunks;
|
|
SampleFormat min,max;
|
|
for (int i=0; i<wvsize; i++) {
|
|
in >> t16; // Machine Code
|
|
mc=(MachineCode)t16;
|
|
in >> t16; // Number of waveform Chunks
|
|
chunks=t16;
|
|
|
|
for (int i=0; i<chunks; i++) {
|
|
in >> date; // Waveform DateTime
|
|
in >> samples; // Number of samples
|
|
in >> seconds; // Duration in seconds
|
|
in >> min; // Min value
|
|
in >> max; // Min value
|
|
in >> t8; // sample size in bytes
|
|
in >> t8; // Number of samples (?? what did I mean by this)
|
|
|
|
SampleFormat *data=new SampleFormat [samples];
|
|
|
|
|
|
for (int k=0; k<samples; k++) {
|
|
in >> data[k]; // Individual Samples;
|
|
}
|
|
Waveform *w=new Waveform(date,mc,data,samples,seconds,min,max);
|
|
AddWaveform(w);
|
|
}
|
|
}
|
|
return true;
|
|
}
|