Chris@87
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@87
|
2
|
Chris@87
|
3 /*
|
Chris@87
|
4 Sonic Visualiser
|
Chris@87
|
5 An audio file viewer and annotation editor.
|
Chris@87
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@87
|
7 This file copyright 2006 Chris Cannam.
|
Chris@87
|
8
|
Chris@87
|
9 This program is free software; you can redistribute it and/or
|
Chris@87
|
10 modify it under the terms of the GNU General Public License as
|
Chris@87
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@87
|
12 License, or (at your option) any later version. See the file
|
Chris@87
|
13 COPYING included with this distribution for more information.
|
Chris@87
|
14 */
|
Chris@87
|
15
|
Chris@96
|
16 #include "MatrixFile.h"
|
Chris@87
|
17 #include "base/TempDirectory.h"
|
Chris@90
|
18 #include "base/System.h"
|
Chris@87
|
19
|
Chris@87
|
20 #include <sys/types.h>
|
Chris@87
|
21 #include <sys/stat.h>
|
Chris@87
|
22 #include <fcntl.h>
|
Chris@87
|
23 #include <unistd.h>
|
Chris@87
|
24
|
Chris@87
|
25 #include <iostream>
|
Chris@87
|
26
|
Chris@87
|
27 #include <cstdio>
|
Chris@87
|
28
|
Chris@87
|
29 #include <QFileInfo>
|
Chris@87
|
30 #include <QDir>
|
Chris@87
|
31
|
Chris@96
|
32 std::map<QString, int> MatrixFile::m_refcount;
|
Chris@96
|
33 QMutex MatrixFile::m_refcountMutex;
|
Chris@91
|
34
|
Chris@96
|
35 MatrixFile::MatrixFile(QString fileBase, Mode mode) :
|
Chris@87
|
36 m_fd(-1),
|
Chris@87
|
37 m_mode(mode),
|
Chris@87
|
38 m_width(0),
|
Chris@87
|
39 m_height(0),
|
Chris@90
|
40 m_headerSize(2 * sizeof(size_t)),
|
Chris@97
|
41 m_defaultCacheWidth(512),
|
Chris@95
|
42 m_prevX(0),
|
Chris@97
|
43 m_requestToken(-1),
|
Chris@97
|
44 m_spareData(0)
|
Chris@87
|
45 {
|
Chris@95
|
46 m_cache.data = 0;
|
Chris@90
|
47
|
Chris@87
|
48 QDir tempDir(TempDirectory::instance()->getPath());
|
Chris@87
|
49 QString fileName(tempDir.filePath(QString("%1.mfc").arg(fileBase)));
|
Chris@87
|
50 bool newFile = !QFileInfo(fileName).exists();
|
Chris@87
|
51
|
Chris@87
|
52 if (newFile && mode == ReadOnly) {
|
Chris@96
|
53 std::cerr << "ERROR: MatrixFile::MatrixFile: Read-only mode "
|
Chris@87
|
54 << "specified, but cache file does not exist" << std::endl;
|
Chris@87
|
55 return;
|
Chris@87
|
56 }
|
Chris@87
|
57
|
Chris@87
|
58 int flags = 0;
|
Chris@87
|
59 mode_t fmode = S_IRUSR | S_IWUSR;
|
Chris@87
|
60
|
Chris@87
|
61 if (mode == ReadWrite) {
|
Chris@87
|
62 flags = O_RDWR | O_CREAT;
|
Chris@87
|
63 } else {
|
Chris@87
|
64 flags = O_RDONLY;
|
Chris@87
|
65 }
|
Chris@87
|
66
|
Chris@90
|
67 if ((m_fd = ::open(fileName.toLocal8Bit(), flags, fmode)) < 0) {
|
Chris@87
|
68 ::perror("Open failed");
|
Chris@96
|
69 std::cerr << "ERROR: MatrixFile::MatrixFile: "
|
Chris@87
|
70 << "Failed to open cache file \""
|
Chris@87
|
71 << fileName.toStdString() << "\"";
|
Chris@87
|
72 if (mode == ReadWrite) std::cerr << " for writing";
|
Chris@87
|
73 std::cerr << std::endl;
|
Chris@91
|
74 return;
|
Chris@87
|
75 }
|
Chris@87
|
76
|
Chris@87
|
77 if (newFile) {
|
Chris@87
|
78 resize(0, 0); // write header
|
Chris@87
|
79 } else {
|
Chris@87
|
80 size_t header[2];
|
Chris@90
|
81 if (::read(m_fd, header, 2 * sizeof(size_t)) < 0) {
|
Chris@87
|
82 perror("Read failed");
|
Chris@96
|
83 std::cerr << "ERROR: MatrixFile::MatrixFile: "
|
Chris@90
|
84 << "Failed to read header (fd " << m_fd << ", file \""
|
Chris@90
|
85 << fileName.toStdString() << "\")" << std::endl;
|
Chris@87
|
86 return;
|
Chris@87
|
87 }
|
Chris@87
|
88 m_width = header[0];
|
Chris@87
|
89 m_height = header[1];
|
Chris@87
|
90 seekTo(0, 0);
|
Chris@87
|
91 }
|
Chris@87
|
92
|
Chris@91
|
93 m_fileName = fileName;
|
Chris@95
|
94
|
Chris@95
|
95 m_readThread.start();
|
Chris@95
|
96
|
Chris@91
|
97 QMutexLocker locker(&m_refcountMutex);
|
Chris@91
|
98 ++m_refcount[fileName];
|
Chris@91
|
99
|
Chris@96
|
100 std::cerr << "MatrixFile::MatrixFile: Done, size is " << "(" << m_width << ", " << m_height << ")" << std::endl;
|
Chris@87
|
101
|
Chris@87
|
102 }
|
Chris@87
|
103
|
Chris@96
|
104 MatrixFile::~MatrixFile()
|
Chris@87
|
105 {
|
Chris@95
|
106 float *requestData = 0;
|
Chris@95
|
107
|
Chris@95
|
108 if (m_requestToken >= 0) {
|
Chris@95
|
109 FileReadThread::Request request;
|
Chris@95
|
110 if (m_readThread.getRequest(m_requestToken, request)) {
|
Chris@95
|
111 requestData = (float *)request.data;
|
Chris@95
|
112 }
|
Chris@90
|
113 }
|
Chris@90
|
114
|
Chris@95
|
115 m_readThread.finish();
|
Chris@95
|
116 m_readThread.wait();
|
Chris@95
|
117
|
Chris@97
|
118 if (requestData) free(requestData);
|
Chris@97
|
119 if (m_cache.data) free(m_cache.data);
|
Chris@97
|
120 if (m_spareData) free(m_spareData);
|
Chris@95
|
121
|
Chris@87
|
122 if (m_fd >= 0) {
|
Chris@87
|
123 if (::close(m_fd) < 0) {
|
Chris@96
|
124 ::perror("MatrixFile::~MatrixFile: close failed");
|
Chris@87
|
125 }
|
Chris@87
|
126 }
|
Chris@90
|
127
|
Chris@91
|
128 if (m_fileName != "") {
|
Chris@91
|
129 QMutexLocker locker(&m_refcountMutex);
|
Chris@91
|
130 if (--m_refcount[m_fileName] == 0) {
|
Chris@95
|
131 if (::unlink(m_fileName.toLocal8Bit())) {
|
Chris@95
|
132 ::perror("Unlink failed");
|
Chris@96
|
133 std::cerr << "WARNING: MatrixFile::~MatrixFile: reference count reached 0, but failed to unlink file \"" << m_fileName.toStdString() << "\"" << std::endl;
|
Chris@91
|
134 } else {
|
Chris@91
|
135 std::cerr << "deleted " << m_fileName.toStdString() << std::endl;
|
Chris@91
|
136 }
|
Chris@91
|
137 }
|
Chris@91
|
138 }
|
Chris@87
|
139 }
|
Chris@87
|
140
|
Chris@87
|
141 size_t
|
Chris@96
|
142 MatrixFile::getWidth() const
|
Chris@87
|
143 {
|
Chris@87
|
144 return m_width;
|
Chris@87
|
145 }
|
Chris@87
|
146
|
Chris@87
|
147 size_t
|
Chris@96
|
148 MatrixFile::getHeight() const
|
Chris@87
|
149 {
|
Chris@87
|
150 return m_height;
|
Chris@87
|
151 }
|
Chris@87
|
152
|
Chris@87
|
153 void
|
Chris@96
|
154 MatrixFile::resize(size_t w, size_t h)
|
Chris@87
|
155 {
|
Chris@87
|
156 if (m_mode != ReadWrite) {
|
Chris@96
|
157 std::cerr << "ERROR: MatrixFile::resize called on read-only cache"
|
Chris@87
|
158 << std::endl;
|
Chris@87
|
159 return;
|
Chris@87
|
160 }
|
Chris@87
|
161
|
Chris@95
|
162 QMutexLocker locker(&m_fdMutex);
|
Chris@95
|
163
|
Chris@87
|
164 off_t off = m_headerSize + (w * h * sizeof(float));
|
Chris@87
|
165
|
Chris@87
|
166 if (w * h > m_width * m_height) {
|
Chris@87
|
167
|
Chris@95
|
168 if (::lseek(m_fd, off - sizeof(float), SEEK_SET) == (off_t)-1) {
|
Chris@95
|
169 ::perror("Seek failed");
|
Chris@96
|
170 std::cerr << "ERROR: MatrixFile::resize(" << w << ", "
|
Chris@95
|
171 << h << "): seek failed, cannot resize" << std::endl;
|
Chris@95
|
172 return;
|
Chris@95
|
173 }
|
Chris@95
|
174
|
Chris@95
|
175 // guess this requires efficient support for sparse files
|
Chris@90
|
176
|
Chris@95
|
177 float f(0);
|
Chris@95
|
178 if (::write(m_fd, &f, sizeof(float)) != sizeof(float)) {
|
Chris@96
|
179 ::perror("WARNING: MatrixFile::resize: write failed");
|
Chris@87
|
180 }
|
Chris@95
|
181
|
Chris@87
|
182 } else {
|
Chris@87
|
183
|
Chris@87
|
184 if (::ftruncate(m_fd, off) < 0) {
|
Chris@96
|
185 ::perror("WARNING: MatrixFile::resize: ftruncate failed");
|
Chris@87
|
186 }
|
Chris@87
|
187 }
|
Chris@87
|
188
|
Chris@87
|
189 m_width = 0;
|
Chris@87
|
190 m_height = 0;
|
Chris@87
|
191
|
Chris@87
|
192 if (::lseek(m_fd, 0, SEEK_SET) == (off_t)-1) {
|
Chris@96
|
193 ::perror("ERROR: MatrixFile::resize: Seek to write header failed");
|
Chris@87
|
194 return;
|
Chris@87
|
195 }
|
Chris@87
|
196
|
Chris@87
|
197 size_t header[2];
|
Chris@87
|
198 header[0] = w;
|
Chris@87
|
199 header[1] = h;
|
Chris@87
|
200 if (::write(m_fd, header, 2 * sizeof(size_t)) != 2 * sizeof(size_t)) {
|
Chris@96
|
201 ::perror("ERROR: MatrixFile::resize: Failed to write header");
|
Chris@87
|
202 return;
|
Chris@87
|
203 }
|
Chris@87
|
204
|
Chris@87
|
205 m_width = w;
|
Chris@87
|
206 m_height = h;
|
Chris@87
|
207
|
Chris@87
|
208 seekTo(0, 0);
|
Chris@87
|
209 }
|
Chris@87
|
210
|
Chris@87
|
211 void
|
Chris@96
|
212 MatrixFile::reset()
|
Chris@87
|
213 {
|
Chris@87
|
214 if (m_mode != ReadWrite) {
|
Chris@96
|
215 std::cerr << "ERROR: MatrixFile::reset called on read-only cache"
|
Chris@87
|
216 << std::endl;
|
Chris@87
|
217 return;
|
Chris@87
|
218 }
|
Chris@87
|
219
|
Chris@95
|
220 QMutexLocker locker(&m_fdMutex);
|
Chris@95
|
221
|
Chris@90
|
222 float *emptyCol = new float[m_height];
|
Chris@90
|
223 for (size_t y = 0; y < m_height; ++y) emptyCol[y] = 0.f;
|
Chris@90
|
224
|
Chris@90
|
225 seekTo(0, 0);
|
Chris@90
|
226 for (size_t x = 0; x < m_width; ++x) setColumnAt(x, emptyCol);
|
Chris@90
|
227
|
Chris@90
|
228 delete[] emptyCol;
|
Chris@87
|
229 }
|
Chris@87
|
230
|
Chris@95
|
231 float
|
Chris@96
|
232 MatrixFile::getValueAt(size_t x, size_t y)
|
Chris@87
|
233 {
|
Chris@95
|
234 float value = 0.f;
|
Chris@95
|
235 if (getValuesFromCache(x, y, 1, &value)) return value;
|
Chris@90
|
236
|
Chris@95
|
237 ssize_t r = 0;
|
Chris@87
|
238
|
Chris@96
|
239 // std::cout << "MatrixFile::getValueAt(" << x << ", " << y << ")"
|
Chris@95
|
240 // << ": reading the slow way" << std::endl;
|
Chris@95
|
241
|
Chris@95
|
242 m_fdMutex.lock();
|
Chris@95
|
243
|
Chris@95
|
244 if (seekTo(x, y)) {
|
Chris@95
|
245 r = ::read(m_fd, &value, sizeof(float));
|
Chris@87
|
246 }
|
Chris@87
|
247
|
Chris@95
|
248 m_fdMutex.unlock();
|
Chris@95
|
249
|
Chris@91
|
250 if (r < 0) {
|
Chris@96
|
251 ::perror("MatrixFile::getValueAt: Read failed");
|
Chris@91
|
252 }
|
Chris@90
|
253 if (r != sizeof(float)) {
|
Chris@90
|
254 value = 0.f;
|
Chris@87
|
255 }
|
Chris@95
|
256
|
Chris@87
|
257 return value;
|
Chris@87
|
258 }
|
Chris@87
|
259
|
Chris@87
|
260 void
|
Chris@96
|
261 MatrixFile::getColumnAt(size_t x, float *values)
|
Chris@87
|
262 {
|
Chris@95
|
263 if (getValuesFromCache(x, 0, m_height, values)) return;
|
Chris@95
|
264
|
Chris@95
|
265 ssize_t r = 0;
|
Chris@95
|
266
|
Chris@96
|
267 std::cout << "MatrixFile::getColumnAt(" << x << ")"
|
Chris@95
|
268 << ": reading the slow way" << std::endl;
|
Chris@95
|
269
|
Chris@95
|
270 m_fdMutex.lock();
|
Chris@95
|
271
|
Chris@95
|
272 if (seekTo(x, 0)) {
|
Chris@95
|
273 r = ::read(m_fd, values, m_height * sizeof(float));
|
Chris@87
|
274 }
|
Chris@87
|
275
|
Chris@95
|
276 m_fdMutex.unlock();
|
Chris@95
|
277
|
Chris@91
|
278 if (r < 0) {
|
Chris@96
|
279 ::perror("MatrixFile::getColumnAt: read failed");
|
Chris@87
|
280 }
|
Chris@95
|
281 }
|
Chris@95
|
282
|
Chris@95
|
283 bool
|
Chris@96
|
284 MatrixFile::getValuesFromCache(size_t x, size_t ystart, size_t ycount,
|
Chris@95
|
285 float *values)
|
Chris@95
|
286 {
|
Chris@95
|
287 m_cacheMutex.lock();
|
Chris@95
|
288
|
Chris@95
|
289 if (!m_cache.data || x < m_cache.x || x >= m_cache.x + m_cache.width) {
|
Chris@95
|
290 bool left = (m_cache.data && x < m_cache.x);
|
Chris@95
|
291 m_cacheMutex.unlock();
|
Chris@95
|
292 primeCache(x, left); // this doesn't take effect until a later callback
|
Chris@95
|
293 m_prevX = x;
|
Chris@95
|
294 return false;
|
Chris@95
|
295 }
|
Chris@95
|
296
|
Chris@95
|
297 for (size_t y = ystart; y < ystart + ycount; ++y) {
|
Chris@95
|
298 values[y - ystart] = m_cache.data[(x - m_cache.x) * m_height + y];
|
Chris@95
|
299 }
|
Chris@95
|
300 m_cacheMutex.unlock();
|
Chris@95
|
301
|
Chris@95
|
302 if (m_cache.x > 0 && x < m_prevX && x < m_cache.x + m_cache.width/4) {
|
Chris@95
|
303 primeCache(x, true);
|
Chris@95
|
304 }
|
Chris@95
|
305
|
Chris@95
|
306 if (m_cache.x + m_cache.width < m_width &&
|
Chris@95
|
307 x > m_prevX &&
|
Chris@95
|
308 x > m_cache.x + (m_cache.width * 3) / 4) {
|
Chris@95
|
309 primeCache(x, false);
|
Chris@95
|
310 }
|
Chris@95
|
311
|
Chris@95
|
312 m_prevX = x;
|
Chris@95
|
313 return true;
|
Chris@87
|
314 }
|
Chris@87
|
315
|
Chris@87
|
316 void
|
Chris@96
|
317 MatrixFile::setValueAt(size_t x, size_t y, float value)
|
Chris@87
|
318 {
|
Chris@87
|
319 if (m_mode != ReadWrite) {
|
Chris@96
|
320 std::cerr << "ERROR: MatrixFile::setValueAt called on read-only cache"
|
Chris@87
|
321 << std::endl;
|
Chris@87
|
322 return;
|
Chris@87
|
323 }
|
Chris@87
|
324
|
Chris@95
|
325 ssize_t w = 0;
|
Chris@95
|
326 bool seekFailed = false;
|
Chris@95
|
327
|
Chris@95
|
328 m_fdMutex.lock();
|
Chris@95
|
329
|
Chris@95
|
330 if (seekTo(x, y)) {
|
Chris@95
|
331 w = ::write(m_fd, &value, sizeof(float));
|
Chris@95
|
332 } else {
|
Chris@95
|
333 seekFailed = true;
|
Chris@95
|
334 }
|
Chris@95
|
335
|
Chris@95
|
336 m_fdMutex.unlock();
|
Chris@95
|
337
|
Chris@95
|
338 if (!seekFailed && w != sizeof(float)) {
|
Chris@96
|
339 ::perror("WARNING: MatrixFile::setValueAt: write failed");
|
Chris@87
|
340 }
|
Chris@87
|
341
|
Chris@95
|
342 //... update cache as appropriate
|
Chris@87
|
343 }
|
Chris@87
|
344
|
Chris@87
|
345 void
|
Chris@96
|
346 MatrixFile::setColumnAt(size_t x, float *values)
|
Chris@87
|
347 {
|
Chris@87
|
348 if (m_mode != ReadWrite) {
|
Chris@96
|
349 std::cerr << "ERROR: MatrixFile::setColumnAt called on read-only cache"
|
Chris@87
|
350 << std::endl;
|
Chris@87
|
351 return;
|
Chris@87
|
352 }
|
Chris@87
|
353
|
Chris@95
|
354 ssize_t w = 0;
|
Chris@95
|
355 bool seekFailed = false;
|
Chris@95
|
356
|
Chris@95
|
357 m_fdMutex.lock();
|
Chris@95
|
358
|
Chris@95
|
359 if (seekTo(x, 0)) {
|
Chris@95
|
360 w = ::write(m_fd, values, m_height * sizeof(float));
|
Chris@95
|
361 } else {
|
Chris@95
|
362 seekFailed = true;
|
Chris@95
|
363 }
|
Chris@95
|
364
|
Chris@95
|
365 m_fdMutex.unlock();
|
Chris@95
|
366
|
Chris@95
|
367 if (!seekFailed && w != ssize_t(m_height * sizeof(float))) {
|
Chris@96
|
368 ::perror("WARNING: MatrixFile::setColumnAt: write failed");
|
Chris@87
|
369 }
|
Chris@87
|
370
|
Chris@95
|
371 //... update cache as appropriate
|
Chris@90
|
372 }
|
Chris@90
|
373
|
Chris@95
|
374 void
|
Chris@96
|
375 MatrixFile::primeCache(size_t x, bool goingLeft)
|
Chris@90
|
376 {
|
Chris@96
|
377 // std::cerr << "MatrixFile::primeCache(" << x << ", " << goingLeft << ")" << std::endl;
|
Chris@90
|
378
|
Chris@95
|
379 size_t rx = x;
|
Chris@95
|
380 size_t rw = m_defaultCacheWidth;
|
Chris@90
|
381
|
Chris@95
|
382 size_t left = rw / 3;
|
Chris@95
|
383 if (goingLeft) left = (rw * 2) / 3;
|
Chris@95
|
384
|
Chris@95
|
385 if (rx > left) rx -= left;
|
Chris@95
|
386 else rx = 0;
|
Chris@95
|
387
|
Chris@95
|
388 if (rx + rw > m_width) rw = m_width - rx;
|
Chris@95
|
389
|
Chris@95
|
390 QMutexLocker locker(&m_cacheMutex);
|
Chris@95
|
391
|
Chris@96
|
392 FileReadThread::Request request;
|
Chris@96
|
393
|
Chris@96
|
394 if (m_requestToken >= 0 &&
|
Chris@96
|
395 m_readThread.getRequest(m_requestToken, request)) {
|
Chris@95
|
396
|
Chris@95
|
397 if (x >= m_requestingX &&
|
Chris@95
|
398 x < m_requestingX + m_requestingWidth) {
|
Chris@95
|
399
|
Chris@95
|
400 if (m_readThread.isReady(m_requestToken)) {
|
Chris@95
|
401
|
Chris@95
|
402 std::cerr << "last request is ready! (" << m_requestingX << ", "<< m_requestingWidth << ")" << std::endl;
|
Chris@95
|
403
|
Chris@96
|
404 m_cache.x = (request.start - m_headerSize) / (m_height * sizeof(float));
|
Chris@96
|
405 m_cache.width = request.size / (m_height * sizeof(float));
|
Chris@96
|
406
|
Chris@96
|
407 std::cerr << "actual: " << m_cache.x << ", " << m_cache.width << std::endl;
|
Chris@95
|
408
|
Chris@97
|
409 if (m_cache.data) {
|
Chris@97
|
410 if (m_spareData) free(m_spareData);
|
Chris@97
|
411 m_spareData = (char *)m_cache.data;
|
Chris@97
|
412 }
|
Chris@96
|
413 m_cache.data = (float *)request.data;
|
Chris@95
|
414
|
Chris@95
|
415 m_readThread.done(m_requestToken);
|
Chris@95
|
416 m_requestToken = -1;
|
Chris@95
|
417 }
|
Chris@95
|
418
|
Chris@96
|
419 // already requested something covering this area; wait for it
|
Chris@95
|
420 return;
|
Chris@95
|
421 }
|
Chris@95
|
422
|
Chris@96
|
423 // the current request is no longer of any use
|
Chris@95
|
424 m_readThread.cancel(m_requestToken);
|
Chris@96
|
425
|
Chris@96
|
426 // crude way to avoid leaking the data
|
Chris@96
|
427 while (!m_readThread.isCancelled(m_requestToken)) {
|
Chris@96
|
428 usleep(10000);
|
Chris@96
|
429 }
|
Chris@96
|
430
|
Chris@97
|
431 if (m_spareData) free(m_spareData);
|
Chris@97
|
432 m_spareData = request.data;
|
Chris@96
|
433 m_readThread.done(m_requestToken);
|
Chris@96
|
434
|
Chris@95
|
435 m_requestToken = -1;
|
Chris@95
|
436 }
|
Chris@95
|
437
|
Chris@95
|
438 request.fd = m_fd;
|
Chris@95
|
439 request.mutex = &m_fdMutex;
|
Chris@95
|
440 request.start = m_headerSize + rx * m_height * sizeof(float);
|
Chris@95
|
441 request.size = rw * m_height * sizeof(float);
|
Chris@97
|
442 request.data = (char *)realloc(m_spareData, rw * m_height * sizeof(float));
|
Chris@96
|
443 MUNLOCK(request.data, rw * m_height * sizeof(float));
|
Chris@97
|
444 m_spareData = 0;
|
Chris@95
|
445
|
Chris@95
|
446 m_requestingX = rx;
|
Chris@95
|
447 m_requestingWidth = rw;
|
Chris@95
|
448
|
Chris@95
|
449 int token = m_readThread.request(request);
|
Chris@96
|
450 std::cerr << "MatrixFile::primeCache: request token is "
|
Chris@96
|
451 << token << " (x = " << rx << ", w = " << rw << ", left = " << goingLeft << ")" << std::endl;
|
Chris@95
|
452
|
Chris@95
|
453 m_requestToken = token;
|
Chris@95
|
454 }
|
Chris@95
|
455
|
Chris@90
|
456 bool
|
Chris@96
|
457 MatrixFile::seekTo(size_t x, size_t y)
|
Chris@87
|
458 {
|
Chris@87
|
459 off_t off = m_headerSize + (x * m_height + y) * sizeof(float);
|
Chris@90
|
460
|
Chris@87
|
461 if (::lseek(m_fd, off, SEEK_SET) == (off_t)-1) {
|
Chris@87
|
462 ::perror("Seek failed");
|
Chris@96
|
463 std::cerr << "ERROR: MatrixFile::seekTo(" << x << ", " << y
|
Chris@87
|
464 << ") failed" << std::endl;
|
Chris@87
|
465 return false;
|
Chris@87
|
466 }
|
Chris@87
|
467
|
Chris@87
|
468 return true;
|
Chris@87
|
469 }
|
Chris@87
|
470
|