Chris@159: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@159: 
Chris@159: /*
Chris@159:     Sonic Visualiser
Chris@159:     An audio file viewer and annotation editor.
Chris@159:     Centre for Digital Music, Queen Mary, University of London.
Chris@159:     This file copyright 2006 Chris Cannam.
Chris@159:     
Chris@159:     This program is free software; you can redistribute it and/or
Chris@159:     modify it under the terms of the GNU General Public License as
Chris@159:     published by the Free Software Foundation; either version 2 of the
Chris@159:     License, or (at your option) any later version.  See the file
Chris@159:     COPYING included with this distribution for more information.
Chris@159: */
Chris@159: 
Chris@159: #include "FFTMemoryCache.h"
Chris@159: #include "system/System.h"
Chris@159: 
Chris@159: #include <iostream>
Chris@537: #include <cstdlib>
Chris@159: 
Chris@374: //#define DEBUG_FFT_MEMORY_CACHE 1
Chris@374: 
Chris@537: FFTMemoryCache::FFTMemoryCache(FFTCache::StorageType storageType,
Chris@929:                                int width, int height) :
Chris@537:     m_width(width),
Chris@537:     m_height(height),
Chris@159:     m_magnitude(0),
Chris@159:     m_phase(0),
Chris@264:     m_fmagnitude(0),
Chris@264:     m_fphase(0),
Chris@334:     m_freal(0),
Chris@334:     m_fimag(0),
Chris@264:     m_factor(0),
Chris@264:     m_storageType(storageType)
Chris@159: {
Chris@374: #ifdef DEBUG_FFT_MEMORY_CACHE
Chris@843:     cerr << "FFTMemoryCache[" << this << "]::FFTMemoryCache (type "
Chris@843:               << m_storageType << "), size " << m_width << "x" << m_height << endl;
Chris@374: #endif
Chris@537: 
Chris@537:     initialise();
Chris@159: }
Chris@159: 
Chris@159: FFTMemoryCache::~FFTMemoryCache()
Chris@159: {
Chris@374: #ifdef DEBUG_FFT_MEMORY_CACHE
Chris@843:     cerr << "FFTMemoryCache[" << this << "]::~FFTMemoryCache" << endl;
Chris@374: #endif
Chris@159: 
Chris@929:     for (int i = 0; i < m_width; ++i) {
Chris@159: 	if (m_magnitude && m_magnitude[i]) free(m_magnitude[i]);
Chris@159: 	if (m_phase && m_phase[i]) free(m_phase[i]);
Chris@264: 	if (m_fmagnitude && m_fmagnitude[i]) free(m_fmagnitude[i]);
Chris@264: 	if (m_fphase && m_fphase[i]) free(m_fphase[i]);
Chris@334:         if (m_freal && m_freal[i]) free(m_freal[i]);
Chris@334:         if (m_fimag && m_fimag[i]) free(m_fimag[i]);
Chris@159:     }
Chris@159: 
Chris@159:     if (m_magnitude) free(m_magnitude);
Chris@159:     if (m_phase) free(m_phase);
Chris@264:     if (m_fmagnitude) free(m_fmagnitude);
Chris@264:     if (m_fphase) free(m_fphase);
Chris@334:     if (m_freal) free(m_freal);
Chris@334:     if (m_fimag) free(m_fimag);
Chris@159:     if (m_factor) free(m_factor);
Chris@159: }
Chris@159: 
Chris@159: void
Chris@537: FFTMemoryCache::initialise()
Chris@159: {
Chris@537:     Profiler profiler("FFTMemoryCache::initialise");
Chris@537: 
Chris@929:     int width = m_width, height = m_height;
Chris@408: 
Chris@374: #ifdef DEBUG_FFT_MEMORY_CACHE
Chris@843:     cerr << "FFTMemoryCache[" << this << "]::initialise(" << width << "x" << height << " = " << width*height << ")" << endl;
Chris@374: #endif
Chris@159: 
Chris@537:     if (m_storageType == FFTCache::Compact) {
Chris@537:         initialise(m_magnitude);
Chris@537:         initialise(m_phase);
Chris@537:     } else if (m_storageType == FFTCache::Polar) {
Chris@537:         initialise(m_fmagnitude);
Chris@537:         initialise(m_fphase);
Chris@334:     } else {
Chris@537:         initialise(m_freal);
Chris@537:         initialise(m_fimag);
Chris@264:     }
Chris@264: 
Chris@159:     m_colset.resize(width);
Chris@159: 
Chris@159:     m_factor = (float *)realloc(m_factor, width * sizeof(float));
Chris@159: 
Chris@159:     m_width = width;
Chris@159:     m_height = height;
Chris@159: 
Chris@374: #ifdef DEBUG_FFT_MEMORY_CACHE
Chris@843:     cerr << "done, width = " << m_width << " height = " << m_height << endl;
Chris@374: #endif
Chris@159: }
Chris@159: 
Chris@159: void
Chris@537: FFTMemoryCache::initialise(uint16_t **&array)
Chris@159: {
Chris@537:     array = (uint16_t **)malloc(m_width * sizeof(uint16_t *));
Chris@537:     if (!array) throw std::bad_alloc();
Chris@537:     MUNLOCK(array, m_width * sizeof(uint16_t *));
Chris@159: 
Chris@929:     for (int i = 0; i < m_width; ++i) {
Chris@537: 	array[i] = (uint16_t *)malloc(m_height * sizeof(uint16_t));
Chris@159: 	if (!array[i]) throw std::bad_alloc();
Chris@537: 	MUNLOCK(array[i], m_height * sizeof(uint16_t));
Chris@159:     }
Chris@159: }
Chris@159: 
Chris@159: void
Chris@537: FFTMemoryCache::initialise(float **&array)
Chris@264: {
Chris@537:     array = (float **)malloc(m_width * sizeof(float *));
Chris@537:     if (!array) throw std::bad_alloc();
Chris@537:     MUNLOCK(array, m_width * sizeof(float *));
Chris@264: 
Chris@929:     for (int i = 0; i < m_width; ++i) {
Chris@537: 	array[i] = (float *)malloc(m_height * sizeof(float));
Chris@264: 	if (!array[i]) throw std::bad_alloc();
Chris@537: 	MUNLOCK(array[i], m_height * sizeof(float));
Chris@264:     }
Chris@264: }
Chris@264: 
Chris@264: void
Chris@929: FFTMemoryCache::setColumnAt(int x, float *mags, float *phases, float factor)
Chris@334: {
Chris@408:     Profiler profiler("FFTMemoryCache::setColumnAt: from polar");
Chris@408: 
Chris@334:     setNormalizationFactor(x, factor);
Chris@334: 
Chris@537:     if (m_storageType == FFTCache::Rectangular) {
Chris@408:         Profiler subprof("FFTMemoryCache::setColumnAt: polar to cart");
Chris@929:         for (int y = 0; y < m_height; ++y) {
Chris@334:             m_freal[x][y] = mags[y] * cosf(phases[y]);
Chris@334:             m_fimag[x][y] = mags[y] * sinf(phases[y]);
Chris@334:         }
Chris@334:     } else {
Chris@929:         for (int y = 0; y < m_height; ++y) {
Chris@334:             setMagnitudeAt(x, y, mags[y]);
Chris@334:             setPhaseAt(x, y, phases[y]);
Chris@334:         }
Chris@334:     }
Chris@334: 
Chris@548:     m_colsetLock.lockForWrite();
Chris@334:     m_colset.set(x);
Chris@548:     m_colsetLock.unlock();
Chris@334: }
Chris@334: 
Chris@334: void
Chris@929: FFTMemoryCache::setColumnAt(int x, float *reals, float *imags)
Chris@159: {
Chris@408:     Profiler profiler("FFTMemoryCache::setColumnAt: from cart");
Chris@408: 
Chris@159:     float max = 0.0;
Chris@159: 
Chris@264:     switch (m_storageType) {
Chris@264: 
Chris@537:     case FFTCache::Rectangular:
Chris@929:         for (int y = 0; y < m_height; ++y) {
Chris@334:             m_freal[x][y] = reals[y];
Chris@334:             m_fimag[x][y] = imags[y];
Chris@334:             float mag = sqrtf(reals[y] * reals[y] + imags[y] * imags[y]);
Chris@334:             if (mag > max) max = mag;
Chris@334:         }
Chris@334:         break;
Chris@334: 
Chris@537:     case FFTCache::Compact:
Chris@537:     case FFTCache::Polar:
Chris@408:     {
Chris@408:         Profiler subprof("FFTMemoryCache::setColumnAt: cart to polar");
Chris@929:         for (int y = 0; y < m_height; ++y) {
Chris@264:             float mag = sqrtf(reals[y] * reals[y] + imags[y] * imags[y]);
Chris@264:             float phase = atan2f(imags[y], reals[y]);
Chris@264:             reals[y] = mag;
Chris@264:             imags[y] = phase;
Chris@264:             if (mag > max) max = mag;
Chris@264:         }
Chris@264:         break;
Chris@408:     }
Chris@264:     };
Chris@159: 
Chris@537:     if (m_storageType == FFTCache::Rectangular) {
Chris@334:         m_factor[x] = max;
Chris@548:         m_colsetLock.lockForWrite();
Chris@334:         m_colset.set(x);
Chris@548:         m_colsetLock.unlock();
Chris@334:     } else {
Chris@334:         setColumnAt(x, reals, imags, max);
Chris@334:     }
Chris@159: }
Chris@159: 
Chris@929: int
Chris@929: FFTMemoryCache::getCacheSize(int width, int height, FFTCache::StorageType type)
Chris@170: {
Chris@929:     int sz = 0;
Chris@264: 
Chris@264:     switch (type) {
Chris@264: 
Chris@537:     case FFTCache::Compact:
Chris@264:         sz = (height * 2 + 1) * width * sizeof(uint16_t);
Chris@264: 
Chris@537:     case FFTCache::Polar:
Chris@537:     case FFTCache::Rectangular:
Chris@264:         sz = (height * 2 + 1) * width * sizeof(float);
Chris@264:     }
Chris@264: 
Chris@264:     return sz;
Chris@170: }
Chris@170: