Chris@537: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@537: Chris@537: /* Chris@537: Sonic Visualiser Chris@537: An audio file viewer and annotation editor. Chris@537: Centre for Digital Music, Queen Mary, University of London. Chris@537: This file copyright 2006-2009 Chris Cannam and QMUL. Chris@537: Chris@537: This program is free software; you can redistribute it and/or Chris@537: modify it under the terms of the GNU General Public License as Chris@537: published by the Free Software Foundation; either version 2 of the Chris@537: License, or (at your option) any later version. See the file Chris@537: COPYING included with this distribution for more information. Chris@537: */ Chris@537: Chris@537: #include "FFTFileCacheWriter.h" Chris@537: Chris@537: #include "fileio/MatrixFile.h" Chris@537: Chris@537: #include "base/Profiler.h" Chris@537: #include "base/Thread.h" Chris@537: #include "base/Exceptions.h" Chris@537: Chris@537: #include Chris@537: Chris@537: //#define DEBUG_FFT_FILE_CACHE_WRITER 1 Chris@537: Chris@537: Chris@537: // The underlying matrix has height (m_height * 2 + 1). In each Chris@537: // column we store magnitude at [0], [2] etc and phase at [1], [3] Chris@537: // etc, and then store the normalization factor (maximum magnitude) at Chris@537: // [m_height * 2]. In compact mode, the factor takes two cells. Chris@537: Chris@537: FFTFileCacheWriter::FFTFileCacheWriter(QString fileBase, Chris@537: FFTCache::StorageType storageType, Chris@929: int width, int height) : Chris@537: m_writebuf(0), Chris@537: m_fileBase(fileBase), Chris@537: m_storageType(storageType), Chris@537: m_factorSize(storageType == FFTCache::Compact ? 2 : 1), Chris@537: m_mfc(new MatrixFile Chris@537: (fileBase, MatrixFile::WriteOnly, Chris@1038: int((storageType == FFTCache::Compact) ? sizeof(uint16_t) : sizeof(float)), Chris@537: width, height * 2 + m_factorSize)) Chris@537: { Chris@577: #ifdef DEBUG_FFT_FILE_CACHE_WRITER Chris@843: cerr << "FFTFileCacheWriter: storage type is " << (storageType == FFTCache::Compact ? "Compact" : storageType == FFTCache::Polar ? "Polar" : "Rectangular") << ", size " << width << "x" << height << endl; Chris@577: #endif Chris@550: m_mfc->setAutoClose(true); Chris@537: m_writebuf = new char[(height * 2 + m_factorSize) * m_mfc->getCellSize()]; Chris@537: } Chris@537: Chris@537: FFTFileCacheWriter::~FFTFileCacheWriter() Chris@537: { Chris@537: if (m_writebuf) delete[] m_writebuf; Chris@537: delete m_mfc; Chris@537: } Chris@537: Chris@537: QString Chris@537: FFTFileCacheWriter::getFileBase() const Chris@537: { Chris@537: return m_fileBase; Chris@537: } Chris@537: Chris@929: int Chris@537: FFTFileCacheWriter::getWidth() const Chris@537: { Chris@537: return m_mfc->getWidth(); Chris@537: } Chris@537: Chris@929: int Chris@537: FFTFileCacheWriter::getHeight() const Chris@537: { Chris@929: int mh = m_mfc->getHeight(); Chris@537: if (mh > m_factorSize) return (mh - m_factorSize) / 2; Chris@537: else return 0; Chris@537: } Chris@537: Chris@550: bool Chris@929: FFTFileCacheWriter::haveSetColumnAt(int x) const Chris@550: { Chris@550: return m_mfc->haveSetColumnAt(x); Chris@550: } Chris@550: Chris@537: void Chris@929: FFTFileCacheWriter::setColumnAt(int x, float *mags, float *phases, float factor) Chris@537: { Chris@929: int h = getHeight(); Chris@537: Chris@537: switch (m_storageType) { Chris@537: Chris@537: case FFTCache::Compact: Chris@929: for (int y = 0; y < h; ++y) { Chris@537: ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mags[y] / factor) * 65535.0); Chris@537: ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phases[y] * 32767) / M_PI)); Chris@537: } Chris@537: break; Chris@537: Chris@537: case FFTCache::Rectangular: Chris@929: for (int y = 0; y < h; ++y) { Chris@537: ((float *)m_writebuf)[y * 2] = mags[y] * cosf(phases[y]); Chris@537: ((float *)m_writebuf)[y * 2 + 1] = mags[y] * sinf(phases[y]); Chris@537: } Chris@537: break; Chris@537: Chris@537: case FFTCache::Polar: Chris@929: for (int y = 0; y < h; ++y) { Chris@537: ((float *)m_writebuf)[y * 2] = mags[y]; Chris@537: ((float *)m_writebuf)[y * 2 + 1] = phases[y]; Chris@537: } Chris@537: break; Chris@537: } Chris@537: Chris@537: static float maxFactor = 0; Chris@537: if (factor > maxFactor) maxFactor = factor; Chris@537: #ifdef DEBUG_FFT_FILE_CACHE_WRITER Chris@843: cerr << "Column " << x << ": normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << endl; Chris@537: #endif Chris@537: Chris@537: setNormalizationFactorToWritebuf(factor); Chris@537: Chris@537: m_mfc->setColumnAt(x, m_writebuf); Chris@537: } Chris@537: Chris@537: void Chris@929: FFTFileCacheWriter::setColumnAt(int x, float *real, float *imag) Chris@537: { Chris@929: int h = getHeight(); Chris@537: Chris@537: float factor = 0.0f; Chris@537: Chris@537: switch (m_storageType) { Chris@537: Chris@537: case FFTCache::Compact: Chris@929: for (int y = 0; y < h; ++y) { Chris@537: float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]); Chris@537: if (mag > factor) factor = mag; Chris@537: } Chris@929: for (int y = 0; y < h; ++y) { Chris@537: float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]); Chris@537: float phase = atan2f(imag[y], real[y]); Chris@537: ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mag / factor) * 65535.0); Chris@537: ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phase * 32767) / M_PI)); Chris@537: } Chris@537: break; Chris@537: Chris@537: case FFTCache::Rectangular: Chris@929: for (int y = 0; y < h; ++y) { Chris@537: ((float *)m_writebuf)[y * 2] = real[y]; Chris@537: ((float *)m_writebuf)[y * 2 + 1] = imag[y]; Chris@537: float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]); Chris@537: if (mag > factor) factor = mag; Chris@537: } Chris@537: break; Chris@537: Chris@537: case FFTCache::Polar: Chris@929: for (int y = 0; y < h; ++y) { Chris@537: float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]); Chris@537: if (mag > factor) factor = mag; Chris@537: ((float *)m_writebuf)[y * 2] = mag; Chris@537: float phase = atan2f(imag[y], real[y]); Chris@537: ((float *)m_writebuf)[y * 2 + 1] = phase; Chris@537: } Chris@537: break; Chris@537: } Chris@537: Chris@537: static float maxFactor = 0; Chris@537: if (factor > maxFactor) maxFactor = factor; Chris@537: #ifdef DEBUG_FFT_FILE_CACHE_WRITER Chris@843: cerr << "[RI] Column " << x << ": normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << endl; Chris@537: #endif Chris@537: Chris@537: setNormalizationFactorToWritebuf(factor); Chris@537: Chris@537: m_mfc->setColumnAt(x, m_writebuf); Chris@537: } Chris@537: Chris@1038: size_t Chris@929: FFTFileCacheWriter::getCacheSize(int width, int height, Chris@537: FFTCache::StorageType type) Chris@537: { Chris@537: return (height * 2 + (type == FFTCache::Compact ? 2 : 1)) * width * Chris@537: (type == FFTCache::Compact ? sizeof(uint16_t) : sizeof(float)) + Chris@929: 2 * sizeof(int); // matrix file header size Chris@537: } Chris@537: Chris@537: void Chris@537: FFTFileCacheWriter::allColumnsWritten() Chris@537: { Chris@537: #ifdef DEBUG_FFT_FILE_CACHE_WRITER Chris@690: SVDEBUG << "FFTFileCacheWriter::allColumnsWritten" << endl; Chris@537: #endif Chris@537: m_mfc->close(); Chris@537: } Chris@537: