diff --git a/edfOps.go b/edfOps.go index f71f43f..c04079f 100644 --- a/edfOps.go +++ b/edfOps.go @@ -99,7 +99,8 @@ func (edf Edf) GetDataRecords() int { // Appends data from one EDF to another. Returns a new EDF object and an error, // which is `nil` if everything runs ok. This function requires the -// EDF files to have the same sampling rate and the same number of channels. +// EDF files to have the same sampling rate, the same number of channels, +// and the same duration for each data record. // // This function is in experimental state and must be used carefully! func Append(x, y Edf) (*Edf, error) { @@ -116,7 +117,7 @@ func Append(x, y Edf) (*Edf, error) { z := NewEdf(x.Header, x.Records) // Updating header - z.Header["datarecords"] = EnforceSize(strconv.Itoa(x.GetDataRecords() + y.GetDataRecords()), 8) + z.Header["datarecords"] = EnforceSize(strconv.Itoa(x.GetDataRecords() + y.GetDataRecords()), GetSpecsLength()["datarecords"]) // Appending data records for i := 0; i < len(x.Records); i++ { diff --git a/edfReader.go b/edfReader.go index 111d06c..987abd1 100644 --- a/edfReader.go +++ b/edfReader.go @@ -1,8 +1,10 @@ package edf -import "os" -import "bytes" -import "encoding/binary" +import ( + "os" + "bytes" + "encoding/binary" +) /* --- MAIN FUNCTIONS --- */ @@ -10,17 +12,17 @@ import "encoding/binary" // The header will be a map relating the properties to a string with the raw data // The records will be a matrix storing the raw bytes in the file func ReadFile(input string) Edf { - inlet, err := os.Open(input) + inlet, err := os.Open(input) - if err != nil { - panic(err) - } + if err != nil { + panic(err) + } - defer inlet.Close() - header := ReadHeader(inlet) - records := ReadRecords(inlet, header) + defer inlet.Close() + header := ReadHeader(inlet) + records := ReadRecords(inlet, header) - return NewEdf(header, records) + return NewEdf(header, records) } // Reads the header of an EDF file. Requires the opened EDF file, the list of @@ -28,100 +30,107 @@ func ReadFile(input string) Edf { // the EDF standard. The specs can be accessed though the GetSpecsList // function, and their lenghts through the GetSpecsLength one. func ReadHeader(inlet *os.File) map[string]string { - specsList := GetSpecsList() - specsLength := GetSpecsLength() - header := make(map[string]string) - index := 0 - - // Reading header's header - for index < len(specsList) { - spec := specsList[index] - - if spec == "label" { - break - } else { - data := make([]byte, specsLength[spec]) - n, _ := inlet.Read(data) - header[spec] = string(data[:n]) - } - - index++ - } - - // Reading header's records - numberSignals := getNumberSignals(header) - for index = index; index < len(specsList); index++ { - spec := specsList[index] - data := make([]byte, specsLength[spec] * numberSignals) - n, _ := inlet.Read(data) - header[spec] = string(data[:n]) - } - - return header + specsList := GetSpecsList() + specsLength := GetSpecsLength() + header := make(map[string]string) + index := 0 + + // Reading header's header + for index < len(specsList) { + spec := specsList[index] + + if spec == "label" { + break + } else { + data := make([]byte, specsLength[spec]) + n, _ := inlet.Read(data) + header[spec] = string(data[:n]) + } + + index++ + } + + // Reading header's records + numberSignals := getNumberSignals(header) + for index = index; index < len(specsList); index++ { + spec := specsList[index] + data := make([]byte, specsLength[spec] * numberSignals) + n, _ := inlet.Read(data) + header[spec] = string(data[:n]) + } + + return header } // Reads the data records from the EDF file. Its parameters are the pointer to // file; and header information, as returned by the ReadHeader function. func ReadRecords(inlet *os.File, header map[string]string) [][]int16 { - numberSignals := getNumberSignals(header) - numberSamples := getNumberSamples(header) - records := make([][]int16, numberSignals) - sampling := make([]int, numberSignals) - duration := str2int(header["duration"]) - dataRecords := str2int(header["datarecords"]) - - // setup records - for i := 0; i < numberSignals; i++ { - sampling[i] = duration * numberSamples[i] - records[i] = make([]int16, sampling[i]) - } - - // translate data - for d := 0; d < dataRecords; d++ { - for i := 0; i < numberSignals; i++ { - data := make([]byte, 2*sampling[i]) - inlet.Read(data) - records[i] = appendInt16Arrays(records[i], translate(data)) - } - } - - return records + numberSignals := getNumberSignals(header) + numberSamples := getNumberSamples(header) + records := make([][]int16, numberSignals) + sampling := make([]int, numberSignals) + duration := str2int(header["duration"]) + dataRecords := str2int(header["datarecords"]) + + // setup records + for i := 0; i < numberSignals; i++ { + sampling[i] = duration * numberSamples[i] + records[i] = make([]int16, sampling[i]) + } + + // Reading records + dataRecordsSize := 2 * dataRecords * Sigma(sampling) + data := make([]byte, dataRecordsSize) + inlet.Read(data) + + // translate data + i := 0 + for d := 0; d < dataRecords; d++ { + for s := 0; s < numberSignals; s++ { + step := 2*sampling[s] + piece := data[i:i+step] + records[s] = appendInt16Arrays(records[s], translate(piece)) + i += step + } + } + + return records } /* --- AUXILIAR FUNCTIONS --- */ func translate(inlet []byte) []int16 { - var data int16 - limit := len(inlet)/2 - outlet := make([]int16, limit) - buffer := bytes.NewReader(inlet) - - for i := 0; i < limit; i++ { - // oops := binary.Read(buffer, binary.BigEndian, &data) - oops := binary.Read(buffer, binary.LittleEndian, &data) - if oops == nil { - outlet[i] = data - } else { - panic(oops) - } - } - - return outlet + var data int16 + limit := len(inlet)/2 + outlet := make([]int16, limit) + buffer := bytes.NewReader(inlet) + + for i := 0; i < limit; i++ { + // oops := binary.Read(buffer, binary.BigEndian, &data) + oops := binary.Read(buffer, binary.LittleEndian, &data) + if oops == nil { + outlet[i] = data + } else { + panic(oops) + } + } + + return outlet } func getNumberSignals(header map[string]string) int { - raw := header["numbersignals"] - return str2int(raw) + raw := header["numbersignals"] + return str2int(raw) } func getNumberSamples(header map[string]string) []int { - numberSignals := getNumberSignals(header) - numberSamples := make([]int, numberSignals) - samples := separateString(header["samplesrecord"], numberSignals) + numberSignals := getNumberSignals(header) + numberSamples := make([]int, numberSignals) + samples := separateString(header["samplesrecord"], numberSignals) - for i := 0; i < numberSignals; i++ { - numberSamples[i] = str2int(samples[i]) - } + for i := 0; i < numberSignals; i++ { + numberSamples[i] = str2int(samples[i]) + } - return numberSamples + return numberSamples } diff --git a/useful.go b/useful.go index c5eac7d..883ce57 100644 --- a/useful.go +++ b/useful.go @@ -148,3 +148,12 @@ func EnforceSize(field string, limit int) string { return field } + +// Sums all values of an int array +func Sigma(a []int) int { + r := 0 + for i := 0; i < len(a); i++ { + r += a[i] + } + return r +} \ No newline at end of file