annotate Azi.cpp @ 35:299df1b44eff tip

Note source code available
author Chris Cannam
date Fri, 15 May 2020 09:40:50 +0100
parents 230562aa012d
children
rev   line source
Chris@0 1
Chris@0 2 #include "Azi.h"
Chris@0 3
Chris@1 4 #include <cmath>
Chris@3 5 #include <iostream>
Chris@7 6 #include <complex>
Chris@24 7 #include <algorithm>
Chris@25 8 #include <climits>
Chris@1 9
Chris@1 10 using std::vector;
Chris@7 11 using std::complex;
Chris@3 12 using std::cerr;
Chris@3 13 using std::endl;
Chris@0 14
Chris@0 15 Azi::Azi(float inputSampleRate) :
Chris@1 16 Plugin(inputSampleRate),
Chris@14 17 m_width(128)
Chris@0 18 {
Chris@0 19 }
Chris@0 20
Chris@0 21 Azi::~Azi()
Chris@0 22 {
Chris@0 23 }
Chris@0 24
Chris@0 25 string
Chris@0 26 Azi::getIdentifier() const
Chris@0 27 {
Chris@0 28 return "azi";
Chris@0 29 }
Chris@0 30
Chris@0 31 string
Chris@0 32 Azi::getName() const
Chris@0 33 {
Chris@0 34 return "Stereo Plan";
Chris@0 35 }
Chris@0 36
Chris@0 37 string
Chris@0 38 Azi::getDescription() const
Chris@0 39 {
Chris@29 40 return "Return a stereo plan decomposition of the audio. The returned feature grid covers the stereo plan from left-channel-only (first bin) to right-channel-only (last bin), with each value indicating what proportion of signal energy is found at that point on the plan at that moment. The input should consist of two channels containing left and right channel signals.";
Chris@0 41 }
Chris@0 42
Chris@0 43 string
Chris@0 44 Azi::getMaker() const
Chris@0 45 {
Chris@26 46 return "Chris Cannam";
Chris@0 47 }
Chris@0 48
Chris@0 49 int
Chris@0 50 Azi::getPluginVersion() const
Chris@0 51 {
Chris@0 52 // Increment this each time you release a version that behaves
Chris@0 53 // differently from the previous one
Chris@0 54 return 1;
Chris@0 55 }
Chris@0 56
Chris@0 57 string
Chris@0 58 Azi::getCopyright() const
Chris@0 59 {
Chris@29 60 return "Freely redistributable (BSD license)";
Chris@0 61 }
Chris@0 62
Chris@0 63 Azi::InputDomain
Chris@0 64 Azi::getInputDomain() const
Chris@0 65 {
Chris@10 66 return FrequencyDomain;
Chris@0 67 }
Chris@0 68
Chris@0 69 size_t
Chris@0 70 Azi::getPreferredBlockSize() const
Chris@0 71 {
Chris@12 72 return 8192;
Chris@0 73 }
Chris@0 74
Chris@0 75 size_t
Chris@0 76 Azi::getPreferredStepSize() const
Chris@0 77 {
Chris@12 78 return 256;
Chris@0 79 }
Chris@0 80
Chris@0 81 size_t
Chris@0 82 Azi::getMinChannelCount() const
Chris@0 83 {
Chris@25 84 return 1; // pointless, but supported
Chris@0 85 }
Chris@0 86
Chris@0 87 size_t
Chris@0 88 Azi::getMaxChannelCount() const
Chris@0 89 {
Chris@1 90 return 2;
Chris@0 91 }
Chris@0 92
Chris@0 93 Azi::ParameterList
Chris@0 94 Azi::getParameterDescriptors() const
Chris@0 95 {
Chris@0 96 ParameterList list;
Chris@0 97
Chris@0 98 // If the plugin has no adjustable parameters, return an empty
Chris@0 99 // list here (and there's no need to provide implementations of
Chris@0 100 // getParameter and setParameter in that case either).
Chris@0 101
Chris@0 102 // Note that it is your responsibility to make sure the parameters
Chris@0 103 // start off having their default values (e.g. in the constructor
Chris@0 104 // above). The host needs to know the default value so it can do
Chris@0 105 // things like provide a "reset to default" function, but it will
Chris@0 106 // not explicitly set your parameters to their defaults for you if
Chris@0 107 // they have not changed in the mean time.
Chris@0 108
Chris@0 109 return list;
Chris@0 110 }
Chris@0 111
Chris@0 112 float
Chris@25 113 Azi::getParameter(string) const
Chris@0 114 {
Chris@0 115 return 0;
Chris@0 116 }
Chris@0 117
Chris@0 118 void
Chris@25 119 Azi::setParameter(string, float)
Chris@0 120 {
Chris@0 121 }
Chris@0 122
Chris@0 123 Azi::ProgramList
Chris@0 124 Azi::getPrograms() const
Chris@0 125 {
Chris@0 126 ProgramList list;
Chris@0 127
Chris@0 128 // If you have no programs, return an empty list (or simply don't
Chris@0 129 // implement this function or getCurrentProgram/selectProgram)
Chris@0 130
Chris@0 131 return list;
Chris@0 132 }
Chris@0 133
Chris@0 134 string
Chris@0 135 Azi::getCurrentProgram() const
Chris@0 136 {
Chris@0 137 return ""; // no programs
Chris@0 138 }
Chris@0 139
Chris@0 140 void
Chris@25 141 Azi::selectProgram(string)
Chris@0 142 {
Chris@0 143 }
Chris@0 144
Chris@0 145 Azi::OutputList
Chris@0 146 Azi::getOutputDescriptors() const
Chris@0 147 {
Chris@0 148 OutputList list;
Chris@0 149
Chris@0 150 // See OutputDescriptor documentation for the possibilities here.
Chris@0 151 // Every plugin must have at least one output.
Chris@0 152
Chris@0 153 OutputDescriptor d;
Chris@1 154 d.identifier = "plan";
Chris@1 155 d.name = "Plan";
Chris@0 156 d.description = "";
Chris@0 157 d.unit = "";
Chris@0 158 d.hasFixedBinCount = true;
Chris@16 159 d.binCount = m_width * 2 + 3; // include a 1-bin "margin" at top and bottom
Chris@0 160 d.hasKnownExtents = false;
Chris@0 161 d.isQuantized = false;
Chris@0 162 d.sampleType = OutputDescriptor::OneSamplePerStep;
Chris@0 163 d.hasDuration = false;
Chris@27 164
Chris@27 165 char buf[100];
Chris@28 166 for (int i = 0; i < int(d.binCount); ++i) {
Chris@27 167 if (i == 0) {
Chris@27 168 d.binNames.push_back("Left");
Chris@28 169 } else if (i + 1 == int(d.binCount)) {
Chris@27 170 d.binNames.push_back("Right");
Chris@27 171 } else if (i == m_width + 1) {
Chris@27 172 d.binNames.push_back("Centre");
Chris@27 173 } else {
Chris@27 174 int p = int(round(double(i - m_width - 1) /
Chris@27 175 double(m_width) * 100.0));
Chris@27 176 if (p > 0) {
Chris@27 177 sprintf(buf, "R %03d", p);
Chris@27 178 } else {
Chris@27 179 sprintf(buf, "L %03d", -p);
Chris@27 180 }
Chris@27 181 d.binNames.push_back(buf);
Chris@27 182 }
Chris@27 183 }
Chris@27 184
Chris@0 185 list.push_back(d);
Chris@0 186
Chris@0 187 return list;
Chris@0 188 }
Chris@0 189
Chris@0 190 bool
Chris@25 191 Azi::initialise(size_t channels, size_t, size_t blockSize)
Chris@0 192 {
Chris@0 193 if (channels < getMinChannelCount() ||
Chris@0 194 channels > getMaxChannelCount()) return false;
Chris@0 195
Chris@25 196 if (blockSize > INT_MAX) return false;
Chris@25 197
Chris@25 198 m_channels = int(channels);
Chris@25 199 m_blockSize = int(blockSize);
Chris@0 200
Chris@0 201 return true;
Chris@0 202 }
Chris@0 203
Chris@0 204 void
Chris@0 205 Azi::reset()
Chris@0 206 {
Chris@0 207 // Clear buffers, reset stored values, etc
Chris@0 208 }
Chris@0 209
Chris@1 210 float
Chris@3 211 Azi::rms(const vector<float> &buffer)
Chris@1 212 {
Chris@1 213 float sum = 0;
Chris@3 214 for (int i = 0; i < int(buffer.size()); ++i) {
Chris@1 215 sum += buffer[i] * buffer[i];
Chris@1 216 }
Chris@25 217 return sqrtf(sum / float(buffer.size()));
Chris@1 218 }
Chris@1 219
Chris@0 220 Azi::FeatureSet
Chris@25 221 Azi::process(const float *const *inputBuffers, Vamp::RealTime)
Chris@0 222 {
Chris@8 223 vector<float> left, right;
Chris@13 224
Chris@13 225 int n = int(m_blockSize/2 + 1);
Chris@13 226
Chris@14 227 vector<float> plan(m_width * 2 + 3, 0.f);
Chris@14 228
Chris@14 229 const float *inleft = inputBuffers[0];
Chris@25 230 const float *inright = (m_channels == 2 ? inputBuffers[1] : inleft);
Chris@13 231
Chris@13 232 for (int i = 0; i < n; ++i) {
Chris@13 233
Chris@13 234 int ri = i*2, ii = i*2 + 1;
Chris@13 235
Chris@14 236 float lmag = sqrtf(inleft[ri] * inleft[ri] + inleft[ii] * inleft[ii]);
Chris@14 237 float rmag = sqrtf(inright[ri] * inright[ri] + inright[ii] * inright[ii]);
Chris@13 238
Chris@13 239 // lmag = 0.0, rmag = 1.0 -> min cancelled is at +1.0
Chris@13 240 // lmag = 1.0, rmag = 0.0 -> at -1.0 [val at 0.0 = 1.0]
Chris@13 241 // lmag = 0.5, rmag = 0.2 -> at -0.6 [val at 0.0 = 0.3]
Chris@13 242 // lmag = 0.5, rmag = 1.0 -> at +0.5 [val at 0.0 = 0.5]
Chris@13 243 // lmag = 1.0, rmag = 1.0 -> at +0.0
Chris@13 244
Chris@13 245 // if lmag == rmag -> 0.0
Chris@13 246 // else if lmag > rmag -> negative
Chris@13 247 // else -> positive
Chris@13 248
Chris@13 249 // val at 0.0 = larger - smaller
Chris@13 250 // mag of null = 1.0 - (smaller / larger)
Chris@13 251
Chris@13 252 float larger = std::max(lmag, rmag);
Chris@13 253 float smaller = std::min(lmag, rmag);
Chris@13 254
Chris@14 255 float pan = 0.0;
Chris@13 256
Chris@13 257 if (larger > smaller) {
Chris@25 258 float abspan = 1.f - (smaller / larger);
Chris@14 259 if (lmag > rmag) pan = -abspan;
Chris@14 260 else pan = abspan;
Chris@13 261 }
Chris@13 262
Chris@14 263 float leftGain = 1.f, rightGain = 1.f;
Chris@14 264 if (pan > 0.f) leftGain *= 1.f - pan;
Chris@14 265 if (pan < 0.f) rightGain *= pan + 1.f;
Chris@13 266
Chris@25 267 float wid = float(m_width);
Chris@25 268 float pos = -pan * wid + wid;
Chris@14 269 float mag = leftGain * lmag + rightGain * rmag;
Chris@13 270
Chris@14 271 float ipos = floorf(pos);
Chris@14 272
Chris@14 273 plan[int(ipos) + 1] += mag * (1.f - (pos - ipos));
Chris@14 274 plan[int(ipos) + 2] += mag * (pos - ipos);
Chris@3 275 }
Chris@1 276
Chris@2 277 FeatureSet fs;
Chris@2 278 Feature f;
Chris@7 279 f.values = plan;
Chris@1 280
Chris@1 281 fs[0].push_back(f);
Chris@1 282
Chris@1 283 return fs;
Chris@0 284 }
Chris@0 285
Chris@0 286 Azi::FeatureSet
Chris@0 287 Azi::getRemainingFeatures()
Chris@0 288 {
Chris@0 289 return FeatureSet();
Chris@0 290 }
Chris@0 291