UNPKG

node-edf

Version:

NodeJS library for reading and writing EDF files.

59 lines (53 loc) 2.67 kB
import * as fs from "fs"; import moment from "moment"; import {ChannelInfo, Chunk, EDFPackage} from "./EDFPackage"; export function WriteEDFPackage(pack: EDFPackage, stream: fs.WriteStream) { WriteEDFHeader(pack, stream); for (const chunk of pack.chunks) { AppendChunk(chunk, stream, pack.channelInfos); } } function Str(length: number, val: any) { const result: string = (val ?? "").toString(); if (result.length > length) throw new Error(`Val "${result}" exceeded string-length limit of ${length}.`); return result.padEnd(length); } export function WriteEDFHeader(pack: EDFPackage, stream: fs.WriteStream) { stream.write(Str(8, pack.edfVersion)); stream.write(Str(80, pack.patientID)); stream.write(Str(80, pack.recordingID)); stream.write(Str(8, moment(pack.startTime).format("DD.MM.YY"))); stream.write(Str(8, moment(pack.startTime).format("HH.mm.ss"))); const headerBytes = 256 + (256 * pack.channelInfos.length); // class itself is 256 bytes, plus 256 per channel-info structure stream.write(Str(8, headerBytes)); stream.write(Str(44, pack.reservedStr)); stream.write(Str(8, pack.chunks.length)); stream.write(Str(8, pack.chunkDuration)); stream.write(Str(4, pack.channelInfos.length)); pack.channelInfos.forEach(a=>stream.write(Str(16, a.name))); pack.channelInfos.forEach(a=>stream.write(Str(80, a.type))); pack.channelInfos.forEach(a=>stream.write(Str(8, a.dimensions))); pack.channelInfos.forEach(a=>stream.write(Str(8, a.physicalMin))); pack.channelInfos.forEach(a=>stream.write(Str(8, a.physicalMax))); pack.channelInfos.forEach(a=>stream.write(Str(8, a.digitalMin))); pack.channelInfos.forEach(a=>stream.write(Str(8, a.digitalMax))); pack.channelInfos.forEach(a=>stream.write(Str(80, a.prefilteringInfo))); pack.channelInfos.forEach(a=>stream.write(Str(8, a.sampleCountPerChunk))); pack.channelInfos.forEach(a=>stream.write(Str(32, a.reservedStr))); } export function AppendChunk(chunk: Chunk, stream: fs.WriteStream, channelInfos: ChannelInfo[]) { // Data stays in channels x samples configuration // 2 Byte signed int litte-endian, 2's complement const totalSamplesPerChunk = channelInfos.map(ch=>ch.sampleCountPerChunk).reduce((total, a)=>total + a, 0); const buffer = Buffer.alloc(totalSamplesPerChunk * 2, "base64"); // each sample is 2 bytes let offset = 0; for (const channelSamples of chunk.channelSamples) { for (const sample of channelSamples) { //buffer.writeInt16LE(parseInt(((sample * 32768) / 188000).toString()), offset); //buffer.writeInt16LE(Math.floor((sample * 32768) / 188000), offset); buffer.writeInt16LE(sample, offset); offset += 2; } } stream.write(buffer, "base64"); }