# HG changeset patch # User Chris Cannam # Date 1146834407 0 # Node ID 0a846f83a4b7af1990f98371542cec16a707cd4b # Parent ce1d385f4f89d801af2e84f9fb628cde6d56701d * Move matrix/fft file code to fileio (from base) * Add right-button menu to panes diff -r ce1d385f4f89 -r 0a846f83a4b7 base/FFTFileCache.cpp --- a/base/FFTFileCache.cpp Fri May 05 12:34:51 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "FFTFileCache.h" - -#include "MatrixFile.h" - -#include - -//!!! This class is a work in progress -- it does only as much as we -// need for the current SpectrogramLayer. Slated for substantial -// refactoring and extension. - -// The underlying matrix has height (m_height * 2 + 1). In each -// column we store magnitude at [0], [2] etc and phase at [1], [3] -// etc, and then store the normalization factor (maximum magnitude) at -// [m_height * 2]. - -FFTFileCache::FFTFileCache(QString fileBase, MatrixFile::Mode mode) : - m_colbuf(0), - m_mfc(new MatrixFile(fileBase, mode)) -{ -} - -FFTFileCache::~FFTFileCache() -{ - delete m_colbuf; - delete m_mfc; -} - -size_t -FFTFileCache::getWidth() const -{ - return m_mfc->getWidth(); -} - -size_t -FFTFileCache::getHeight() const -{ - size_t mh = m_mfc->getHeight(); - if (mh > 0) return (mh - 1) / 2; - else return 0; -} - -void -FFTFileCache::resize(size_t width, size_t height) -{ - m_mfc->resize(width, height * 2 + 1); - delete m_colbuf; - m_colbuf = new float[height * 2 + 1]; -} - -void -FFTFileCache::reset() -{ - m_mfc->reset(); -} - -float -FFTFileCache::getMagnitudeAt(size_t x, size_t y) const -{ - return m_mfc->getValueAt(x, y * 2); -} - -float -FFTFileCache::getNormalizedMagnitudeAt(size_t x, size_t y) const -{ - float factor = m_mfc->getValueAt(x, m_mfc->getHeight() - 1); - float mag = m_mfc->getValueAt(x, y * 2); - if (factor != 0) return mag / factor; - else return 0.f; -} - -float -FFTFileCache::getPhaseAt(size_t x, size_t y) const -{ - return m_mfc->getValueAt(x, y * 2 + 1); -} - -void -FFTFileCache::setNormalizationFactor(size_t x, float factor) -{ - m_mfc->setValueAt(x, m_mfc->getHeight() - 1, factor); -} - -void -FFTFileCache::setMagnitudeAt(size_t x, size_t y, float mag) -{ - m_mfc->setValueAt(x, y * 2, mag); -} - -void -FFTFileCache::setNormalizedMagnitudeAt(size_t x, size_t y, float norm) -{ - float factor = m_mfc->getValueAt(x, m_mfc->getHeight() - 1); - m_mfc->setValueAt(x, y * 2, norm * factor); -} - -void -FFTFileCache::setPhaseAt(size_t x, size_t y, float phase) -{ - m_mfc->setValueAt(x, y * 2 + 1, phase); -} - -void -FFTFileCache::setColumnAt(size_t x, float *mags, float *phases, float factor) -{ - size_t h = getHeight(); - for (size_t y = 0; y < h; ++y) { - m_colbuf[y * 2] = mags[y]; - m_colbuf[y * 2 + 1] = phases[y]; - } - m_colbuf[h * 2] = factor; - m_mfc->setColumnAt(x, m_colbuf); -} - diff -r ce1d385f4f89 -r 0a846f83a4b7 base/FFTFileCache.h --- a/base/FFTFileCache.h Fri May 05 12:34:51 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _FFT_FILE_CACHE_H_ -#define _FFT_FILE_CACHE_H_ - -#include "FFTCache.h" -#include "MatrixFile.h" - -class FFTFileCache : public FFTCacheBase -{ -public: - //!!! This is very much a work in progress. - // - // Initially, make this take a string for the filename, - // and make the spectrogram layer have two, one for the main - // thread and one for the fill thread, one RO and one RW, both - // using the same string based off spectrogram layer address - // or export ID. - // Subsequently factor out into reader and writer; - // make take arguments to ctor describing FFT parameters and - // calculate its own string and eventually do its own FFT as - // well. Intention is to make it able ultimately to write - // its own cache so it can do it in the background while e.g. - // plugins get data from it -- need the reader thread to be able - // to block waiting for the writer thread as appropriate. - - FFTFileCache(QString fileBase, MatrixFile::Mode mode); - virtual ~FFTFileCache(); - - virtual size_t getWidth() const; - virtual size_t getHeight() const; - - virtual void resize(size_t width, size_t height); - virtual void reset(); // zero-fill or 1-fill as appropriate without changing size - - virtual float getMagnitudeAt(size_t x, size_t y) const; - virtual float getNormalizedMagnitudeAt(size_t x, size_t y) const; - virtual float getPhaseAt(size_t x, size_t y) const; - - virtual void setNormalizationFactor(size_t x, float factor); - virtual void setMagnitudeAt(size_t x, size_t y, float mag); - virtual void setNormalizedMagnitudeAt(size_t x, size_t y, float norm); - virtual void setPhaseAt(size_t x, size_t y, float phase); - - //!!! not thread safe (but then neither is m_mfc) - virtual void setColumnAt(size_t x, float *mags, float *phases, float factor); - -protected: - float *m_colbuf; - MatrixFile *m_mfc; -}; - -#endif diff -r ce1d385f4f89 -r 0a846f83a4b7 base/FileReadThread.cpp --- a/base/FileReadThread.cpp Fri May 05 12:34:51 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "FileReadThread.h" - -#include -#include - -FileReadThread::FileReadThread() : - m_nextToken(0), - m_exiting(false) -{ -} - -void -FileReadThread::run() -{ - m_mutex.lock(); - - while (!m_exiting) { - if (m_queue.empty()) { - m_condition.wait(&m_mutex, 1000); - } else { - process(); - } - notifyCancelled(); - } - - notifyCancelled(); - m_mutex.unlock(); - - std::cerr << "FileReadThread::run() exiting" << std::endl; -} - -void -FileReadThread::finish() -{ - std::cerr << "FileReadThread::finish()" << std::endl; - - m_mutex.lock(); - while (!m_queue.empty()) { - m_cancelledRequests[m_queue.begin()->first] = m_queue.begin()->second; - m_newlyCancelled.insert(m_queue.begin()->first); - m_queue.erase(m_queue.begin()); - } - - m_exiting = true; - m_mutex.unlock(); - - m_condition.wakeAll(); - - std::cerr << "FileReadThread::finish() exiting" << std::endl; -} - -int -FileReadThread::request(const Request &request) -{ - m_mutex.lock(); - - int token = m_nextToken++; - m_queue[token] = request; - - m_mutex.unlock(); - m_condition.wakeAll(); - - return token; -} - -void -FileReadThread::cancel(int token) -{ - m_mutex.lock(); - - if (m_queue.find(token) != m_queue.end()) { - m_cancelledRequests[token] = m_queue[token]; - m_queue.erase(token); - m_newlyCancelled.insert(token); - } else if (m_readyRequests.find(token) != m_readyRequests.end()) { - m_cancelledRequests[token] = m_readyRequests[token]; - m_readyRequests.erase(token); - } else { - std::cerr << "WARNING: FileReadThread::cancel: token " << token << " not found" << std::endl; - } - - m_mutex.unlock(); - - std::cerr << "FileReadThread::cancel(" << token << ") waking condition" << std::endl; - - m_condition.wakeAll(); -} - -bool -FileReadThread::isReady(int token) -{ - m_mutex.lock(); - - bool ready = m_readyRequests.find(token) != m_readyRequests.end(); - - m_mutex.unlock(); - return ready; -} - -bool -FileReadThread::isCancelled(int token) -{ - m_mutex.lock(); - - bool cancelled = - m_cancelledRequests.find(token) != m_cancelledRequests.end() && - m_newlyCancelled.find(token) == m_newlyCancelled.end(); - - m_mutex.unlock(); - return cancelled; -} - -bool -FileReadThread::getRequest(int token, Request &request) -{ - m_mutex.lock(); - - bool found = false; - - if (m_queue.find(token) != m_queue.end()) { - request = m_queue[token]; - found = true; - } else if (m_cancelledRequests.find(token) != m_cancelledRequests.end()) { - request = m_cancelledRequests[token]; - found = true; - } else if (m_readyRequests.find(token) != m_readyRequests.end()) { - request = m_readyRequests[token]; - found = true; - } - - m_mutex.unlock(); - - return found; -} - -void -FileReadThread::done(int token) -{ - m_mutex.lock(); - - bool found = false; - - if (m_cancelledRequests.find(token) != m_cancelledRequests.end()) { - m_cancelledRequests.erase(token); - m_newlyCancelled.erase(token); - found = true; - } else if (m_readyRequests.find(token) != m_readyRequests.end()) { - m_readyRequests.erase(token); - found = true; - } else if (m_queue.find(token) != m_queue.end()) { - std::cerr << "WARNING: FileReadThread::done(" << token << "): request is still in queue (wait or cancel it)" << std::endl; - } - - m_mutex.unlock(); - - if (!found) { - std::cerr << "WARNING: FileReadThread::done(" << token << "): request not found" << std::endl; - } -} - -void -FileReadThread::process() -{ - // entered with m_mutex locked and m_queue non-empty - - int token = m_queue.begin()->first; - Request request = m_queue.begin()->second; - - m_mutex.unlock(); - - std::cerr << "FileReadThread::process: got something to do" << std::endl; - - bool successful = false; - bool seekFailed = false; - ssize_t r = 0; - - if (request.mutex) request.mutex->lock(); - - if (::lseek(request.fd, request.start, SEEK_SET) == (off_t)-1) { - seekFailed = true; - } else { - - // if request.size is large, we want to avoid making a single - // system call to read it all as it may block too much - - static const size_t blockSize = 16384; - - size_t size = request.size; - char *destination = request.data; - - while (size > 0) { - size_t readSize = size; - if (readSize > blockSize) readSize = blockSize; - ssize_t br = ::read(request.fd, destination, readSize); - if (br < 0) { - r = br; - break; - } else { - r += br; - if (br < ssize_t(readSize)) break; - } - destination += readSize; - size -= readSize; - } - } - - if (request.mutex) request.mutex->unlock(); - - if (seekFailed) { - ::perror("Seek failed"); - std::cerr << "ERROR: FileReadThread::process: seek to " - << request.start << " failed" << std::endl; - request.size = 0; - } else { - if (r < 0) { - ::perror("ERROR: FileReadThread::process: Read failed"); - request.size = 0; - } else if (r < ssize_t(request.size)) { - std::cerr << "WARNING: FileReadThread::process: read " - << request.size << " returned only " << r << " bytes" - << std::endl; - request.size = r; - } else { - successful = true; - } - } - - // Check that the token hasn't been cancelled and the thread - // hasn't been asked to finish - - m_mutex.lock(); - - if (m_queue.find(token) != m_queue.end() && !m_exiting) { - m_queue.erase(token); - m_readyRequests[token] = request; - m_mutex.unlock(); - std::cerr << "emitting" << std::endl; - emit ready(token, successful); - m_mutex.lock(); - } -} - -void -FileReadThread::notifyCancelled() -{ - // entered with m_mutex locked - - while (!m_newlyCancelled.empty()) { - - int token = *m_newlyCancelled.begin(); - - std::cerr << "FileReadThread::notifyCancelled: token " << token << std::endl; - - m_newlyCancelled.erase(token); - emit cancelled(token); - } -} - - diff -r ce1d385f4f89 -r 0a846f83a4b7 base/FileReadThread.h --- a/base/FileReadThread.h Fri May 05 12:34:51 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _FILE_READ_THREAD_H_ -#define _FILE_READ_THREAD_H_ - -#include "NonRTThread.h" - -#include -#include - -#include -#include - -#include - -class FileReadThread : public NonRTThread -{ - Q_OBJECT - -public: - FileReadThread(); - - virtual void run(); - virtual void finish(); - - struct Request { - int fd; - QMutex *mutex; // used to synchronise access to fd; may be null - off_t start; - size_t size; - char *data; // caller is responsible for allocating and deallocating - }; - - virtual int request(const Request &request); - virtual void cancel(int token); - - virtual bool isReady(int token); - virtual bool isCancelled(int token); // and safe to delete - virtual bool getRequest(int token, Request &request); - virtual void done(int token); - -signals: - void ready(int token, bool successful); - void cancelled(int token); - -protected: - int m_nextToken; - bool m_exiting; - - typedef std::map RequestQueue; - RequestQueue m_queue; - RequestQueue m_cancelledRequests; - RequestQueue m_readyRequests; - std::set m_newlyCancelled; - - QMutex m_mutex; - QWaitCondition m_condition; - - void process(); - void notifyCancelled(); -}; - -#endif diff -r ce1d385f4f89 -r 0a846f83a4b7 base/MatrixFile.cpp --- a/base/MatrixFile.cpp Fri May 05 12:34:51 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,470 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "MatrixFile.h" -#include "base/TempDirectory.h" -#include "base/System.h" - -#include -#include -#include -#include - -#include - -#include - -#include -#include - -std::map MatrixFile::m_refcount; -QMutex MatrixFile::m_refcountMutex; - -MatrixFile::MatrixFile(QString fileBase, Mode mode) : - m_fd(-1), - m_mode(mode), - m_width(0), - m_height(0), - m_headerSize(2 * sizeof(size_t)), - m_defaultCacheWidth(512), - m_prevX(0), - m_requestToken(-1), - m_spareData(0) -{ - m_cache.data = 0; - - QDir tempDir(TempDirectory::instance()->getPath()); - QString fileName(tempDir.filePath(QString("%1.mfc").arg(fileBase))); - bool newFile = !QFileInfo(fileName).exists(); - - if (newFile && mode == ReadOnly) { - std::cerr << "ERROR: MatrixFile::MatrixFile: Read-only mode " - << "specified, but cache file does not exist" << std::endl; - return; - } - - int flags = 0; - mode_t fmode = S_IRUSR | S_IWUSR; - - if (mode == ReadWrite) { - flags = O_RDWR | O_CREAT; - } else { - flags = O_RDONLY; - } - - if ((m_fd = ::open(fileName.toLocal8Bit(), flags, fmode)) < 0) { - ::perror("Open failed"); - std::cerr << "ERROR: MatrixFile::MatrixFile: " - << "Failed to open cache file \"" - << fileName.toStdString() << "\""; - if (mode == ReadWrite) std::cerr << " for writing"; - std::cerr << std::endl; - return; - } - - if (newFile) { - resize(0, 0); // write header - } else { - size_t header[2]; - if (::read(m_fd, header, 2 * sizeof(size_t)) < 0) { - perror("Read failed"); - std::cerr << "ERROR: MatrixFile::MatrixFile: " - << "Failed to read header (fd " << m_fd << ", file \"" - << fileName.toStdString() << "\")" << std::endl; - return; - } - m_width = header[0]; - m_height = header[1]; - seekTo(0, 0); - } - - m_fileName = fileName; - - m_readThread.start(); - - QMutexLocker locker(&m_refcountMutex); - ++m_refcount[fileName]; - - std::cerr << "MatrixFile::MatrixFile: Done, size is " << "(" << m_width << ", " << m_height << ")" << std::endl; - -} - -MatrixFile::~MatrixFile() -{ - float *requestData = 0; - - if (m_requestToken >= 0) { - FileReadThread::Request request; - if (m_readThread.getRequest(m_requestToken, request)) { - requestData = (float *)request.data; - } - } - - m_readThread.finish(); - m_readThread.wait(); - - if (requestData) free(requestData); - if (m_cache.data) free(m_cache.data); - if (m_spareData) free(m_spareData); - - if (m_fd >= 0) { - if (::close(m_fd) < 0) { - ::perror("MatrixFile::~MatrixFile: close failed"); - } - } - - if (m_fileName != "") { - QMutexLocker locker(&m_refcountMutex); - if (--m_refcount[m_fileName] == 0) { - if (::unlink(m_fileName.toLocal8Bit())) { - ::perror("Unlink failed"); - std::cerr << "WARNING: MatrixFile::~MatrixFile: reference count reached 0, but failed to unlink file \"" << m_fileName.toStdString() << "\"" << std::endl; - } else { - std::cerr << "deleted " << m_fileName.toStdString() << std::endl; - } - } - } -} - -size_t -MatrixFile::getWidth() const -{ - return m_width; -} - -size_t -MatrixFile::getHeight() const -{ - return m_height; -} - -void -MatrixFile::resize(size_t w, size_t h) -{ - if (m_mode != ReadWrite) { - std::cerr << "ERROR: MatrixFile::resize called on read-only cache" - << std::endl; - return; - } - - QMutexLocker locker(&m_fdMutex); - - off_t off = m_headerSize + (w * h * sizeof(float)); - - if (w * h > m_width * m_height) { - - if (::lseek(m_fd, off - sizeof(float), SEEK_SET) == (off_t)-1) { - ::perror("Seek failed"); - std::cerr << "ERROR: MatrixFile::resize(" << w << ", " - << h << "): seek failed, cannot resize" << std::endl; - return; - } - - // guess this requires efficient support for sparse files - - float f(0); - if (::write(m_fd, &f, sizeof(float)) != sizeof(float)) { - ::perror("WARNING: MatrixFile::resize: write failed"); - } - - } else { - - if (::ftruncate(m_fd, off) < 0) { - ::perror("WARNING: MatrixFile::resize: ftruncate failed"); - } - } - - m_width = 0; - m_height = 0; - - if (::lseek(m_fd, 0, SEEK_SET) == (off_t)-1) { - ::perror("ERROR: MatrixFile::resize: Seek to write header failed"); - return; - } - - size_t header[2]; - header[0] = w; - header[1] = h; - if (::write(m_fd, header, 2 * sizeof(size_t)) != 2 * sizeof(size_t)) { - ::perror("ERROR: MatrixFile::resize: Failed to write header"); - return; - } - - m_width = w; - m_height = h; - - seekTo(0, 0); -} - -void -MatrixFile::reset() -{ - if (m_mode != ReadWrite) { - std::cerr << "ERROR: MatrixFile::reset called on read-only cache" - << std::endl; - return; - } - - QMutexLocker locker(&m_fdMutex); - - float *emptyCol = new float[m_height]; - for (size_t y = 0; y < m_height; ++y) emptyCol[y] = 0.f; - - seekTo(0, 0); - for (size_t x = 0; x < m_width; ++x) setColumnAt(x, emptyCol); - - delete[] emptyCol; -} - -float -MatrixFile::getValueAt(size_t x, size_t y) -{ - float value = 0.f; - if (getValuesFromCache(x, y, 1, &value)) return value; - - ssize_t r = 0; - -// std::cout << "MatrixFile::getValueAt(" << x << ", " << y << ")" -// << ": reading the slow way" << std::endl; - - m_fdMutex.lock(); - - if (seekTo(x, y)) { - r = ::read(m_fd, &value, sizeof(float)); - } - - m_fdMutex.unlock(); - - if (r < 0) { - ::perror("MatrixFile::getValueAt: Read failed"); - } - if (r != sizeof(float)) { - value = 0.f; - } - - return value; -} - -void -MatrixFile::getColumnAt(size_t x, float *values) -{ - if (getValuesFromCache(x, 0, m_height, values)) return; - - ssize_t r = 0; - - std::cout << "MatrixFile::getColumnAt(" << x << ")" - << ": reading the slow way" << std::endl; - - m_fdMutex.lock(); - - if (seekTo(x, 0)) { - r = ::read(m_fd, values, m_height * sizeof(float)); - } - - m_fdMutex.unlock(); - - if (r < 0) { - ::perror("MatrixFile::getColumnAt: read failed"); - } -} - -bool -MatrixFile::getValuesFromCache(size_t x, size_t ystart, size_t ycount, - float *values) -{ - m_cacheMutex.lock(); - - if (!m_cache.data || x < m_cache.x || x >= m_cache.x + m_cache.width) { - bool left = (m_cache.data && x < m_cache.x); - m_cacheMutex.unlock(); - primeCache(x, left); // this doesn't take effect until a later callback - m_prevX = x; - return false; - } - - for (size_t y = ystart; y < ystart + ycount; ++y) { - values[y - ystart] = m_cache.data[(x - m_cache.x) * m_height + y]; - } - m_cacheMutex.unlock(); - - if (m_cache.x > 0 && x < m_prevX && x < m_cache.x + m_cache.width/4) { - primeCache(x, true); - } - - if (m_cache.x + m_cache.width < m_width && - x > m_prevX && - x > m_cache.x + (m_cache.width * 3) / 4) { - primeCache(x, false); - } - - m_prevX = x; - return true; -} - -void -MatrixFile::setValueAt(size_t x, size_t y, float value) -{ - if (m_mode != ReadWrite) { - std::cerr << "ERROR: MatrixFile::setValueAt called on read-only cache" - << std::endl; - return; - } - - ssize_t w = 0; - bool seekFailed = false; - - m_fdMutex.lock(); - - if (seekTo(x, y)) { - w = ::write(m_fd, &value, sizeof(float)); - } else { - seekFailed = true; - } - - m_fdMutex.unlock(); - - if (!seekFailed && w != sizeof(float)) { - ::perror("WARNING: MatrixFile::setValueAt: write failed"); - } - - //... update cache as appropriate -} - -void -MatrixFile::setColumnAt(size_t x, float *values) -{ - if (m_mode != ReadWrite) { - std::cerr << "ERROR: MatrixFile::setColumnAt called on read-only cache" - << std::endl; - return; - } - - ssize_t w = 0; - bool seekFailed = false; - - m_fdMutex.lock(); - - if (seekTo(x, 0)) { - w = ::write(m_fd, values, m_height * sizeof(float)); - } else { - seekFailed = true; - } - - m_fdMutex.unlock(); - - if (!seekFailed && w != ssize_t(m_height * sizeof(float))) { - ::perror("WARNING: MatrixFile::setColumnAt: write failed"); - } - - //... update cache as appropriate -} - -void -MatrixFile::primeCache(size_t x, bool goingLeft) -{ -// std::cerr << "MatrixFile::primeCache(" << x << ", " << goingLeft << ")" << std::endl; - - size_t rx = x; - size_t rw = m_defaultCacheWidth; - - size_t left = rw / 3; - if (goingLeft) left = (rw * 2) / 3; - - if (rx > left) rx -= left; - else rx = 0; - - if (rx + rw > m_width) rw = m_width - rx; - - QMutexLocker locker(&m_cacheMutex); - - FileReadThread::Request request; - - if (m_requestToken >= 0 && - m_readThread.getRequest(m_requestToken, request)) { - - if (x >= m_requestingX && - x < m_requestingX + m_requestingWidth) { - - if (m_readThread.isReady(m_requestToken)) { - - std::cerr << "last request is ready! (" << m_requestingX << ", "<< m_requestingWidth << ")" << std::endl; - - m_cache.x = (request.start - m_headerSize) / (m_height * sizeof(float)); - m_cache.width = request.size / (m_height * sizeof(float)); - - std::cerr << "actual: " << m_cache.x << ", " << m_cache.width << std::endl; - - if (m_cache.data) { - if (m_spareData) free(m_spareData); - m_spareData = (char *)m_cache.data; - } - m_cache.data = (float *)request.data; - - m_readThread.done(m_requestToken); - m_requestToken = -1; - } - - // already requested something covering this area; wait for it - return; - } - - // the current request is no longer of any use - m_readThread.cancel(m_requestToken); - - // crude way to avoid leaking the data - while (!m_readThread.isCancelled(m_requestToken)) { - usleep(10000); - } - - if (m_spareData) free(m_spareData); - m_spareData = request.data; - m_readThread.done(m_requestToken); - - m_requestToken = -1; - } - - request.fd = m_fd; - request.mutex = &m_fdMutex; - request.start = m_headerSize + rx * m_height * sizeof(float); - request.size = rw * m_height * sizeof(float); - request.data = (char *)realloc(m_spareData, rw * m_height * sizeof(float)); - MUNLOCK(request.data, rw * m_height * sizeof(float)); - m_spareData = 0; - - m_requestingX = rx; - m_requestingWidth = rw; - - int token = m_readThread.request(request); - std::cerr << "MatrixFile::primeCache: request token is " - << token << " (x = " << rx << ", w = " << rw << ", left = " << goingLeft << ")" << std::endl; - - m_requestToken = token; -} - -bool -MatrixFile::seekTo(size_t x, size_t y) -{ - off_t off = m_headerSize + (x * m_height + y) * sizeof(float); - - if (::lseek(m_fd, off, SEEK_SET) == (off_t)-1) { - ::perror("Seek failed"); - std::cerr << "ERROR: MatrixFile::seekTo(" << x << ", " << y - << ") failed" << std::endl; - return false; - } - - return true; -} - diff -r ce1d385f4f89 -r 0a846f83a4b7 base/MatrixFile.h --- a/base/MatrixFile.h Fri May 05 12:34:51 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _MATRIX_FILE_CACHE_H_ -#define _MATRIX_FILE_CACHE_H_ - -#include -#include -#include -#include - -#include "FileReadThread.h" - -class MatrixFile : public QObject -{ - Q_OBJECT - -public: - enum Mode { ReadOnly, ReadWrite }; - - MatrixFile(QString fileBase, Mode mode); - virtual ~MatrixFile(); - - size_t getWidth() const; - size_t getHeight() const; - - void resize(size_t width, size_t height); - void reset(); - - float getValueAt(size_t x, size_t y); - void getColumnAt(size_t x, float *values); - - void setValueAt(size_t x, size_t y, float value); - void setColumnAt(size_t x, float *values); - -protected: - int m_fd; - Mode m_mode; - size_t m_width; - size_t m_height; - size_t m_headerSize; - QString m_fileName; - size_t m_defaultCacheWidth; - size_t m_prevX; - - struct Cache { - size_t x; - size_t width; - float *data; - }; - - Cache m_cache; - - bool getValuesFromCache(size_t x, size_t ystart, size_t ycount, - float *values); - - void primeCache(size_t x, bool left); - - bool seekTo(size_t x, size_t y); - - FileReadThread m_readThread; - int m_requestToken; - - size_t m_requestingX; - size_t m_requestingWidth; - char *m_spareData; - - static std::map m_refcount; - static QMutex m_refcountMutex; - QMutex m_fdMutex; - QMutex m_cacheMutex; -}; - -#endif - diff -r ce1d385f4f89 -r 0a846f83a4b7 base/View.cpp --- a/base/View.cpp Fri May 05 12:34:51 2006 +0000 +++ b/base/View.cpp Fri May 05 13:06:47 2006 +0000 @@ -739,8 +739,13 @@ if (!visible) return; bool modifierPressed = // we only care about these ones - ((QApplication::keyboardModifiers() & Qt::ShiftModifier) || - (QApplication::keyboardModifiers() & Qt::ControlModifier)); + ((QApplication::keyboardModifiers() & Qt::ShiftModifier) +#ifndef Q_WS_MAC + /* OS/X reports that CtrlModifier is pressed after we've + imported a file with Apple+I even though we then released it */ + || (QApplication::keyboardModifiers() & Qt::ControlModifier) +#endif + ); switch (m_followPlay) { diff -r ce1d385f4f89 -r 0a846f83a4b7 transform/TransformFactory.cpp --- a/transform/TransformFactory.cpp Fri May 05 12:34:51 2006 +0000 +++ b/transform/TransformFactory.cpp Fri May 05 13:06:47 2006 +0000 @@ -175,7 +175,7 @@ !plugin->getParameterDescriptors().empty()); transforms[transformName] = - TransformDesc(tr("Analysis Plugin"), + TransformDesc(tr("Analysis Plugins"), transformName, userDescription, friendlyName, @@ -255,7 +255,7 @@ bool configurable = (descriptor->parameterCount > 0); transforms[transformName] = - TransformDesc(tr("Real-Time Plugin"), + TransformDesc(tr("Other Plugins"), transformName, userDescription, userDescription,