annotate 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
rev   line source
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@87 16 #include "MatrixFileCache.h"
Chris@87 17 #include "base/TempDirectory.h"
Chris@87 18
Chris@87 19 #include <sys/types.h>
Chris@87 20 #include <sys/stat.h>
Chris@87 21 #include <fcntl.h>
Chris@87 22 #include <unistd.h>
Chris@87 23
Chris@87 24 #include <iostream>
Chris@87 25
Chris@87 26 #include <cstdio>
Chris@87 27
Chris@87 28 #include <QFileInfo>
Chris@87 29 #include <QDir>
Chris@87 30
Chris@87 31 MatrixFileCache::MatrixFileCache(QString fileBase, Mode mode) :
Chris@87 32 m_fd(-1),
Chris@87 33 m_off(-1),
Chris@87 34 m_mode(mode),
Chris@87 35 m_width(0),
Chris@87 36 m_height(0),
Chris@87 37 m_rx(0),
Chris@87 38 m_rw(0),
Chris@87 39 m_range(0),
Chris@87 40 m_headerSize(2 * sizeof(size_t))
Chris@87 41 {
Chris@87 42 QDir tempDir(TempDirectory::instance()->getPath());
Chris@87 43 QString fileName(tempDir.filePath(QString("%1.mfc").arg(fileBase)));
Chris@87 44 bool newFile = !QFileInfo(fileName).exists();
Chris@87 45
Chris@87 46 if (newFile && mode == ReadOnly) {
Chris@87 47 std::cerr << "ERROR: MatrixFileCache::MatrixFileCache: Read-only mode "
Chris@87 48 << "specified, but cache file does not exist" << std::endl;
Chris@87 49 return;
Chris@87 50 }
Chris@87 51
Chris@87 52 int flags = 0;
Chris@87 53 mode_t fmode = S_IRUSR | S_IWUSR;
Chris@87 54
Chris@87 55 if (mode == ReadWrite) {
Chris@87 56 flags = O_RDWR | O_CREAT;
Chris@87 57 } else {
Chris@87 58 flags = O_RDONLY;
Chris@87 59 }
Chris@87 60
Chris@87 61 if ((m_fd = ::open(fileName.toLocal8Bit(), flags, mode)) < 0) {
Chris@87 62 ::perror("Open failed");
Chris@87 63 std::cerr << "ERROR: MatrixFileCache::MatrixFileCache: "
Chris@87 64 << "Failed to open cache file \""
Chris@87 65 << fileName.toStdString() << "\"";
Chris@87 66 if (mode == ReadWrite) std::cerr << " for writing";
Chris@87 67 std::cerr << std::endl;
Chris@87 68 }
Chris@87 69
Chris@87 70 if (newFile) {
Chris@87 71 resize(0, 0); // write header
Chris@87 72 } else {
Chris@87 73 size_t header[2];
Chris@87 74 if (::read(m_fd, header, 2 * sizeof(size_t))) {
Chris@87 75 perror("Read failed");
Chris@87 76 std::cerr << "ERROR: MatrixFileCache::MatrixFileCache: "
Chris@87 77 << "Failed to read header" << std::endl;
Chris@87 78 return;
Chris@87 79 }
Chris@87 80 m_width = header[0];
Chris@87 81 m_height = header[1];
Chris@87 82 seekTo(0, 0);
Chris@87 83 }
Chris@87 84
Chris@87 85 std::cerr << "MatrixFileCache::MatrixFileCache: Done, size is " << m_width << "x" << m_height << std::endl;
Chris@87 86
Chris@87 87 }
Chris@87 88
Chris@87 89 MatrixFileCache::~MatrixFileCache()
Chris@87 90 {
Chris@87 91 if (m_fd >= 0) {
Chris@87 92 if (::close(m_fd) < 0) {
Chris@87 93 ::perror("MatrixFileCache::~MatrixFileCache: close failed");
Chris@87 94 }
Chris@87 95 }
Chris@87 96 }
Chris@87 97
Chris@87 98 size_t
Chris@87 99 MatrixFileCache::getWidth() const
Chris@87 100 {
Chris@87 101 return m_width;
Chris@87 102 }
Chris@87 103
Chris@87 104 size_t
Chris@87 105 MatrixFileCache::getHeight() const
Chris@87 106 {
Chris@87 107 return m_height;
Chris@87 108 }
Chris@87 109
Chris@87 110 void
Chris@87 111 MatrixFileCache::resize(size_t w, size_t h)
Chris@87 112 {
Chris@87 113 if (m_mode != ReadWrite) {
Chris@87 114 std::cerr << "ERROR: MatrixFileCache::resize called on read-only cache"
Chris@87 115 << std::endl;
Chris@87 116 return;
Chris@87 117 }
Chris@87 118
Chris@87 119 off_t off = m_headerSize + (w * h * sizeof(float));
Chris@87 120
Chris@87 121 if (w * h > m_width * m_height) {
Chris@87 122
Chris@87 123 if (::lseek(m_fd, off - sizeof(float), SEEK_SET) == (off_t)-1) {
Chris@87 124 ::perror("Seek failed");
Chris@87 125 std::cerr << "ERROR: MatrixFileCache::resize(" << w << ", "
Chris@87 126 << h << "): seek failed, cannot resize" << std::endl;
Chris@87 127 return;
Chris@87 128 }
Chris@87 129
Chris@87 130 // guess this requires efficient support for sparse files
Chris@87 131
Chris@87 132 float f(0);
Chris@87 133 if (::write(m_fd, &f, sizeof(float)) != sizeof(float)) {
Chris@87 134 ::perror("WARNING: MatrixFileCache::resize: write failed");
Chris@87 135 }
Chris@87 136
Chris@87 137 } else {
Chris@87 138
Chris@87 139 if (::ftruncate(m_fd, off) < 0) {
Chris@87 140 ::perror("MatrixFileCache::resize: ftruncate failed");
Chris@87 141 }
Chris@87 142 }
Chris@87 143
Chris@87 144 m_width = 0;
Chris@87 145 m_height = 0;
Chris@87 146 m_off = 0;
Chris@87 147
Chris@87 148 if (::lseek(m_fd, 0, SEEK_SET) == (off_t)-1) {
Chris@87 149 ::perror("ERROR: MatrixFileCache::resize: Seek to write header failed");
Chris@87 150 return;
Chris@87 151 }
Chris@87 152
Chris@87 153 size_t header[2];
Chris@87 154 header[0] = w;
Chris@87 155 header[1] = h;
Chris@87 156 if (::write(m_fd, header, 2 * sizeof(size_t)) != 2 * sizeof(size_t)) {
Chris@87 157 ::perror("ERROR: MatrixFileCache::resize: Failed to write header");
Chris@87 158 return;
Chris@87 159 }
Chris@87 160
Chris@87 161 m_width = w;
Chris@87 162 m_height = h;
Chris@87 163
Chris@87 164 seekTo(0, 0);
Chris@87 165 }
Chris@87 166
Chris@87 167 void
Chris@87 168 MatrixFileCache::reset()
Chris@87 169 {
Chris@87 170 if (m_mode != ReadWrite) {
Chris@87 171 std::cerr << "ERROR: MatrixFileCache::reset called on read-only cache"
Chris@87 172 << std::endl;
Chris@87 173 return;
Chris@87 174 }
Chris@87 175
Chris@87 176 //...
Chris@87 177 }
Chris@87 178
Chris@87 179 void
Chris@87 180 MatrixFileCache::setRangeOfInterest(size_t x, size_t width)
Chris@87 181 {
Chris@87 182 }
Chris@87 183
Chris@87 184 float
Chris@87 185 MatrixFileCache::getValueAt(size_t x, size_t y) const
Chris@87 186 {
Chris@87 187 if (m_rw > 0 && x >= m_rx && x < m_rx + m_rw) {
Chris@87 188 return m_range[x - m_rx][y];
Chris@87 189 }
Chris@87 190
Chris@87 191 if (!seekTo(x, y)) return 0.f;
Chris@87 192 float value;
Chris@87 193 if (::read(m_fd, &value, sizeof(float)) != sizeof(float)) {
Chris@87 194 ::perror("MatrixFileCache::getValueAt: read failed");
Chris@87 195 return 0.f;
Chris@87 196 }
Chris@87 197 return value;
Chris@87 198 }
Chris@87 199
Chris@87 200 void
Chris@87 201 MatrixFileCache::getColumnAt(size_t x, float *values) const
Chris@87 202 {
Chris@87 203 if (m_rw > 0 && x >= m_rx && x < m_rx + m_rw) {
Chris@87 204 for (size_t y = 0; y < m_height; ++y) {
Chris@87 205 values[y] = m_range[x - m_rx][y];
Chris@87 206 }
Chris@87 207 }
Chris@87 208
Chris@87 209 if (!seekTo(x, 0)) return;
Chris@87 210 if (::read(m_fd, values, m_height * sizeof(float)) != m_height * sizeof(float)) {
Chris@87 211 ::perror("MatrixFileCache::getColumnAt: read failed");
Chris@87 212 }
Chris@87 213 return;
Chris@87 214 }
Chris@87 215
Chris@87 216 void
Chris@87 217 MatrixFileCache::setValueAt(size_t x, size_t y, float value)
Chris@87 218 {
Chris@87 219 if (m_mode != ReadWrite) {
Chris@87 220 std::cerr << "ERROR: MatrixFileCache::setValueAt called on read-only cache"
Chris@87 221 << std::endl;
Chris@87 222 return;
Chris@87 223 }
Chris@87 224
Chris@87 225 if (!seekTo(x, y)) return;
Chris@87 226 if (::write(m_fd, &value, sizeof(float)) != sizeof(float)) {
Chris@87 227 ::perror("WARNING: MatrixFileCache::setValueAt: write failed");
Chris@87 228 }
Chris@87 229
Chris@87 230 //... update range as appropriate
Chris@87 231 }
Chris@87 232
Chris@87 233 void
Chris@87 234 MatrixFileCache::setColumnAt(size_t x, float *values)
Chris@87 235 {
Chris@87 236 if (m_mode != ReadWrite) {
Chris@87 237 std::cerr << "ERROR: MatrixFileCache::setColumnAt called on read-only cache"
Chris@87 238 << std::endl;
Chris@87 239 return;
Chris@87 240 }
Chris@87 241
Chris@87 242 if (!seekTo(x, 0)) return;
Chris@87 243 if (::write(m_fd, values, m_height * sizeof(float)) != m_height * sizeof(float)) {
Chris@87 244 ::perror("WARNING: MatrixFileCache::setColumnAt: write failed");
Chris@87 245 }
Chris@87 246
Chris@87 247 //... update range as appropriate
Chris@87 248 }
Chris@87 249
Chris@87 250 bool
Chris@87 251 MatrixFileCache::seekTo(size_t x, size_t y) const
Chris@87 252 {
Chris@87 253 off_t off = m_headerSize + (x * m_height + y) * sizeof(float);
Chris@87 254 if (off == m_off) return true;
Chris@87 255
Chris@87 256 if (::lseek(m_fd, off, SEEK_SET) == (off_t)-1) {
Chris@87 257 ::perror("Seek failed");
Chris@87 258 std::cerr << "ERROR: MatrixFileCache::seekTo(" << x << ", " << y
Chris@87 259 << ") failed" << std::endl;
Chris@87 260 return false;
Chris@87 261 }
Chris@87 262
Chris@87 263 m_off = off;
Chris@87 264 return true;
Chris@87 265 }
Chris@87 266