annotate chromamethods.cpp @ 144:0d70058c2bce

reinstated slash notation replacement for Harte syntax (maybe there are some cross version effects that result in Johan having different chord symbols... must check!)
author matthiasm
date Tue, 19 Jun 2012 16:28:16 +0100
parents 8ff2aa01df4d
children 2cd99c0810f2
rev   line source
Chris@35 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@35 2
Chris@35 3 /*
Chris@35 4 NNLS-Chroma / Chordino
Chris@35 5
Chris@35 6 Audio feature extraction plugins for chromagram and chord
Chris@35 7 estimation.
Chris@35 8
Chris@35 9 Centre for Digital Music, Queen Mary University of London.
Chris@35 10 This file copyright 2008-2010 Matthias Mauch and QMUL.
Chris@35 11
Chris@35 12 This program is free software; you can redistribute it and/or
Chris@35 13 modify it under the terms of the GNU General Public License as
Chris@35 14 published by the Free Software Foundation; either version 2 of the
Chris@35 15 License, or (at your option) any later version. See the file
Chris@35 16 COPYING included with this distribution for more information.
Chris@35 17 */
Chris@35 18
Chris@27 19 #include "chromamethods.h"
Chris@27 20
Chris@27 21 #include <cmath>
Chris@27 22 #include <list>
Chris@27 23 #include <iostream>
Chris@27 24 #include <fstream>
Chris@27 25 #include <sstream>
Chris@27 26 #include <cassert>
Chris@27 27 #include <cstdlib>
Chris@27 28 #include <cstdio>
Chris@27 29 #include <boost/tokenizer.hpp>
Chris@27 30 #include <boost/iostreams/device/file.hpp>
Chris@27 31 #include <boost/iostreams/stream.hpp>
Chris@27 32 #include <boost/lexical_cast.hpp>
Chris@27 33
Chris@27 34 using namespace std;
Chris@27 35 using namespace boost;
Chris@27 36
Chris@27 37
Chris@27 38 /** Special Convolution
mail@115 39 Special convolution is as long as the convolvee, i.e. the first argument.
mail@115 40 In the "valid" core part of the convolution it contains the usual convolution
mail@115 41 values, but the parts at the beginning (ending) that would normally be
mail@115 42 calculated using zero padding simply have the same values as the first
mail@115 43 (last) valid convolution bin.
Chris@27 44 **/
Chris@27 45
Chris@27 46 vector<float> SpecialConvolution(vector<float> convolvee, vector<float> kernel)
Chris@27 47 {
Chris@27 48 float s;
Chris@27 49 int m, n;
Chris@27 50 int lenConvolvee = convolvee.size();
Chris@27 51 int lenKernel = kernel.size();
Chris@27 52
mail@77 53 vector<float> Z(nNote,0);
Chris@27 54 assert(lenKernel % 2 != 0); // no exception handling !!!
Chris@27 55
Chris@27 56 for (n = lenKernel - 1; n < lenConvolvee; n++) {
Chris@27 57 s=0.0;
Chris@27 58 for (m = 0; m < lenKernel; m++) {
Chris@27 59 // cerr << "m = " << m << ", n = " << n << ", n-m = " << (n-m) << '\n';
Chris@27 60 s += convolvee[n-m] * kernel[m];
Chris@27 61 // if (debug_on) cerr << "--> s = " << s << '\n';
Chris@27 62 }
Chris@27 63 // cerr << n - lenKernel/2 << endl;
Chris@27 64 Z[n -lenKernel/2] = s;
Chris@27 65 }
Chris@27 66
Chris@27 67 // fill upper and lower pads
Chris@27 68 for (n = 0; n < lenKernel/2; n++) Z[n] = Z[lenKernel/2];
Chris@27 69 for (n = lenConvolvee; n < lenConvolvee +lenKernel/2; n++) Z[n - lenKernel/2] =
Chris@27 70 Z[lenConvolvee - lenKernel/2 - 1];
Chris@27 71 return Z;
Chris@27 72 }
Chris@27 73
Chris@27 74 float cospuls(float x, float centre, float width)
Chris@27 75 {
Chris@27 76 float recipwidth = 1.0/width;
Chris@27 77 if (abs(x - centre) <= 0.5 * width) {
Chris@27 78 return cos((x-centre)*2*M_PI*recipwidth)*.5+.5;
Chris@27 79 }
Chris@27 80 return 0.0;
Chris@27 81 }
Chris@27 82
Chris@27 83 float pitchCospuls(float x, float centre, int binsperoctave)
Chris@27 84 {
Chris@27 85 float warpedf = -binsperoctave * (log2(centre) - log2(x));
Chris@27 86 float out = cospuls(warpedf, 0.0, 2.0);
Chris@27 87 // now scale to correct for note density
Chris@27 88 float c = log(2.0)/binsperoctave;
Chris@27 89 if (x > 0) {
Chris@27 90 out = out / (c * x);
Chris@27 91 } else {
Chris@27 92 out = 0;
Chris@27 93 }
Chris@27 94 return out;
Chris@27 95 }
Chris@27 96
mail@115 97 /**
mail@115 98 * Calculates a matrix that can be used to linearly map from the magnitude spectrum to a pitch-scale spectrum.
mail@115 99 * @return this always returns true, which is a bit stupid, really. The main purpose of the function is to change the values in the "matrix" pointed to by *outmatrix
mail@115 100 */
Chris@27 101 bool logFreqMatrix(int fs, int blocksize, float *outmatrix) {
mail@115 102 // TODO: rewrite so that everyone understands what is done here.
mail@115 103 // TODO: make this more general, such that it works with all minoctave, maxoctave and whatever nBPS (or check if it already does)
Chris@27 104
mail@80 105 int binspersemitone = nBPS;
Chris@27 106 int minoctave = 0; // this must be 0
Chris@27 107 int maxoctave = 7; // this must be 7
Chris@27 108 int oversampling = 80;
Chris@27 109
Chris@27 110 // linear frequency vector
Chris@27 111 vector<float> fft_f;
Chris@27 112 for (int i = 0; i < blocksize/2; ++i) {
Chris@27 113 fft_f.push_back(i * (fs * 1.0 / blocksize));
Chris@27 114 }
Chris@27 115 float fft_width = fs * 2.0 / blocksize;
Chris@27 116
Chris@27 117 // linear oversampled frequency vector
Chris@27 118 vector<float> oversampled_f;
Chris@91 119 for (int i = 0; i < oversampling * blocksize/2; ++i) {
Chris@27 120 oversampled_f.push_back(i * ((fs * 1.0 / blocksize) / oversampling));
Chris@27 121 }
Chris@27 122
Chris@27 123 // pitch-spaced frequency vector
Chris@27 124 int minMIDI = 21 + minoctave * 12 - 1; // this includes one additional semitone!
Chris@27 125 int maxMIDI = 21 + maxoctave * 12; // this includes one additional semitone!
Chris@27 126 vector<float> cq_f;
Chris@27 127 float oob = 1.0/binspersemitone; // one over binspersemitone
mail@80 128 for (int i = minMIDI; i < maxMIDI; ++i) {
mail@80 129 for (int k = 0; k < binspersemitone; ++k) {
Chris@27 130 cq_f.push_back(440 * pow(2.0,0.083333333333 * (i+oob*k-69)));
Chris@27 131 }
Chris@27 132 }
mail@80 133 // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI-oob-69)));
Chris@27 134 cq_f.push_back(440 * pow(2.0,0.083333 * (maxMIDI-69)));
Chris@27 135
Chris@27 136 int nFFT = fft_f.size();
Chris@27 137
Chris@27 138 vector<float> fft_activation;
Chris@27 139 for (int iOS = 0; iOS < 2 * oversampling; ++iOS) {
Chris@27 140 float cosp = cospuls(oversampled_f[iOS],fft_f[1],fft_width);
Chris@27 141 fft_activation.push_back(cosp);
Chris@27 142 // cerr << cosp << endl;
Chris@27 143 }
Chris@135 144
Chris@135 145 for (int i = 0; i < nFFT * cq_f.size(); ++i) {
Chris@135 146 outmatrix[i] = 0.f;
Chris@135 147 }
Chris@27 148
Chris@27 149 float cq_activation;
Chris@27 150 for (int iFFT = 1; iFFT < nFFT; ++iFFT) {
Chris@27 151 // find frequency stretch where the oversampled vector can be non-zero (i.e. in a window of width fft_width around the current frequency)
Chris@27 152 int curr_start = oversampling * iFFT - oversampling;
Chris@27 153 int curr_end = oversampling * iFFT + oversampling; // don't know if I should add "+1" here
Chris@27 154 // cerr << oversampled_f[curr_start] << " " << fft_f[iFFT] << " " << oversampled_f[curr_end] << endl;
matthiasm@122 155 for (int iCQ = 0; iCQ < (int)cq_f.size(); ++iCQ) {
Chris@27 156 if (cq_f[iCQ] * pow(2.0, 0.084) + fft_width > fft_f[iFFT] && cq_f[iCQ] * pow(2.0, -0.084 * 2) - fft_width < fft_f[iFFT]) { // within a generous neighbourhood
Chris@27 157 for (int iOS = curr_start; iOS < curr_end; ++iOS) {
Chris@27 158 cq_activation = pitchCospuls(oversampled_f[iOS],cq_f[iCQ],binspersemitone*12);
Chris@27 159 // cerr << oversampled_f[iOS] << " " << cq_f[iCQ] << " " << cq_activation << endl;
Chris@27 160 outmatrix[iFFT + nFFT * iCQ] += cq_activation * fft_activation[iOS-curr_start];
Chris@27 161 }
mail@115 162 }
Chris@27 163 }
Chris@27 164 }
Chris@27 165 return true;
Chris@27 166 }
Chris@27 167
mail@41 168 void dictionaryMatrix(float* dm, float s_param) {
mail@115 169 // TODO: make this more general, such that it works with all minoctave, maxoctave and even more than one note per semitone
mail@80 170 int binspersemitone = nBPS;
Chris@27 171 int minoctave = 0; // this must be 0
Chris@27 172 int maxoctave = 7; // this must be 7
Chris@27 173
Chris@27 174 // pitch-spaced frequency vector
Chris@27 175 int minMIDI = 21 + minoctave * 12 - 1; // this includes one additional semitone!
Chris@27 176 int maxMIDI = 21 + maxoctave * 12; // this includes one additional semitone!
Chris@27 177 vector<float> cq_f;
Chris@27 178 float oob = 1.0/binspersemitone; // one over binspersemitone
mail@80 179 for (int i = minMIDI; i < maxMIDI; ++i) {
mail@80 180 for (int k = 0; k < binspersemitone; ++k) {
Chris@27 181 cq_f.push_back(440 * pow(2.0,0.083333333333 * (i+oob*k-69)));
Chris@27 182 }
Chris@27 183 }
Chris@27 184 cq_f.push_back(440 * pow(2.0,0.083333 * (maxMIDI-69)));
Chris@27 185
Chris@27 186 float curr_f;
Chris@27 187 float floatbin;
Chris@27 188 float curr_amp;
Chris@27 189 // now for every combination calculate the matrix element
Chris@91 190 for (int iOut = 0; iOut < 12 * (maxoctave - minoctave); ++iOut) {
Chris@27 191 // cerr << iOut << endl;
Chris@91 192 for (int iHarm = 1; iHarm <= 20; ++iHarm) {
Chris@27 193 curr_f = 440 * pow(2,(minMIDI-69+iOut)*1.0/12) * iHarm;
Chris@27 194 // if (curr_f > cq_f[nNote-1]) break;
Chris@27 195 floatbin = ((iOut + 1) * binspersemitone + 1) + binspersemitone * 12 * log2(iHarm);
Chris@27 196 // cerr << floatbin << endl;
Chris@27 197 curr_amp = pow(s_param,float(iHarm-1));
Chris@27 198 // cerr << "curramp" << curr_amp << endl;
Chris@91 199 for (int iNote = 0; iNote < nNote; ++iNote) {
Chris@27 200 if (abs(iNote+1.0-floatbin)<2) {
mail@77 201 dm[iNote + nNote * iOut] += cospuls(iNote+1.0, floatbin, binspersemitone + 0.0) * curr_amp;
Chris@27 202 // dm[iNote + nNote * iOut] += 1 * curr_amp;
Chris@27 203 }
Chris@27 204 }
Chris@27 205 }
Chris@27 206 }
Chris@27 207 }
Chris@27 208
Chris@30 209 static
Chris@30 210 std::vector<std::string>
Chris@30 211 getPluginPath()
Chris@30 212 {
Chris@30 213 //!!! This is duplicated from PluginHostAdapter::getPluginPath,
Chris@30 214 //!!! which is not available to us in the plugin (only to the
Chris@30 215 //!!! host)
Chris@30 216
Chris@30 217 std::vector<std::string> path;
Chris@30 218 std::string envPath;
Chris@30 219
Chris@30 220 char *cpath = getenv("VAMP_PATH");
Chris@30 221 if (cpath) envPath = cpath;
Chris@30 222
Chris@30 223 #ifdef _WIN32
Chris@30 224 #define PATH_SEPARATOR ';'
Chris@30 225 #define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins"
Chris@30 226 #else
Chris@30 227 #define PATH_SEPARATOR ':'
Chris@30 228 #ifdef __APPLE__
Chris@30 229 #define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"
Chris@30 230 #else
Chris@30 231 #define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"
Chris@30 232 #endif
Chris@30 233 #endif
Chris@30 234
Chris@30 235 if (envPath == "") {
Chris@30 236 envPath = DEFAULT_VAMP_PATH;
Chris@30 237 char *chome = getenv("HOME");
Chris@30 238 if (chome) {
Chris@30 239 std::string home(chome);
Chris@30 240 std::string::size_type f;
Chris@30 241 while ((f = envPath.find("$HOME")) != std::string::npos &&
Chris@30 242 f < envPath.length()) {
Chris@30 243 envPath.replace(f, 5, home);
Chris@30 244 }
Chris@30 245 }
Chris@30 246 #ifdef _WIN32
Chris@30 247 char *cpfiles = getenv("ProgramFiles");
Chris@30 248 if (!cpfiles) cpfiles = (char *)"C:\\Program Files";
Chris@30 249 std::string pfiles(cpfiles);
Chris@30 250 std::string::size_type f;
Chris@30 251 while ((f = envPath.find("%ProgramFiles%")) != std::string::npos &&
Chris@30 252 f < envPath.length()) {
Chris@30 253 envPath.replace(f, 14, pfiles);
Chris@30 254 }
Chris@30 255 #endif
Chris@30 256 }
Chris@30 257
Chris@30 258 std::string::size_type index = 0, newindex = 0;
Chris@30 259
Chris@30 260 while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
Chris@30 261 path.push_back(envPath.substr(index, newindex - index));
Chris@30 262 index = newindex + 1;
Chris@30 263 }
Chris@30 264
Chris@30 265 path.push_back(envPath.substr(index));
Chris@30 266
Chris@30 267 return path;
Chris@30 268 }
Chris@27 269
mail@90 270
mail@90 271
mail@90 272 static vector<string> staticChordnames() {
mail@90 273 vector<string> chordnames;
mail@90 274 chordnames.push_back("");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@90 275 chordnames.push_back("");// =0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@90 276 chordnames.push_back("m");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
mail@90 277 chordnames.push_back("m");//=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
matthiasm@120 278 chordnames.push_back("m7b5");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0
matthiasm@120 279 chordnames.push_back("m7b5");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0
mail@90 280 chordnames.push_back("6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0
mail@90 281 chordnames.push_back("7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
mail@90 282 chordnames.push_back("maj7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1
mail@90 283 chordnames.push_back("m7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0
mail@90 284 chordnames.push_back("m6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0
mail@90 285 chordnames.push_back("");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@90 286 chordnames.push_back("");//=0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@123 287 chordnames.push_back("dim");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0
mail@90 288 chordnames.push_back("aug");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0
mail@90 289 chordnames.push_back("");//=0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@90 290 chordnames.push_back("");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@90 291 chordnames.push_back("7");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
mail@112 292 // from here: Harte syntax
mail@112 293 chordnames.push_back("");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@112 294 chordnames.push_back("");// =0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@112 295 chordnames.push_back(":min");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
mail@112 296 chordnames.push_back(":min");//=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
mail@112 297 chordnames.push_back(":hdim7");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0
mail@112 298 chordnames.push_back(":hdim7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0
mail@112 299 chordnames.push_back(":maj6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0
mail@112 300 chordnames.push_back(":7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
mail@112 301 chordnames.push_back(":maj7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1
mail@112 302 chordnames.push_back(":min7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0
mail@112 303 chordnames.push_back(":min6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0
mail@112 304 chordnames.push_back("");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@112 305 chordnames.push_back("");//=0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@123 306 chordnames.push_back(":dim");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0
mail@112 307 chordnames.push_back(":aug");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0
mail@112 308 chordnames.push_back("");//=0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@112 309 chordnames.push_back("");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0
mail@112 310 chordnames.push_back(":7");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
mail@90 311 return chordnames;
mail@90 312 }
mail@90 313
mail@90 314 static vector<float> staticChordvalues() {
mail@90 315 vector<float> chordvalues;
mail@90 316 float chordvaluearray[] = {1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,
mail@90 317 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,
mail@90 318 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,
mail@90 319 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,
mail@90 320 0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0,
mail@90 321 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,
mail@90 322 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0,
mail@90 323 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,
mail@90 324 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,
mail@90 325 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,
mail@90 326 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,
mail@90 327 0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,
mail@90 328 0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,
mail@90 329 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,
mail@90 330 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,
mail@90 331 0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,
mail@90 332 0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,
mail@90 333 0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0};
mail@90 334 for (int iChord = 0; iChord < 18; ++iChord) {
mail@90 335 for (int iNote = 0; iNote < 24; iNote++) {
mail@90 336 chordvalues.push_back(chordvaluearray[24*iChord+iNote]);
mail@90 337 }
mail@90 338 }
mail@90 339 return chordvalues;
mail@90 340 }
mail@90 341
mail@115 342 vector<string> chordDictionary(vector<float> *mchorddict, vector<vector<int> > *m_chordnotes, float boostN, float harte_syntax) {
matthiasm@86 343
Chris@27 344 typedef tokenizer<char_separator<char> > Tok;
Chris@27 345 char_separator<char> sep(",; ","=");
Chris@30 346
Chris@30 347 string chordDictBase("chord.dict");
Chris@30 348 string chordDictFilename;
Chris@30 349
Chris@30 350 vector<string> ppath = getPluginPath();
mail@90 351
matthiasm@120 352 const char* notenames[24] = {
matthiasm@120 353 "A (bass)","Bb (bass)","B (bass)","C (bass)","C# (bass)","D (bass)","Eb (bass)","E (bass)","F (bass)","F# (bass)","G (bass)","Ab (bass)",
matthiasm@120 354 "A","Bb","B","C","C#","D","Eb","E","F","F#","G","Ab"};
matthiasm@120 355
matthiasm@144 356 const char* bassnames[13][12] ={
matthiasm@120 357 {"A","","B","C","C#","D","","E","","F#","G","G#"},
matthiasm@120 358 {"Bb","","C","Db","D","Eb","","F","","G","Ab","A"},
matthiasm@120 359 {"B","","C#","D","D#","E","","F#","","G#","A","A#"},
matthiasm@120 360 {"C","","D","Eb","E","F","","G","","A","Bb","B"},
matthiasm@120 361 {"C#","","D#","E","E#","F#","","G#","","A#","B","B#"},
matthiasm@120 362 {"D","","E","F","F#","G","","A","","B","C","C#"},
matthiasm@120 363 {"Eb","","F","Gb","G","Ab","","Bb","","C","Db","D"},
matthiasm@120 364 {"E","","F#","G","G#","A","","B","","C#","D","D#"},
matthiasm@120 365 {"F","","G","Ab","A","Bb","","C","","D","Eb","E"},
matthiasm@120 366 {"F#","","G#","A","A#","B","","C#","","D#","E","E#"},
matthiasm@120 367 {"G","","A","Bb","B","C","","D","","E","F","F#"},
matthiasm@144 368 {"Ab","","Bb","Cb","C","Db","","Eb","","F","Gb","G"},
matthiasm@144 369 {"1","","2","b3","3","4","","5","","6","b7","7"}
matthiasm@120 370 };
matthiasm@120 371
mail@90 372 bool hasExternalDictinoary = true;
matthiasm@122 373 int ppathsize = static_cast<int>(ppath.size());
matthiasm@122 374 for (int i = 0; i < ppathsize; ++i) {
mail@61 375 chordDictFilename = ppath[i] + "/" + chordDictBase;
mail@61 376 cerr << "Looking for chord.dict in " << chordDictFilename << "..." ;
mail@61 377 fstream fin;
mail@61 378 fin.open(chordDictFilename.c_str(),ios::in);
mail@61 379 if( fin.is_open() )
mail@61 380 {
mail@61 381 fin.close();
mail@61 382 cerr << " success." << endl;
mail@61 383 break;
mail@61 384 } else {
matthiasm@122 385 if (i+1 < ppathsize) cerr << " (not found yet) ..." << endl;
mail@90 386 else {
mail@97 387 cerr << "* WARNING: failed to find chord dictionary, using default chord dictionary." << endl;
mail@90 388 hasExternalDictinoary = false;
mail@90 389 }
mail@61 390 }
Chris@30 391 }
Chris@30 392
Chris@30 393 iostreams::stream<iostreams::file_source> chordDictFile(chordDictFilename);
Chris@27 394 string line;
mail@89 395 // int iElement = 0;
Chris@27 396 int nChord = 0;
Chris@27 397
mail@112 398 vector<float> tempChordDict = staticChordvalues();
Chris@91 399 vector<string> tempChordNames = staticChordnames();
mail@115 400 if (harte_syntax == 1.0) {
mail@112 401 tempChordNames.erase(tempChordNames.begin(),tempChordNames.begin()+tempChordNames.size()/2);
mail@112 402 } else {
mail@112 403 tempChordNames.erase(tempChordNames.begin()+tempChordNames.size()/2,tempChordNames.begin()+tempChordNames.size());
mail@112 404 }
mail@112 405
Chris@27 406 vector<string> loadedChordNames;
Chris@27 407 vector<float> loadedChordDict;
mail@90 408 if (hasExternalDictinoary && chordDictFile.is_open()) {
mail@90 409 tempChordDict.clear();
mail@90 410 tempChordNames.clear();
matthiasm@86 411 while (std::getline(chordDictFile, line)) { // loop over lines in chord.dict file
Chris@27 412 // first, get the chord definition
Chris@27 413 string chordType;
Chris@27 414 vector<float> tempPCVector;
Chris@27 415 // cerr << line << endl;
Chris@27 416 if (!line.empty() && line.substr(0,1) != "#") {
Chris@27 417 Tok tok(line, sep);
Chris@27 418 for(Tok::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter) { // loop over line elements
Chris@27 419 string tempString = *tok_iter;
Chris@27 420 // cerr << tempString << endl;
mail@90 421 if (tok_iter == tok.begin()) { // either the chord name or a colon
Chris@27 422 if (tempString == "=") {
Chris@27 423 chordType = "";
Chris@27 424 } else {
Chris@27 425 chordType = tempString;
mail@90 426 tok_iter++;
Chris@27 427 }
Chris@27 428 } else {
mail@90 429 tempChordDict.push_back(lexical_cast<float>(*tok_iter));
Chris@27 430 }
mail@90 431 }
mail@90 432 tempChordNames.push_back(chordType);
mail@90 433 }
mail@90 434 }
matthias@140 435 cerr << "-----------------> " << tempChordNames.size() << endl;
mail@90 436 }
mail@90 437
mail@90 438
Chris@91 439 for (int iType = 0; iType < (int)tempChordNames.size(); ++iType) {
mail@90 440 // now make all 12 chords of every type
Chris@91 441 for (int iSemitone = 0; iSemitone < 12; iSemitone++) {
mail@90 442 vector<int> tempchordnotes;
mail@90 443 // add bass slash notation
mail@90 444 string slashNotation = "";
Chris@91 445 for (int kSemitone = 1; kSemitone < 12; kSemitone++) {
mail@90 446 if (tempChordDict[24*iType+(kSemitone) % 12] > 0.99) {
mail@115 447 if (harte_syntax == 0.0) {
mail@112 448 slashNotation = bassnames[iSemitone][kSemitone];
matthiasm@144 449 } else {
matthiasm@144 450 slashNotation = bassnames[12][kSemitone];
matthiasm@144 451 }
Chris@27 452 }
Chris@27 453 }
mail@90 454 if (slashNotation=="") tempchordnotes.push_back(MIDI_basenote + (iSemitone+12) % 12);
Chris@91 455 for (int kSemitone = 0; kSemitone < 12; kSemitone++) { // bass pitch classes
mail@90 456 // cerr << ((kSemitone - iSemitone + 12) % 12) << endl;
mail@90 457 float bassValue = 0;
mail@90 458 if (tempChordDict[24*iType+(kSemitone - iSemitone + 12) % 12]==1) {
mail@90 459 bassValue = 1;
mail@90 460 tempchordnotes.push_back(MIDI_basenote + (kSemitone+12) % 12);
mail@90 461 } else {
mail@90 462 if (tempChordDict[24*iType+((kSemitone - iSemitone + 12) % 12) + 12] == 1) bassValue = 0.5;
mail@90 463 }
mail@90 464 loadedChordDict.push_back(bassValue);
mail@90 465 }
Chris@91 466 for (int kSemitone = 0; kSemitone < 12; kSemitone++) { // chord pitch classes
mail@90 467 loadedChordDict.push_back(tempChordDict[24*iType+((kSemitone - iSemitone + 12) % 12) + 12]);
mail@90 468 if (tempChordDict[24*iType+((kSemitone - iSemitone + 12) % 12) + 12] > 0) tempchordnotes.push_back(MIDI_basenote + (kSemitone+12+6) % 12 - 6 + 24);
mail@90 469 }
mail@90 470 ostringstream os;
mail@90 471 if (slashNotation.empty()) {
mail@90 472 os << notenames[12+iSemitone] << tempChordNames[iType];
mail@90 473 } else {
mail@90 474 os << notenames[12+iSemitone] << tempChordNames[iType] << "/" << slashNotation;
mail@90 475 }
mail@90 476 // cerr << os.str() << endl;
mail@90 477 loadedChordNames.push_back(os.str());
mail@90 478
mail@90 479 m_chordnotes->push_back(tempchordnotes);
mail@90 480 // for (int iNote = 0; iNote < tempchordnotes.size(); ++iNote) {
mail@90 481 // cerr << tempchordnotes[iNote] << " ";
mail@90 482 // }
mail@90 483 // cerr << endl;
Chris@27 484 }
mail@90 485 }
mail@90 486
mail@90 487
mail@90 488 // N type
mail@90 489 loadedChordNames.push_back("N");
matthiasm@122 490 for (int kSemitone = 0; kSemitone < 12; kSemitone++) loadedChordDict.push_back(0.5);
matthiasm@122 491 for (int kSemitone = 0; kSemitone < 12; kSemitone++) loadedChordDict.push_back(1.0);
mail@90 492 vector<int> tempchordvector;
mail@90 493 m_chordnotes->push_back(tempchordvector);
mail@90 494 float exponent = 2.0;
mail@90 495 // float m_boostN = 1.1;
mail@90 496 // cerr << " N BOOST : " << boostN << endl << endl;
Chris@91 497 for (int iChord = 0; iChord < (int)loadedChordDict.size()/24; iChord++) {
mail@90 498 float sum = 0;
mail@90 499 float stand = 0;
mail@90 500 for (int iST = 0; iST < 24; ++iST) {
mail@90 501 sum += loadedChordDict[24 * iChord + iST];
mail@90 502 }
mail@90 503 for (int iST = 0; iST < 24; ++iST) {
mail@90 504 // loadedChordDict[24 * iChord + iST] -= sum/24;
mail@90 505 stand += pow(abs(loadedChordDict[24 * iChord + iST]),exponent)/24;
mail@90 506 }
Chris@91 507 if (iChord < (int)loadedChordDict.size()/24 - 1) {
Chris@91 508 stand = powf(stand,1.0f/exponent);
mail@90 509 } else {
matthiasm@95 510 stand = powf(stand,1.0f/exponent) / (1+boostN);
mail@90 511 }
mail@90 512 for (int iST = 0; iST < 24; ++iST) {
mail@90 513 loadedChordDict[24 * iChord + iST] /= stand;
Chris@27 514 }
matthiasm@44 515
mail@90 516 }
mail@90 517
mail@90 518
mail@90 519
mail@90 520 nChord = 0;
Chris@91 521 for (int i = 0; i < (int)loadedChordNames.size(); i++) {
mail@90 522 nChord++;
mail@90 523 }
mail@90 524 chordDictFile.close();
mail@90 525
mail@90 526
mail@90 527 // mchorddict = new float[nChord*24];
mail@90 528 for (int i = 0; i < nChord*24; i++) {
mail@90 529 mchorddict->push_back(loadedChordDict[i]);
mail@90 530 }
Chris@27 531
Chris@27 532 // cerr << "before leaving" << chordnames[1] << endl;
Chris@27 533 return loadedChordNames;
Chris@27 534 }
mail@90 535
Chris@91 536