Mercurial > hg > svcore
comparison base/MatrixFileCache.cpp @ 87:7de62a884810
* Start factoring out the spectrogram's FFT cache into a separate set of
classes that will permit a choice of disk or memory cache strategies
author | Chris Cannam |
---|---|
date | Tue, 02 May 2006 12:27:41 +0000 |
parents | |
children | c4e163f911dd |
comparison
equal
deleted
inserted
replaced
86:e076e676439b | 87:7de62a884810 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2006 Chris Cannam. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #include "MatrixFileCache.h" | |
17 #include "base/TempDirectory.h" | |
18 | |
19 #include <sys/types.h> | |
20 #include <sys/stat.h> | |
21 #include <fcntl.h> | |
22 #include <unistd.h> | |
23 | |
24 #include <iostream> | |
25 | |
26 #include <cstdio> | |
27 | |
28 #include <QFileInfo> | |
29 #include <QDir> | |
30 | |
31 MatrixFileCache::MatrixFileCache(QString fileBase, Mode mode) : | |
32 m_fd(-1), | |
33 m_off(-1), | |
34 m_mode(mode), | |
35 m_width(0), | |
36 m_height(0), | |
37 m_rx(0), | |
38 m_rw(0), | |
39 m_range(0), | |
40 m_headerSize(2 * sizeof(size_t)) | |
41 { | |
42 QDir tempDir(TempDirectory::instance()->getPath()); | |
43 QString fileName(tempDir.filePath(QString("%1.mfc").arg(fileBase))); | |
44 bool newFile = !QFileInfo(fileName).exists(); | |
45 | |
46 if (newFile && mode == ReadOnly) { | |
47 std::cerr << "ERROR: MatrixFileCache::MatrixFileCache: Read-only mode " | |
48 << "specified, but cache file does not exist" << std::endl; | |
49 return; | |
50 } | |
51 | |
52 int flags = 0; | |
53 mode_t fmode = S_IRUSR | S_IWUSR; | |
54 | |
55 if (mode == ReadWrite) { | |
56 flags = O_RDWR | O_CREAT; | |
57 } else { | |
58 flags = O_RDONLY; | |
59 } | |
60 | |
61 if ((m_fd = ::open(fileName.toLocal8Bit(), flags, mode)) < 0) { | |
62 ::perror("Open failed"); | |
63 std::cerr << "ERROR: MatrixFileCache::MatrixFileCache: " | |
64 << "Failed to open cache file \"" | |
65 << fileName.toStdString() << "\""; | |
66 if (mode == ReadWrite) std::cerr << " for writing"; | |
67 std::cerr << std::endl; | |
68 } | |
69 | |
70 if (newFile) { | |
71 resize(0, 0); // write header | |
72 } else { | |
73 size_t header[2]; | |
74 if (::read(m_fd, header, 2 * sizeof(size_t))) { | |
75 perror("Read failed"); | |
76 std::cerr << "ERROR: MatrixFileCache::MatrixFileCache: " | |
77 << "Failed to read header" << std::endl; | |
78 return; | |
79 } | |
80 m_width = header[0]; | |
81 m_height = header[1]; | |
82 seekTo(0, 0); | |
83 } | |
84 | |
85 std::cerr << "MatrixFileCache::MatrixFileCache: Done, size is " << m_width << "x" << m_height << std::endl; | |
86 | |
87 } | |
88 | |
89 MatrixFileCache::~MatrixFileCache() | |
90 { | |
91 if (m_fd >= 0) { | |
92 if (::close(m_fd) < 0) { | |
93 ::perror("MatrixFileCache::~MatrixFileCache: close failed"); | |
94 } | |
95 } | |
96 } | |
97 | |
98 size_t | |
99 MatrixFileCache::getWidth() const | |
100 { | |
101 return m_width; | |
102 } | |
103 | |
104 size_t | |
105 MatrixFileCache::getHeight() const | |
106 { | |
107 return m_height; | |
108 } | |
109 | |
110 void | |
111 MatrixFileCache::resize(size_t w, size_t h) | |
112 { | |
113 if (m_mode != ReadWrite) { | |
114 std::cerr << "ERROR: MatrixFileCache::resize called on read-only cache" | |
115 << std::endl; | |
116 return; | |
117 } | |
118 | |
119 off_t off = m_headerSize + (w * h * sizeof(float)); | |
120 | |
121 if (w * h > m_width * m_height) { | |
122 | |
123 if (::lseek(m_fd, off - sizeof(float), SEEK_SET) == (off_t)-1) { | |
124 ::perror("Seek failed"); | |
125 std::cerr << "ERROR: MatrixFileCache::resize(" << w << ", " | |
126 << h << "): seek failed, cannot resize" << std::endl; | |
127 return; | |
128 } | |
129 | |
130 // guess this requires efficient support for sparse files | |
131 | |
132 float f(0); | |
133 if (::write(m_fd, &f, sizeof(float)) != sizeof(float)) { | |
134 ::perror("WARNING: MatrixFileCache::resize: write failed"); | |
135 } | |
136 | |
137 } else { | |
138 | |
139 if (::ftruncate(m_fd, off) < 0) { | |
140 ::perror("MatrixFileCache::resize: ftruncate failed"); | |
141 } | |
142 } | |
143 | |
144 m_width = 0; | |
145 m_height = 0; | |
146 m_off = 0; | |
147 | |
148 if (::lseek(m_fd, 0, SEEK_SET) == (off_t)-1) { | |
149 ::perror("ERROR: MatrixFileCache::resize: Seek to write header failed"); | |
150 return; | |
151 } | |
152 | |
153 size_t header[2]; | |
154 header[0] = w; | |
155 header[1] = h; | |
156 if (::write(m_fd, header, 2 * sizeof(size_t)) != 2 * sizeof(size_t)) { | |
157 ::perror("ERROR: MatrixFileCache::resize: Failed to write header"); | |
158 return; | |
159 } | |
160 | |
161 m_width = w; | |
162 m_height = h; | |
163 | |
164 seekTo(0, 0); | |
165 } | |
166 | |
167 void | |
168 MatrixFileCache::reset() | |
169 { | |
170 if (m_mode != ReadWrite) { | |
171 std::cerr << "ERROR: MatrixFileCache::reset called on read-only cache" | |
172 << std::endl; | |
173 return; | |
174 } | |
175 | |
176 //... | |
177 } | |
178 | |
179 void | |
180 MatrixFileCache::setRangeOfInterest(size_t x, size_t width) | |
181 { | |
182 } | |
183 | |
184 float | |
185 MatrixFileCache::getValueAt(size_t x, size_t y) const | |
186 { | |
187 if (m_rw > 0 && x >= m_rx && x < m_rx + m_rw) { | |
188 return m_range[x - m_rx][y]; | |
189 } | |
190 | |
191 if (!seekTo(x, y)) return 0.f; | |
192 float value; | |
193 if (::read(m_fd, &value, sizeof(float)) != sizeof(float)) { | |
194 ::perror("MatrixFileCache::getValueAt: read failed"); | |
195 return 0.f; | |
196 } | |
197 return value; | |
198 } | |
199 | |
200 void | |
201 MatrixFileCache::getColumnAt(size_t x, float *values) const | |
202 { | |
203 if (m_rw > 0 && x >= m_rx && x < m_rx + m_rw) { | |
204 for (size_t y = 0; y < m_height; ++y) { | |
205 values[y] = m_range[x - m_rx][y]; | |
206 } | |
207 } | |
208 | |
209 if (!seekTo(x, 0)) return; | |
210 if (::read(m_fd, values, m_height * sizeof(float)) != m_height * sizeof(float)) { | |
211 ::perror("MatrixFileCache::getColumnAt: read failed"); | |
212 } | |
213 return; | |
214 } | |
215 | |
216 void | |
217 MatrixFileCache::setValueAt(size_t x, size_t y, float value) | |
218 { | |
219 if (m_mode != ReadWrite) { | |
220 std::cerr << "ERROR: MatrixFileCache::setValueAt called on read-only cache" | |
221 << std::endl; | |
222 return; | |
223 } | |
224 | |
225 if (!seekTo(x, y)) return; | |
226 if (::write(m_fd, &value, sizeof(float)) != sizeof(float)) { | |
227 ::perror("WARNING: MatrixFileCache::setValueAt: write failed"); | |
228 } | |
229 | |
230 //... update range as appropriate | |
231 } | |
232 | |
233 void | |
234 MatrixFileCache::setColumnAt(size_t x, float *values) | |
235 { | |
236 if (m_mode != ReadWrite) { | |
237 std::cerr << "ERROR: MatrixFileCache::setColumnAt called on read-only cache" | |
238 << std::endl; | |
239 return; | |
240 } | |
241 | |
242 if (!seekTo(x, 0)) return; | |
243 if (::write(m_fd, values, m_height * sizeof(float)) != m_height * sizeof(float)) { | |
244 ::perror("WARNING: MatrixFileCache::setColumnAt: write failed"); | |
245 } | |
246 | |
247 //... update range as appropriate | |
248 } | |
249 | |
250 bool | |
251 MatrixFileCache::seekTo(size_t x, size_t y) const | |
252 { | |
253 off_t off = m_headerSize + (x * m_height + y) * sizeof(float); | |
254 if (off == m_off) return true; | |
255 | |
256 if (::lseek(m_fd, off, SEEK_SET) == (off_t)-1) { | |
257 ::perror("Seek failed"); | |
258 std::cerr << "ERROR: MatrixFileCache::seekTo(" << x << ", " << y | |
259 << ") failed" << std::endl; | |
260 return false; | |
261 } | |
262 | |
263 m_off = off; | |
264 return true; | |
265 } | |
266 |