Skip to content

Commit a10bdab

Browse files
committed
Add npy file sources
1 parent 42209fe commit a10bdab

2 files changed

Lines changed: 205 additions & 0 deletions

File tree

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
------------------------------------------------------------------
3+
4+
This file is part of the Open Ephys GUI
5+
Copyright (C) 2017 Open Ephys
6+
7+
------------------------------------------------------------------
8+
9+
This program is free software: you can redistribute it and/or modify
10+
it under the terms of the GNU General Public License as published by
11+
the Free Software Foundation, either version 3 of the License, or
12+
(at your option) any later version.
13+
14+
This program is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
GNU General Public License for more details.
18+
19+
You should have received a copy of the GNU General Public License
20+
along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
22+
*/
23+
24+
#include "NpyFile.h"
25+
26+
using namespace BinaryRecordingEngine;
27+
28+
NpyFile::NpyFile(String path, const Array<NpyType>& typeList)
29+
{
30+
File file(path);
31+
Result res = file.create();
32+
if (res.failed())
33+
{
34+
std::cerr << "Error creating file " << path << ":" << res.getErrorMessage() << std::endl;
35+
return;
36+
}
37+
m_file = file.createOutputStream();
38+
if (!m_file)
39+
return;
40+
41+
m_okOpen = true;
42+
43+
String header = "{'descr': [";
44+
45+
int nTypes = typeList.size();
46+
String name;
47+
48+
for (int i = 0; i < nTypes; i++)
49+
{
50+
NpyType& type = typeList.getReference(i);
51+
if (i > 0) header += ", ";
52+
header += "('" + type.getName() + "', '" + type.getTypeString() + "', (" + String(type.getTypeLength()) + ",))";
53+
}
54+
header += "], 'fortran_order': False, 'shape': (1,), }";
55+
56+
int headLength = header.length();
57+
int padding = (int((headLength + 30 ) / 16) + 1) * 16;
58+
header = header.paddedRight(' ', padding);
59+
header += '\n';
60+
61+
uint8 magicNum = 0x093;
62+
m_file->write(&magicNum, sizeof(uint8));
63+
String magic = "NUMPY";
64+
uint16 len = header.length();
65+
m_file->write(magic.toUTF8(), magic.getNumBytesAsUTF8());
66+
uint16 ver = 0x0001;
67+
m_file->write(&ver, sizeof(uint16));
68+
m_file->write(&len, sizeof(uint16));
69+
m_file->write(header.toUTF8(), len);
70+
m_countPos = headLength + 4; //10-6
71+
72+
}
73+
74+
NpyFile::~NpyFile()
75+
{
76+
if (m_file->setPosition(m_countPos))
77+
{
78+
String newShape = String(m_recordCount) + ",), }";
79+
m_file->write(newShape.toUTF8(), newShape.getNumBytesAsUTF8());
80+
}
81+
else
82+
{
83+
std::cerr << "Error. Unable to seek to update header on file " << m_file->getFile().getFullPathName() << std::endl;
84+
}
85+
}
86+
87+
void NpyFile::writeData(const void* data, size_t size)
88+
{
89+
m_file->write(data, size);
90+
}
91+
92+
void NpyFile::increaseRecordCount(int count)
93+
{
94+
m_recordCount += count;
95+
}
96+
97+
98+
NpyType::NpyType(String n, BaseType t, size_t l)
99+
: name(n), type(t), length(l)
100+
{
101+
}
102+
103+
String NpyType::getTypeString() const
104+
{
105+
switch (type)
106+
{
107+
case BaseType::CHAR:
108+
return "U" + String(length);
109+
case BaseType::INT8:
110+
return "<i1";
111+
case BaseType::UINT8:
112+
return "<u1";
113+
case BaseType::INT16:
114+
return "<i2";
115+
case BaseType::UINT16:
116+
return "<u2";
117+
case BaseType::INT32:
118+
return "<i4";
119+
case BaseType::UINT32:
120+
return "<u4";
121+
case BaseType::INT64:
122+
return "<i8";
123+
case BaseType::UINT64:
124+
return "<u8";
125+
case BaseType::FLOAT:
126+
return "<f4";
127+
case BaseType::DOUBLE:
128+
return "<f8";
129+
default:
130+
return "<b1";
131+
}
132+
}
133+
134+
int NpyType::getTypeLength() const
135+
{
136+
if (type == BaseType::CHAR)
137+
return 1;
138+
else
139+
return length;
140+
}
141+
142+
String NpyType::getName() const
143+
{
144+
return name;
145+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
------------------------------------------------------------------
3+
4+
This file is part of the Open Ephys GUI
5+
Copyright (C) 2017 Open Ephys
6+
7+
------------------------------------------------------------------
8+
9+
This program is free software: you can redistribute it and/or modify
10+
it under the terms of the GNU General Public License as published by
11+
the Free Software Foundation, either version 3 of the License, or
12+
(at your option) any later version.
13+
14+
This program is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
GNU General Public License for more details.
18+
19+
You should have received a copy of the GNU General Public License
20+
along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
22+
*/
23+
24+
#ifndef NPYFILE_H
25+
#define NPYFILE_H
26+
27+
#include <RecordingLib.h>
28+
29+
namespace BinaryRecordingEngine
30+
{
31+
32+
class NpyType
33+
{
34+
public:
35+
NpyType(String, BaseType, size_t);
36+
String getName() const;
37+
String getTypeString() const;
38+
int getTypeLength() const;
39+
private:
40+
String name;
41+
BaseType type;
42+
size_t length;
43+
};
44+
45+
class NpyFile
46+
{
47+
public:
48+
NpyFile(String path, const Array<NpyType>& typeList);
49+
~NpyFile();
50+
void writeData(const void* data, size_t size);
51+
void increaseRecordCount(int count = 1);
52+
private:
53+
ScopedPointer<FileOutputStream> m_file;
54+
bool m_okOpen{ false };
55+
int64 m_recordCount{ 0 };
56+
size_t m_countPos;
57+
};
58+
59+
};
60+
#endif

0 commit comments

Comments
 (0)