diff options
| -rw-r--r-- | rotord/src/mtrand.cpp | 50 | ||||
| -rw-r--r-- | rotord/src/mtrand.h | 155 | ||||
| -rw-r--r-- | rotord/src/nodes_audio_analysis.cpp | 126 |
3 files changed, 326 insertions, 5 deletions
diff --git a/rotord/src/mtrand.cpp b/rotord/src/mtrand.cpp new file mode 100644 index 0000000..c0a4e48 --- /dev/null +++ b/rotord/src/mtrand.cpp @@ -0,0 +1,50 @@ +// mtrand.cpp, see include file mtrand.h for information + +#include "mtrand.h" +// non-inline function definitions and static member definitions cannot +// reside in header file because of the risk of multiple declarations + +// initialization of static private members +unsigned long MTRand_int32::state[n] = {0x0UL}; +int MTRand_int32::p = 0; +bool MTRand_int32::init = false; + +void MTRand_int32::gen_state() { // generate new state vector + for (int i = 0; i < (n - m); ++i) + state[i] = state[i + m] ^ twiddle(state[i], state[i + 1]); + for (int i = n - m; i < (n - 1); ++i) + state[i] = state[i + m - n] ^ twiddle(state[i], state[i + 1]); + state[n - 1] = state[m - 1] ^ twiddle(state[n - 1], state[0]); + p = 0; // reset position +} + +void MTRand_int32::seed(unsigned long s) { // init by 32 bit seed + state[0] = s & 0xFFFFFFFFUL; // for > 32 bit machines + for (int i = 1; i < n; ++i) { + state[i] = 1812433253UL * (state[i - 1] ^ (state[i - 1] >> 30)) + i; +// see Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier +// in the previous versions, MSBs of the seed affect only MSBs of the array state +// 2002/01/09 modified by Makoto Matsumoto + state[i] &= 0xFFFFFFFFUL; // for > 32 bit machines + } + p = n; // force gen_state() to be called for next random number +} + +void MTRand_int32::seed(const unsigned long* array, int size) { // init by array + seed(19650218UL); + int i = 1, j = 0; + for (int k = ((n > size) ? n : size); k; --k) { + state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL)) + + array[j] + j; // non linear + state[i] &= 0xFFFFFFFFUL; // for > 32 bit machines + ++j; j %= size; + if ((++i) == n) { state[0] = state[n - 1]; i = 1; } + } + for (int k = n - 1; k; --k) { + state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL)) - i; + state[i] &= 0xFFFFFFFFUL; // for > 32 bit machines + if ((++i) == n) { state[0] = state[n - 1]; i = 1; } + } + state[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array + p = n; // force gen_state() to be called for next random number +}
\ No newline at end of file diff --git a/rotord/src/mtrand.h b/rotord/src/mtrand.h new file mode 100644 index 0000000..482903d --- /dev/null +++ b/rotord/src/mtrand.h @@ -0,0 +1,155 @@ +// mtrand.h +// C++ include file for MT19937, with initialization improved 2002/1/26. +// Coded by Takuji Nishimura and Makoto Matsumoto. +// Ported to C++ by Jasper Bedaux 2003/1/1 (see http://www.bedaux.net/mtrand/). +// The generators returning floating point numbers are based on +// a version by Isaku Wada, 2002/01/09 +// +// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The names of its contributors may not be used to endorse or promote +// products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Any feedback is very welcome. +// http://www.math.keio.ac.jp/matumoto/emt.html +// email: matumoto@math.keio.ac.jp +// +// Feedback about the C++ port should be sent to Jasper Bedaux, +// see http://www.bedaux.net/mtrand/ for e-mail address and info. + +#ifndef MTRAND_H +#define MTRAND_H + +class MTRand_int32 { // Mersenne Twister random number generator +public: +// default constructor: uses default seed only if this is the first instance + MTRand_int32() { if (!init) seed(5489UL); init = true; } +// constructor with 32 bit int as seed + MTRand_int32(unsigned long s) { seed(s); init = true; } +// constructor with array of size 32 bit ints as seed + MTRand_int32(const unsigned long* array, int size) { seed(array, size); init = true; } +// the two seed functions + void seed(unsigned long); // seed with 32 bit integer + void seed(const unsigned long*, int size); // seed with array +// overload operator() to make this a generator (functor) + unsigned long operator()() { return rand_int32(); } +// 2007-02-11: made the destructor virtual; thanks "double more" for pointing this out + virtual ~MTRand_int32() {} // destructor +protected: // used by derived classes, otherwise not accessible; use the ()-operator + unsigned long rand_int32(); // generate 32 bit random integer +private: + static const int n = 624, m = 397; // compile time constants +// the variables below are static (no duplicates can exist) + static unsigned long state[n]; // state vector array + static int p; // position in state array + static bool init; // true if init function is called +// private functions used to generate the pseudo random numbers + unsigned long twiddle(unsigned long, unsigned long); // used by gen_state() + void gen_state(); // generate new state +// make copy constructor and assignment operator unavailable, they don't make sense + MTRand_int32(const MTRand_int32&); // copy constructor not defined + void operator=(const MTRand_int32&); // assignment operator not defined +}; + +// inline for speed, must therefore reside in header file +inline unsigned long MTRand_int32::twiddle(unsigned long u, unsigned long v) { + return (((u & 0x80000000UL) | (v & 0x7FFFFFFFUL)) >> 1) + ^ ((v & 1UL) * 0x9908B0DFUL); +// 2013-07-22: line above modified for performance according to http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/Ierymenko.html +// thanks Vitaliy FEOKTISTOV for pointing this out +} + +inline unsigned long MTRand_int32::rand_int32() { // generate 32 bit random int + if (p == n) gen_state(); // new state vector needed +// gen_state() is split off to be non-inline, because it is only called once +// in every 624 calls and otherwise irand() would become too big to get inlined + unsigned long x = state[p++]; + x ^= (x >> 11); + x ^= (x << 7) & 0x9D2C5680UL; + x ^= (x << 15) & 0xEFC60000UL; + return x ^ (x >> 18); +} + +// generates double floating point numbers in the half-open interval [0, 1) +class MTRand : public MTRand_int32 { +public: + MTRand() : MTRand_int32() {} + MTRand(unsigned long seed) : MTRand_int32(seed) {} + MTRand(const unsigned long* seed, int size) : MTRand_int32(seed, size) {} + ~MTRand() {} + double operator()() { + return static_cast<double>(rand_int32()) * (1. / 4294967296.); } // divided by 2^32 +private: + MTRand(const MTRand&); // copy constructor not defined + void operator=(const MTRand&); // assignment operator not defined +}; + +// generates double floating point numbers in the closed interval [0, 1] +class MTRand_closed : public MTRand_int32 { +public: + MTRand_closed() : MTRand_int32() {} + MTRand_closed(unsigned long seed) : MTRand_int32(seed) {} + MTRand_closed(const unsigned long* seed, int size) : MTRand_int32(seed, size) {} + ~MTRand_closed() {} + double operator()() { + return static_cast<double>(rand_int32()) * (1. / 4294967295.); } // divided by 2^32 - 1 +private: + MTRand_closed(const MTRand_closed&); // copy constructor not defined + void operator=(const MTRand_closed&); // assignment operator not defined +}; + +// generates double floating point numbers in the open interval (0, 1) +class MTRand_open : public MTRand_int32 { +public: + MTRand_open() : MTRand_int32() {} + MTRand_open(unsigned long seed) : MTRand_int32(seed) {} + MTRand_open(const unsigned long* seed, int size) : MTRand_int32(seed, size) {} + ~MTRand_open() {} + double operator()() { + return (static_cast<double>(rand_int32()) + .5) * (1. / 4294967296.); } // divided by 2^32 +private: + MTRand_open(const MTRand_open&); // copy constructor not defined + void operator=(const MTRand_open&); // assignment operator not defined +}; + +// generates 53 bit resolution doubles in the half-open interval [0, 1) +class MTRand53 : public MTRand_int32 { +public: + MTRand53() : MTRand_int32() {} + MTRand53(unsigned long seed) : MTRand_int32(seed) {} + MTRand53(const unsigned long* seed, int size) : MTRand_int32(seed, size) {} + ~MTRand53() {} + double operator()() { + return (static_cast<double>(rand_int32() >> 5) * 67108864. + + static_cast<double>(rand_int32() >> 6)) * (1. / 9007199254740992.); } +private: + MTRand53(const MTRand53&); // copy constructor not defined + void operator=(const MTRand53&); // assignment operator not defined +}; + +#endif // MTRAND_H
\ No newline at end of file diff --git a/rotord/src/nodes_audio_analysis.cpp b/rotord/src/nodes_audio_analysis.cpp index ea44048..f077d41 100644 --- a/rotord/src/nodes_audio_analysis.cpp +++ b/rotord/src/nodes_audio_analysis.cpp @@ -93,7 +93,7 @@ namespace Rotor{ if (i.second.values.size()) { data+=" ("; bool first=true; - for (auto j: i.second.values) { + for (auto j: i.second.values) { if (first){ first=false; } @@ -101,7 +101,7 @@ namespace Rotor{ data=data+toString(j); } data+=") "; - } + } data+="]"; } return data; @@ -109,6 +109,10 @@ namespace Rotor{ bool sortsegments(std::pair<int,double> i,std::pair<int,double> j){ return (i.second<j.second); } + + bool sortseggrps(std::pair<double,vector<pair<double,int> > > i,std::pair<double,vector<pair<double,int> > > j){ + return (i.first<j.first); + } void Intensity_segmenter::cleanup(){ //algorithm idea: //get average tempo and intensity for each segment and store them @@ -131,10 +135,34 @@ namespace Rotor{ analysers["segmenter"].cleanup(); analysers["tempo"].cleanup(); analysers["intensity"].cleanup(); + + //combine with similarity numbers + // 1. count similarity numbers + + map<int,vector<int> > similarities; + + //what do we want to know about these similarities? + // how many are there? map.size() + // how many members are in each one? map[item].size() + // which members are they? auto m: map[item] + + uint32_t i=0; + for (auto f:analysers["segmenter"].features) { + if (f.second.values.size()) { + int group=f.second.values[0]; + if (similarities.find(group)==similarities.end()){ + similarities[group]={}; + } + similarities[group].push_back(i); + } + i++; + } + for (auto s:similarities) cerr<<"group "<<s.first<<" count: "<<s.second.size()<<endl; + cerr<<analysers["segmenter"].features.size()<<" segments"<<endl; cerr<<analysers["tempo"].features.size()<<" tempo features"<<endl; cerr<<analysers["intensity"].features.size()<<" intensity features"<<endl; - uint32_t i=0; + i=0; double min_tempo=9999999.0; double min_intensity=9999999.0; double max_tempo=0.0; @@ -182,11 +210,15 @@ namespace Rotor{ } //make relative scale 0.0-1.0 and save weighted totals vector< pair<int,double>> totals; + vector<double> totalsmap; for (i=0;i<tempos.size();i++){ tempos[i]=(tempos[i]-min_tempo)/(max_tempo-min_tempo); intensities[i]=(intensities[i]-min_intensity)/(max_intensity-min_intensity); totals.push_back(make_pair(i,(tempos[i]*parameters["tempo_weight"]->value)+(intensities[i]*parameters["intensity_weight"]->value))); + totalsmap.push_back((tempos[i]*parameters["tempo_weight"]->value)+(intensities[i]*parameters["intensity_weight"]->value)); } + + /* //sort and convert to features std::sort(totals.begin(),totals.end(),sortsegments); for (i=0;i<totals.size();i++) { @@ -214,10 +246,94 @@ namespace Rotor{ cerr<<endl; } } + for (i=0;i<totals.size();i++){ vampHost::feature f; f.values.push_back((double)i-bucketoffsets[i]); features[times[totals[i].first]]=f; - } + } + */ + + /* +sort intensity totals +find out how many segments will share levels apart from similarity levels +start with a structure: +map<inputnum,vector<pair<tempo,inputnum>> +start grouping by similarity +if there are more similarity groups than wantedgroups, start by grouping similarities +otherwise take biggest similarity groups and split them by intensity +if there are still too many groups, merge closest smallest groups +finally sort by intensity to map output + +nned to retrieve total intensity by segment + */ + // segment group_intensity seg_intense segment + vector<pair<double,vector<pair<double,int> > > > seggrps; + for (i=0;i<totalsmap.size();i++){ + vector<pair<double,int> > data; + data.push_back(make_pair(totalsmap[i],i)); + seggrps.push_back(make_pair(totalsmap[i],data)); + } + for (auto s:similarities){ + if (s.second.size()>1){ + for (int j=s.second.size()-1;j>0;j--){ + seggrps[s.second[0]].second.push_back(make_pair(totalsmap[s.second[j]],s.second[j])); + //keep running average// should be by area? + seggrps[s.second[0]].first+=(totalsmap[s.second[j]]*(1.0/max(1,(int)seggrps[s.second[0]].second.size()-1))); + double div=seggrps[s.second[0]].second.size()==1?1.0:((double)seggrps[s.second[0]].second.size()-1/(double)seggrps[s.second[0]].second.size()); + //neat! this gives 1,1/2,2/3,3/4.. + seggrps[s.second[0]].first*=div; + seggrps.erase(seggrps.begin()+s.second[j]); + } + } + } + cerr<<"similarities assigned, "<<(totalsmap.size()-seggrps.size())<<" segments merged"<<endl; + //sort the contents by intensity + std::sort(seggrps.begin(),seggrps.end(),sortseggrps); + //possible mergers will be with groups with adjacent intensity + while (seggrps.size()>(int)parameters["levels"]->value){ + //reduce similarity groups + //decide the best 2 to merge + vector<double> diffs; + for (int j=0;j<seggrps.size()-1;j++) diffs.push_back(seggrps[j+1].first-seggrps[j].first); + int smallest=0; + for (int j=1;j<diffs.size();j++) if (diffs[i]<diffs[smallest]) smallest=i; + for (int j=0;j<seggrps[smallest].second.size();j++) { + seggrps[smallest+1].second.push_back(seggrps[smallest].second[j]); + } + seggrps.erase(seggrps.begin()+smallest); + } + cerr<<"intensities merged, "<<seggrps.size()<<" levels remain"<<endl; + while (seggrps.size()<(int)parameters["levels"]->value) { + //split groups + } + + map<int,int> outputvalues; + for (int j=0;j<seggrps.size();j++){ + for (int k=0;k<seggrps[j].second.size();k++){ + outputvalues[seggrps[j].second[k].second]=j; + } + } + + + for (i=0;i<totals.size();i++){ + vampHost::feature f; + f.values.push_back(outputvalues[i]); + features[times[totals[i].first]]=f; + } } -}
\ No newline at end of file +} + +/* +A data structure to represent segments and their mapping to output levels +how do we merge the intensity groups with the similarities? + +we create a list + + + + +... we iterate through the list of segments and place the right output number + + +*/ |
