annotate base/Window.h @ 1520:954d0cf29ca7 import-audio-data

Switch the normalisation option in WritableWaveFileModel from normalising on read to normalising on write, so that the saved file is already normalised and therefore can be read again without having to remember to normalise it
author Chris Cannam
date Wed, 12 Sep 2018 13:56:56 +0100
parents 48e9f538e6e9
children ad5f892c0c4d
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@52 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #ifndef _WINDOW_H_
Chris@0 17 #define _WINDOW_H_
Chris@0 18
Chris@0 19 #include <cmath>
Chris@0 20 #include <iostream>
Chris@350 21 #include <string>
Chris@0 22 #include <map>
Chris@402 23 #include <cstdlib>
Chris@0 24
Chris@1270 25 #include <bqvec/VectorOps.h>
Chris@1270 26 #include <bqvec/Allocators.h>
Chris@1270 27
Chris@1059 28 #include "system/System.h"
Chris@405 29
Chris@0 30 enum WindowType {
Chris@0 31 RectangularWindow,
Chris@0 32 BartlettWindow,
Chris@0 33 HammingWindow,
Chris@0 34 HanningWindow,
Chris@0 35 BlackmanWindow,
Chris@0 36 GaussianWindow,
Chris@142 37 ParzenWindow,
Chris@142 38 NuttallWindow,
Chris@142 39 BlackmanHarrisWindow
Chris@0 40 };
Chris@0 41
Chris@0 42 template <typename T>
Chris@0 43 class Window
Chris@0 44 {
Chris@0 45 public:
Chris@0 46 /**
Chris@813 47 * Construct a windower of the given type and size.
Chris@813 48 *
Chris@813 49 * Note that the cosine windows are periodic by design, rather
Chris@813 50 * than symmetrical. (A window of size N is equivalent to a
Chris@813 51 * symmetrical window of size N+1 with the final element missing.)
Chris@0 52 */
Chris@1270 53 Window(WindowType type, int size) : m_type(type), m_size(size), m_cache(0) {
Chris@1270 54 encache();
Chris@1270 55 }
Chris@1270 56 Window(const Window &w) : m_type(w.m_type), m_size(w.m_size), m_cache(0) {
Chris@1270 57 encache();
Chris@1270 58 }
Chris@0 59 Window &operator=(const Window &w) {
Chris@1429 60 if (&w == this) return *this;
Chris@1429 61 m_type = w.m_type;
Chris@1429 62 m_size = w.m_size;
Chris@1429 63 encache();
Chris@1429 64 return *this;
Chris@0 65 }
Chris@1270 66 virtual ~Window() {
Chris@1270 67 breakfastquay::deallocate(m_cache);
Chris@1270 68 }
Chris@0 69
Chris@1270 70 inline void cut(T *const BQ_R__ block) const {
Chris@1270 71 breakfastquay::v_multiply(block, m_cache, m_size);
Chris@1270 72 }
Chris@1270 73
Chris@1270 74 inline void cut(const T *const BQ_R__ src, T *const BQ_R__ dst) const {
Chris@1270 75 breakfastquay::v_multiply(dst, src, m_cache, m_size);
Chris@0 76 }
Chris@0 77
Chris@162 78 T getArea() { return m_area; }
Chris@928 79 T getValue(int i) { return m_cache[i]; }
Chris@140 80
Chris@0 81 WindowType getType() const { return m_type; }
Chris@928 82 int getSize() const { return m_size; }
Chris@0 83
Chris@350 84 // The names used by these functions are un-translated, for use in
Chris@350 85 // e.g. XML I/O. Use Preferences::getPropertyValueLabel if you
Chris@350 86 // want translated names for use in the user interface.
Chris@350 87 static std::string getNameForType(WindowType type);
Chris@350 88 static WindowType getTypeForName(std::string name);
Chris@350 89
Chris@0 90 protected:
Chris@0 91 WindowType m_type;
Chris@928 92 int m_size;
Chris@1270 93 T *BQ_R__ m_cache;
Chris@162 94 T m_area;
Chris@0 95
Chris@0 96 void encache();
Chris@1038 97 void cosinewin(T *, double, double, double, double);
Chris@0 98 };
Chris@0 99
Chris@0 100 template <typename T>
Chris@0 101 void Window<T>::encache()
Chris@0 102 {
Chris@1270 103 if (!m_cache) m_cache = breakfastquay::allocate<T>(m_size);
Chris@1270 104
Chris@928 105 const int n = m_size;
Chris@1270 106 breakfastquay::v_set(m_cache, T(1.0), n);
Chris@141 107 int i;
Chris@0 108
Chris@0 109 switch (m_type) {
Chris@1429 110
Chris@0 111 case RectangularWindow:
Chris@1429 112 for (i = 0; i < n; ++i) {
Chris@1429 113 m_cache[i] *= T(0.5);
Chris@1429 114 }
Chris@1429 115 break;
Chris@1429 116
Chris@0 117 case BartlettWindow:
Chris@1429 118 for (i = 0; i < n/2; ++i) {
Chris@1429 119 m_cache[i] *= T(i) / T(n/2);
Chris@1429 120 m_cache[i + n/2] *= T(1.0) - T(i) / T(n/2);
Chris@1429 121 }
Chris@1429 122 break;
Chris@1429 123
Chris@0 124 case HammingWindow:
Chris@1270 125 cosinewin(m_cache, 0.54, 0.46, 0.0, 0.0);
Chris@1429 126 break;
Chris@1429 127
Chris@0 128 case HanningWindow:
Chris@1270 129 cosinewin(m_cache, 0.50, 0.50, 0.0, 0.0);
Chris@1429 130 break;
Chris@1429 131
Chris@0 132 case BlackmanWindow:
Chris@1270 133 cosinewin(m_cache, 0.42, 0.50, 0.08, 0.0);
Chris@1429 134 break;
Chris@1429 135
Chris@0 136 case GaussianWindow:
Chris@1429 137 for (i = 0; i < n; ++i) {
Chris@1270 138 m_cache[i] *= T(pow(2, - pow((i - (n-1)/2.0) / ((n-1)/2.0 / 3), 2)));
Chris@1429 139 }
Chris@1429 140 break;
Chris@1429 141
Chris@0 142 case ParzenWindow:
Chris@141 143 {
Chris@141 144 int N = n-1;
Chris@141 145 for (i = 0; i < N/4; ++i) {
Chris@1038 146 T m = T(2 * pow(1.0 - (T(N)/2 - T(i)) / (T(N)/2), 3));
Chris@1270 147 m_cache[i] *= m;
Chris@1270 148 m_cache[N-i] *= m;
Chris@141 149 }
Chris@141 150 for (i = N/4; i <= N/2; ++i) {
Chris@141 151 int wn = i - N/2;
Chris@1038 152 T m = T(1.0 - 6 * pow(T(wn) / (T(N)/2), 2) * (1.0 - T(abs(wn)) / (T(N)/2)));
Chris@1270 153 m_cache[i] *= m;
Chris@1270 154 m_cache[N-i] *= m;
Chris@141 155 }
Chris@142 156 break;
Chris@142 157 }
Chris@142 158
Chris@142 159 case NuttallWindow:
Chris@1270 160 cosinewin(m_cache, 0.3635819, 0.4891775, 0.1365995, 0.0106411);
Chris@1429 161 break;
Chris@142 162
Chris@142 163 case BlackmanHarrisWindow:
Chris@1270 164 cosinewin(m_cache, 0.35875, 0.48829, 0.14128, 0.01168);
Chris@142 165 break;
Chris@0 166 }
Chris@1429 167
Chris@162 168 m_area = 0;
Chris@162 169 for (int i = 0; i < n; ++i) {
Chris@162 170 m_area += m_cache[i];
Chris@162 171 }
Chris@1038 172 m_area /= T(n);
Chris@0 173 }
Chris@0 174
Chris@142 175 template <typename T>
Chris@1038 176 void Window<T>::cosinewin(T *mult, double a0, double a1, double a2, double a3)
Chris@142 177 {
Chris@928 178 const int n = m_size;
Chris@142 179 for (int i = 0; i < n; ++i) {
Chris@1038 180 mult[i] *= T(a0
Chris@1038 181 - a1 * cos((2 * M_PI * i) / n)
Chris@1038 182 + a2 * cos((4 * M_PI * i) / n)
Chris@1038 183 - a3 * cos((6 * M_PI * i) / n));
Chris@142 184 }
Chris@142 185 }
Chris@142 186
Chris@350 187 template <typename T>
Chris@350 188 std::string
Chris@350 189 Window<T>::getNameForType(WindowType type)
Chris@350 190 {
Chris@350 191 switch (type) {
Chris@350 192 case RectangularWindow: return "rectangular";
Chris@350 193 case BartlettWindow: return "bartlett";
Chris@350 194 case HammingWindow: return "hamming";
Chris@350 195 case HanningWindow: return "hanning";
Chris@350 196 case BlackmanWindow: return "blackman";
Chris@350 197 case GaussianWindow: return "gaussian";
Chris@350 198 case ParzenWindow: return "parzen";
Chris@350 199 case NuttallWindow: return "nuttall";
Chris@350 200 case BlackmanHarrisWindow: return "blackman-harris";
Chris@350 201 }
Chris@350 202
Chris@350 203 std::cerr << "WARNING: Window::getNameForType: unknown type "
Chris@350 204 << type << std::endl;
Chris@350 205
Chris@350 206 return "unknown";
Chris@350 207 }
Chris@350 208
Chris@350 209 template <typename T>
Chris@350 210 WindowType
Chris@350 211 Window<T>::getTypeForName(std::string name)
Chris@350 212 {
Chris@350 213 if (name == "rectangular") return RectangularWindow;
Chris@350 214 if (name == "bartlett") return BartlettWindow;
Chris@350 215 if (name == "hamming") return HammingWindow;
Chris@350 216 if (name == "hanning") return HanningWindow;
Chris@350 217 if (name == "blackman") return BlackmanWindow;
Chris@350 218 if (name == "gaussian") return GaussianWindow;
Chris@350 219 if (name == "parzen") return ParzenWindow;
Chris@350 220 if (name == "nuttall") return NuttallWindow;
Chris@350 221 if (name == "blackman-harris") return BlackmanHarrisWindow;
Chris@350 222
Chris@350 223 std::cerr << "WARNING: Window::getTypeForName: unknown name \""
Chris@350 224 << name << "\", defaulting to \"hanning\"" << std::endl;
Chris@350 225
Chris@350 226 return HanningWindow;
Chris@350 227 }
Chris@350 228
Chris@0 229 #endif