SF.net sc3-plugins Git: sc3-plugins branch, master, updated. 3.5-22-g6c447e7
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "sc3-plugins".
The branch, master has been updated
via 6c447e789a125c4a7a39e71b2e6bde1f3396bf57 (commit)
from 7d36252a73bf0a167c094684393100733a5b4500 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 6c447e789a125c4a7a39e71b2e6bde1f3396bf57
Author: Nick Collins <clicksonnil@...>
Date: Sat Jun 30 16:27:32 2012 +0100
Added SCMIRUGens with accompanying help files and alteration to CMakeLists file
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index eeedbff..4e8155f 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
<at> <at> -92,6 +92,7 <at> <at> set(PLUGIN_DIRS
MdaUGens
RFWUGens
RMEQSuiteUGens
+ SCMIRUGens
SLUGens
SummerUGens
TagSystemUGens
diff --git a/source/SCMIRUGens/Chromagram.cpp b/source/SCMIRUGens/Chromagram.cpp
new file mode 100644
index 0000000..2a58f51
--- /dev/null
+++ b/source/SCMIRUGens/Chromagram.cpp
<at> <at> -0,0 +1,332 <at> <at>
+/*
+ * Created by Nicholas Collins on 13/08/2010.
+ * Copyright 2010 Nicholas M Collins. All rights reserved.
+ */
+
+//#define SC_DARWIN
+#include "SC_PlugIn.h"
+#include "FFT_UGens.h"
+
+
+InterfaceTable *ft;
+
+
+
+struct Chromagram : public Unit
+{
+ int fftsize_;
+ float chromanorm_; //for normalisation
+ int numdivisions_;
+ int tuningbase_;
+ int octaves_;
+ //int integrateflag_;
+ //float integrationconstant_;
+
+
+ int numindices_;
+ int * indexdata_;
+ float * indexweights_;
+ float * fftpower_;
+ float * chroma_;
+
+
+};
+
+
+
+
+extern "C" {
+
+ void Chromagram_next_k(Chromagram *unit, int inNumSamples);
+ void Chromagram_Ctor(Chromagram* unit);
+ void Chromagram_Dtor(Chromagram* unit);
+
+}
+
+
+
+
+
+void Chromagram_Ctor( Chromagram* unit ) {
+
+ int i, j;
+
+ double sr = unit->mWorld->mFullRate.mSampleRate; //never trust SAMPLERATE, gives UGens output
rate, not audio rate
+ float nyquist = sr*0.5;
+ unit->fftsize_ = ZIN0(1);
+
+
+ float freqperbin = sr / unit->fftsize_;
+
+
+ int divisions = ZIN0(2);
+ float tuningbase = ZIN0(3);
+ int octaves = ZIN0(4);
+
+ if (octaves<1) octaves = 1;
+
+ float nyminusonebin = nyquist-freqperbin;
+
+ //must have room for at least one octave of divisions
+ if ((tuningbase<0.0) || (tuningbase>(nyminusonebin*0.5))) {
+
+ tuningbase = 32.703195662575 ; //C at MIDI note 24
+
+ }
+
+ unit->tuningbase_ = tuningbase;
+
+ //if octaves can't fit within available fft bins, have to cut short
+ float topfreq = tuningbase * pow(2.0,octaves);
+
+ //printf("checks %d %f %d %f %f %f \n", divisions, tuningbase, octaves, sr, nyminusonebin, topfreq);
+
+ //if can't fit all octaves into Nyquist
+ if (topfreq >= (nyminusonebin)) {
+
+ octaves = (int) (log2(nyminusonebin/tuningbase));
+
+ }
+
+ unit->octaves_ = octaves;
+
+ //should include number of octaves as divisor too
+ unit->chromanorm_ = 1.0/((float)unit->fftsize_ * octaves);
+
+
+ //unit->integrateflag_ = ZIN0(5);
+ //unit->integrationconstant_ = ZIN0(6);
+
+ int totaldivisions = octaves * divisions;
+
+ unit->numindices_ = 2*totaldivisions;
+ int * indexdata = (int *)RTAlloc(unit->mWorld, sizeof(int)*unit->numindices_);
+ float * weightdata = (float *) RTAlloc(unit->mWorld, sizeof(float)*unit->numindices_);
+
+ unit->indexdata_ = indexdata;
+ unit->indexweights_ = weightdata;
+
+ //work out indices of fft bins corresponding to chroma positions, from basefreq up
+ //avoid lots of pow calls by working out cumulative ratios as go
+
+ float ratio = pow(2.0,1.0/divisions);
+
+ //float rationow= 1.0;
+
+ float octavenow = 1.0;
+
+ float temp = 1.0f/freqperbin;
+
+ int indexnow;
+
+ for ( j=0; j<octaves; ++j) {
+
+ float freqnow= tuningbase * octavenow;
+
+ indexnow = 2*j*divisions;
+
+ for ( i=0; i<divisions; ++i) {
+
+ //express as fft bins
+ float binpos = freqnow * temp;
+
+ int lower = (int) binpos;
+ float interp = binpos- lower;
+ int upper = lower+1;
+
+ //linear interpolation
+ indexdata[indexnow] = lower;
+ weightdata[indexnow] = 1.0 - interp;
+
+ //printf("lower oct %d div %d value: %d %f \n",j, i, indexdata[indexnow], weightdata[indexnow]);
+
+ ++indexnow;
+
+ indexdata[indexnow] = upper;
+ weightdata[indexnow] = interp;
+
+
+ //printf("upper oct %d div %d value: %d %f \n",j, i, indexdata[indexnow], weightdata[indexnow]);
+
+ ++indexnow;
+
+ freqnow *= ratio;
+
+ }
+
+ octavenow *= 2.0;
+
+ }
+
+ //would depend if taking harmonics as well as pure bin evidence
+ //int highestbin =
+ //unit->fftpower_ = RTAlloc(unit->mWorld, sizeof(float)*highestbin);
+
+ //for now only need to calculate as go, no need for intermediate storage
+ unit->chroma_ = (float*)RTAlloc(unit->mWorld, sizeof(float)*divisions);
+
+ SETCALC(Chromagram_next_k);
+
+ //in case of later interpolation, first output must be set to zero
+ for ( i=0; i<divisions; ++i) {
+
+ unit->chroma_[i] = 0.0;
+
+ ZOUT0(i) = 0.f;
+
+ }
+
+ unit->numdivisions_ = divisions;
+
+}
+
+void Chromagram_Dtor(Chromagram *unit)
+{
+
+ RTFree(unit->mWorld, unit->indexdata_);
+ RTFree(unit->mWorld, unit->indexweights_);
+ RTFree(unit->mWorld, unit->chroma_);
+
+}
+
+
+//NEXT: destructor then next function using octaves and divisions slots, with appropriate power calc
from fft data as go
+
+
+void Chromagram_next_k( Chromagram *unit, int inNumSamples ) {
+
+ int i, j;
+
+ int divisions = unit->numdivisions_;
+ float * chroma = unit->chroma_;
+ int octaves = unit->octaves_;
+
+ //float *input = IN(0);
+
+ //int numSamples = unit->mWorld->mFullRate.mBufLength;
+
+ //if input is legitimate buffer number:
+
+ float fbufnum = ZIN0(0);
+
+ //next FFT bufffer ready, update
+ //assuming at this point that buffer precalculated for any resampling
+ if (fbufnum > -0.01f) {
+
+ int ibufnum = (uint32)fbufnum;
+
+ World *world = unit->mWorld;
+ SndBuf *buf;
+
+ if (ibufnum >= world->mNumSndBufs) {
+ int localBufNum = ibufnum - world->mNumSndBufs;
+ Graph *parent = unit->mParent;
+ if(localBufNum <= parent->localBufNum) {
+ buf = parent->mLocalSndBufs + localBufNum;
+ } else {
+ buf = world->mSndBufs;
+ }
+ } else {
+ buf = world->mSndBufs + ibufnum;
+ }
+
+ //make sure in real and imag form
+ //SCComplexBuf * complexbuf = ToComplexApx(buf);
+
+ float * data= (float *)ToComplexApx(buf);
+
+ //float * data= buf->data;
+
+ //int numindices= unit->numindices_;
+
+ int * indexdata= unit->indexdata_;
+ float * indexweights= unit->indexweights_;
+
+ float real, imag;
+ int index, indexnow; //index2,
+ float weight1, intensity1, weight2, intensity2;
+
+
+ float norm = unit->chromanorm_;
+
+ //reset chroma unless keeping previous via leaky integration
+ if((int)(ZIN0(5)) > 0) {
+
+ float integration = ZIN0(6);
+
+ if (integration>0.999999999f) {
+ integration = 0.999999999f;
+ }
+
+ for ( i=0; i<divisions; ++i) {
+ chroma[i] *= integration;
+ }
+
+
+
+ } else {
+
+ for ( i=0; i<divisions; ++i) {
+ chroma[i] = 0.0;
+ }
+
+ }
+
+ //for (int j=0; j< numindices; j+=2) {
+//
+//
+//
+// }
+//
+
+ for ( j=0; j<octaves; ++j) {
+
+ indexnow = 2*j*divisions;
+
+ for ( i=0; i<divisions; ++i) {
+
+ index = 2*indexdata[indexnow];
+ real= data[index];
+ imag= data[index+1];
+ intensity1 = (real*real) + (imag*imag);
+ weight1= indexweights[indexnow];
+
+ index+=2;
+ real= data[index];
+ imag= data[index+1];
+ intensity2 = (real*real) + (imag*imag);
+ weight2= indexweights[indexnow+1];
+
+
+ chroma[i] += (norm*(weight1*intensity1 + weight2*intensity2));
+
+ indexnow+=2;
+ }
+
+ }
+
+
+ }
+
+
+ for (i=0; i<divisions; ++i)
+ ZOUT0(i) = chroma[i];
+
+
+}
+
+
+PluginLoad(Chromagram) {
+
+ init_SCComplex(inTable);
+
+ ft = inTable;
+
+ DefineDtorCantAliasUnit(Chromagram);
+
+}
+
+
+
+
+
diff --git a/source/SCMIRUGens/FeatureSave.cpp b/source/SCMIRUGens/FeatureSave.cpp
new file mode 100644
index 0000000..3b20373
--- /dev/null
+++ b/source/SCMIRUGens/FeatureSave.cpp
<at> <at> -0,0 +1,213 <at> <at>
+/*
+ SuperCollider real time audio synthesis system
+ Copyright (c) 2002 James McCartney. All rights reserved.
+ http://www.audiosynth.com
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "SC_PlugIn.h"
+
+#include "stdio.h"
+
+InterfaceTable *ft;
+
+
+struct FeatureSave : public Unit
+{
+
+ int frameswritten_;
+ int numfeatures_;
+ //char * filename_;
+ int fileready_;
+
+ //open file data
+ FILE *fp;
+
+};
+
+extern "C" {
+
+ void FeatureSave_next(FeatureSave *unit, int inNumSamples);
+ void FeatureSave_Ctor(FeatureSave* unit);
+ //void FeatureSave_Dtor(FeatureSave* unit);
+
+}
+
+
+void FeatureSaveUnitCmdFunc (Unit *unit, struct sc_msg_iter *args);
+void FeatureSaveUnitCmdFunc2 (Unit *unit, struct sc_msg_iter *args);
+
+
+
+//will need to create in NRT mode
+
+void FeatureSave_Ctor(FeatureSave* unit) {
+
+ unit->frameswritten_ = 0;
+ unit->fileready_ = 0;
+ unit->numfeatures_ = IN0(0);
+
+ //printf("FeatureSave: numfeatures %d \n",unit->numfeatures_);
+
+
+ DefineUnitCmd("FeatureSave","createfile",FeatureSaveUnitCmdFunc);
+ DefineUnitCmd("FeatureSave","closefile",FeatureSaveUnitCmdFunc2);
+
+
+ //printf("FeatureSave sanity check: unit pointer %p \n",unit->mUnitDef);
+
+
+ //mCmds undefined here
+ //unit->mUnitDef->mCmds;
+
+
+ SETCALC(FeatureSave_next);
+
+}
+
+
+
+void FeatureSave_next(FeatureSave *unit, int inNumSamples) {
+
+ float trig = IN0(1); //trigger input
+
+ //if trigger and file open
+
+ //printf("%f %d %d %d \n",trig, unit->fileready_, unit->numfeatures_, trig>(-0.01f));
+ //printf("FeatureSave:next sanity check: unit pointer %p \n",unit->mUnitDef);
+
+ if((trig>(-0.01f)) && (unit->fileready_==1)) {
+
+ //printf("%f %d \n",trig, unit->fileready_);
+
+ //write to file
+
+ for (int i=0; i<unit->numfeatures_; ++i) {
+
+ float featureval = IN0(i+2);
+ //printf("%d %f trig %f \n",i, featureval, trig);
+
+ //printf("featureval %f %d \n",featureval, unit->fileready_);
+
+
+ fwrite(&featureval, sizeof(float),1, unit->fp);
+
+ }
+
+
+ ++unit->frameswritten_;
+
+ }
+
+
+}
+
+
+
+void FeatureSaveUnitCmdFunc (Unit *unit, struct sc_msg_iter *args) {
+
+ FeatureSave * fsave = (FeatureSave*) unit;
+
+ //message type:
+ //int cmdtype = args->geti();
+
+
+ const char * stringarg = args->gets();
+
+ //printf("got here at least %s\n",stringarg);
+
+ //strcpy(fsave->filename_, stringarg);
+
+ //create file for writing
+ //won't push to NRT thread for now since assuming only using this UGen in NRT mode to start with
+
+ //fsave->fp = fopen(fsave->filename_, "wb");
+ fsave->fp = fopen(stringarg, "wb+");
+
+ //dummy header data for now
+ fwrite(&fsave->frameswritten_, sizeof(int),1, fsave->fp);
+
+ fwrite(&fsave->numfeatures_, sizeof(int),1, fsave->fp);
+
+ fsave->fileready_ = 1;
+
+}
+
+
+
+void FeatureSaveUnitCmdFunc2 (Unit *unit, struct sc_msg_iter *args) {
+
+ FeatureSave * fsave = (FeatureSave*) unit;
+
+ //message type:
+ //int cmdtype = args->geti();
+
+ fsave->fileready_ = 0;
+
+ //printf("ever called? %d \n", fsave->frameswritten_);
+
+ //finalise header data:
+
+ //back to start
+ //rewind(fsave->fp);
+
+ fseek(fsave->fp, 0, SEEK_SET);
+
+ //int testval = 64;
+ //fwrite(&testval, sizeof(int),1, fsave->fp);
+
+ fwrite(&fsave->frameswritten_, sizeof(int),1, fsave->fp);
+
+// int test;
+// fread(&test, sizeof(int),1, fsave->fp);
+// printf("ever called 2? %d \n", test);
+//
+//
+// fseek(fsave->fp, 0, SEEK_END);
+
+ //close file
+ fclose(fsave->fp);
+
+
+}
+
+PluginLoad(FeatureSave) {
+
+ //FILE * testfile = fopen("blah", "wb");
+//
+// int numelements = 1000;
+//
+// fwrite(&numelements, sizeof(int),1, testfile);
+//
+// for (int i=0; i<numelements; ++i) {
+// float now = i*0.67;
+// fwrite(&now, sizeof(int),1, testfile);
+//
+// }
+//
+// fclose(testfile);
+
+
+ ft = inTable;
+
+ DefineSimpleUnit(FeatureSave);
+
+}
+
+
+
+
diff --git a/source/SCMIRUGens/SensoryDissonance.cpp b/source/SCMIRUGens/SensoryDissonance.cpp
new file mode 100644
index 0000000..05b7bba
--- /dev/null
+++ b/source/SCMIRUGens/SensoryDissonance.cpp
<at> <at> -0,0 +1,327 <at> <at>
+/*
+ * Created by Nicholas Collins on 13/08/2010.
+ * Copyright 2010 Nicholas M Collins. All rights reserved.
+ */
+
+//William A. Sethares method (see e.g., Consonance-Based Spectral Mappings, CMJ 22(1): 56-72, 1998).
+//this is the harmonic dissonance method, looking for peaks in spectrum, and looking at proximity of
peaks as indicating potential dissonance
+//An alternative roughness formulation is a multiband filterbank with amplitude modulation detection
in each band looking for rates of 15-100Hz or so
+
+//outputs dissonance measure
+//could also output number of detected peaks as an interesting auxilliary noisiness measure (could get
average dissonnance per peak from that, though not especially meaingful in itself?)
+
+
+//#define SC_DARWIN
+#include "SC_PlugIn.h"
+#include "FFT_UGens.h"
+
+
+InterfaceTable *ft;
+
+
+struct SensoryDissonance : public Unit
+{
+ int fftsize_;
+ int topbin_;
+ int frequencyperbin_;
+
+ float dissonance_;
+
+ int maxnumpeaks_;
+ float peakthreshold_;
+
+ float * peakfreqs_;
+ float * peakamps_;
+
+ float norm_;
+ int clamp_;
+
+ int initfftsize_;
+};
+
+
+
+
+extern "C" {
+
+ void SensoryDissonance_next_k(SensoryDissonance *unit, int inNumSamples);
+ void SensoryDissonance_Ctor(SensoryDissonance* unit);
+ void SensoryDissonance_Dtor(SensoryDissonance* unit);
+
+}
+
+
+
+
+
+void SensoryDissonance_Ctor( SensoryDissonance* unit ) {
+
+ //int i, j;
+
+ unit->initfftsize_ = 0; //must defer this till have a buffer to check
+
+ unit->maxnumpeaks_ = ZIN0(1); //100;
+ unit->peakthreshold_ = ZIN0(2);
+ unit->peakfreqs_ = (float *)RTAlloc(unit->mWorld, sizeof(float)*unit->maxnumpeaks_);
+ unit->peakamps_ = (float *)RTAlloc(unit->mWorld, sizeof(float)*unit->maxnumpeaks_);
+
+ unit->norm_ = ZIN0(3); //0.01/unit->maxnumpeaks_; //unit->fftsize_;
+
+ unit->clamp_ = ZIN0(4);
+
+ SETCALC(SensoryDissonance_next_k);
+
+
+}
+
+void SensoryDissonance_Dtor(SensoryDissonance *unit)
+{
+
+ RTFree(unit->mWorld, unit->peakfreqs_);
+ RTFree(unit->mWorld, unit->peakamps_);
+
+}
+
+
+//NEXT: destructor then next function using octaves and divisions slots, with appropriate power calc
from fft data as go
+
+
+void SensoryDissonance_next_k( SensoryDissonance *unit, int inNumSamples ) {
+
+ //int i, j;
+
+ //float *input = IN(0);
+
+ //int numSamples = unit->mWorld->mFullRate.mBufLength;
+
+ //if input is legitimate buffer number:
+ float fbufnum = ZIN0(0);
+
+ //next FFT bufffer ready, update
+ //assuming at this point that buffer precalculated for any resampling
+ if (fbufnum > -0.01f) {
+
+ int ibufnum = (uint32)fbufnum;
+
+ World *world = unit->mWorld;
+ SndBuf *buf;
+
+ if (ibufnum >= world->mNumSndBufs) {
+ int localBufNum = ibufnum - world->mNumSndBufs;
+ Graph *parent = unit->mParent;
+ if(localBufNum <= parent->localBufNum) {
+ buf = parent->mLocalSndBufs + localBufNum;
+ } else {
+ buf = world->mSndBufs;
+ }
+ } else {
+ buf = world->mSndBufs + ibufnum;
+ }
+
+
+ if(unit->initfftsize_ ==0) {
+
+ double sr = unit->mWorld->mFullRate.mSampleRate; //never trust SAMPLERATE, gives UGens output
rate, not audio rate
+ //float nyquist = sr*0.5;
+
+ unit->fftsize_ = buf->frames; //ZIN0(1);
+ //printf("check fftsize %d \n",unit->fftsize_);
+ unit->topbin_= unit->fftsize_*0.25;
+
+ unit->frequencyperbin_ = sr / unit->fftsize_;
+
+ unit->initfftsize_ = 1;
+ }
+
+ //make sure in real and imag form
+ //SCComplexBuf * complexbuf = ToComplexApx(buf);
+
+ float * data= (float *)ToComplexApx(buf);
+
+ //float * data= buf->data;
+
+ //int numindices= unit->numindices_;
+
+ float * peakfreqs= unit->peakfreqs_;
+ float * peakamps= unit->peakamps_;
+
+ float real, imag;
+ int index;
+
+ int numpeaks = 0;
+ int maxnumpeaks = unit->maxnumpeaks_;
+
+ float intensity;
+ float position;
+
+ float threshold = unit->peakthreshold_;
+
+ //create powerspectrum
+
+ float prev=0.0, now=0.0, next=0.0;
+
+ float frequencyperbin = unit->frequencyperbin_;
+
+ //float totalpeakpower = 0.0f;
+ float temp1, refinement;
+
+ for (int j=1; j<=unit->topbin_; ++j) {
+
+ index = 2*j;
+ real= data[index];
+ imag= data[index+1];
+ intensity = (real*real) + (imag*imag);
+//
+
+
+ next= intensity;
+
+ if(j>=3) {
+
+ //hunt for peaks
+
+ //look for peak by scoring within +-3
+ //assume peak must be centrally greater than 60dB say
+
+ //powertest_
+ //minpeakdB_ was 60
+
+ if (now>threshold) {
+
+ //y1= powerspectrum_[i-1];
+ // //y2= valuenow;
+ // y3= powerspectrum_[i+1];
+ //
+ if ((now>prev) && (now>next)) {
+
+ //second peak condition; sum of second differences must be positive
+ //NCfloat testsum= (valuenow - powerspectrum_[i-2]) + (valuenow - powerspectrum_[i+2]);
+
+ //if (testsum>0.0) {
+
+ //refine estimate of peak using quadratic function
+ //see workbook 28th Jan 2010
+
+ temp1= prev+next-(2*now);
+
+ if (fabs(temp1)>0.00001) {
+ position=(prev-next)/(2*temp1);
+
+ //running quadratic formula
+ refinement = (0.5*temp1*(position*position)) + (0.5*(next-prev)*position) + now;
+ //refinement= y2 - (((y3-y1)^2)/(8*temp1));
+
+ } else {
+ //degenerate straight line case; shouldn't occur
+ //since require greater than for peak, not equality
+
+ position=0.0; //may as well take centre
+
+ //bettervalue= max([y1,y2,y3]); %straight line through them, find max
+
+ refinement= now; //must be max for else would have picked another one in previous calculation! %max([y1,y2,y3]);
+
+ }
+
+ //correct??????????????????????????????
+ peakfreqs[numpeaks] = (j-1+position)*frequencyperbin; //frequencyconversion;
+ //printf("peakfrequencies %d is %f from i %d position %f freqperbin %f \n",
numpeaks_,peakfrequencies_[numpeaks_],i, position, frequencyperbin_);
+
+ peakamps[numpeaks] = sqrt(refinement); //Sethares formula requires amplitudes
+ //totalpeakpower += refinement;
+
+ //cout << " peak " << numpeaks_ << " " << peakfrequencies_[numpeaks_] << " " << refinement << " " ;
+
+ ++numpeaks;
+
+ //}
+
+ }
+
+ }
+
+ //test against maxnumberpeaks_
+ if ( numpeaks == maxnumpeaks )
+ break;
+
+
+
+ }
+
+ prev = now; now=next;
+
+
+
+
+
+
+
+ }
+
+
+ //now have list of peaks: calculate total dissonance:
+
+ //iterate through peaks, matching each to min of next 10, and no more than octave, using Sethares p. 58
CMJ article
+
+ float dissonancesum = 0.0;
+
+ float f1, v1, f2, v2;
+ float d;
+ float diff; //, minf;
+ float s, a, b;
+ float octave;
+
+ for (int i=0; i<(numpeaks-1); ++i) {
+
+ f1 = peakfreqs[i];
+ v1 = peakamps[i];
+ s = 0.24f/(0.21f*f1+19.f); //constant needed as denominator in formula
+ a = -3.5f*s;
+ b= -5.75f*s;
+
+ octave = 2.0f*f1;
+
+ for (int k=i+1; k<sc_min(i+20,numpeaks); ++k) {
+
+ f2 = peakfreqs[k];
+ v2 = peakamps[k];
+
+ if(f2>octave) break; //shortcut escape if separated by more than an octave
+
+ diff = f2-f1; //no need for fabs, f2>f1
+ //minf = //always f1 lower
+
+
+
+ d = v1*v2*(exp(a*diff) - exp(b*diff));
+
+ dissonancesum += d;
+ }
+
+ }
+
+ unit->dissonance_ = sc_min(unit->clamp_,dissonancesum*unit->norm_); //numpeaks;
//dissonancesum; //divide by fftsize as compensation for amplitudes via FFT
+
+ }
+
+
+ //ZOUT0(i) = unit->dissonance_;
+ ZOUT0(0) = unit->dissonance_;
+
+}
+
+
+PluginLoad(SensoryDissonance) {
+
+ init_SCComplex(inTable);
+
+ ft = inTable;
+
+ DefineDtorCantAliasUnit(SensoryDissonance);
+
+}
+
+
+
+
+
diff --git a/source/SCMIRUGens/sc/Classes/Chromagram.sc b/source/SCMIRUGens/sc/Classes/Chromagram.sc
new file mode 100644
index 0000000..77e9de5
--- /dev/null
+++ b/source/SCMIRUGens/sc/Classes/Chromagram.sc
<at> <at> -0,0 +1,13 <at> <at>
+Chromagram : MultiOutUGen {
+
+ *kr {
+ arg fft, fftsize=2048, n=12, tuningbase=32.703195662575, octaves=8, integrationflag=0, coeff=0.9;
+ ^this.multiNew('control', fft, fftsize, n, tuningbase, octaves, integrationflag, coeff);
+ }
+
+ init { arg ... theInputs;
+ inputs = theInputs;
+
+ ^this.initOutputs(theInputs[2], rate);
+ }
+}
diff --git a/source/SCMIRUGens/sc/Classes/FeatureSave.sc b/source/SCMIRUGens/sc/Classes/FeatureSave.sc
new file mode 100644
index 0000000..15e8586
--- /dev/null
+++ b/source/SCMIRUGens/sc/Classes/FeatureSave.sc
<at> <at> -0,0 +1,10 <at> <at>
+FeatureSave : UGen {
+
+ *kr {arg features, trig;
+
+
+ ^this.multiNewList(['control', features.size.max(1), trig] ++ features.asArray)
+ }
+
+}
+
diff --git a/source/SCMIRUGens/sc/Classes/SensoryDissonance.sc b/source/SCMIRUGens/sc/Classes/SensoryDissonance.sc
new file mode 100644
index 0000000..5fc6927
--- /dev/null
+++ b/source/SCMIRUGens/sc/Classes/SensoryDissonance.sc
<at> <at> -0,0 +1,11 <at> <at>
+SensoryDissonance : UGen {
+
+ *kr {
+ arg fft, maxpeaks=100, peakthreshold=0.1, norm, clamp=1.0;
+
+ norm = norm ?? {0.01/maxpeaks};
+
+ ^this.multiNew('control', fft, maxpeaks, peakthreshold, norm, clamp);
+ }
+
+}
diff --git a/source/SCMIRUGens/sc/HelpSource/Classes/Chromagram.schelp b/source/SCMIRUGens/sc/HelpSource/Classes/Chromagram.schelp
new file mode 100644
index 0000000..fbc5bc7
--- /dev/null
+++ b/source/SCMIRUGens/sc/HelpSource/Classes/Chromagram.schelp
<at> <at> -0,0 +1,135 <at> <at>
+class:: Chromagram
+summary:: Octave chroma band based representation of energy in a signal; Chromagram for nTET tuning
systems with any base reference
+related:: Classes/SensoryDissonance
+categories:: UGens>Analysis
+keyword:: Chroma, pitch class, equal temperament, filter bank
+
+Description::
+
+A chromagram, measuring the energy at particular chroma within an nTET tuning system.
+
+
+Possible extension:
+TODO: tritave and other non-standard octaves
+TODO: Could have arbitrary tuning systems if precalculated the exact fft bin + interpolation data.
+TODO: chroma as energy independent, relative to total fft energy in polled bins or whole spectrum?
+
+
+classmethods::
+
+method::kr
+
+
+argument::fft
+input fft chain, that is, from an FFT UGen
+argument::fftsize
+FFT size, required for initialisation
+argument::n
+Equal divisions of an octave, e.g. n=12 is 12TET, 12 steps in an octave
+argument::tuningbase
+Base frequency or tuning; will correspong to index 0 in results (conventionally, this would be a 'C' in
12TET, but its an arbitrary reference)
+argument::octaves
+Number of octaves considered from tuning base up
+argument::integrationflag
+Whether to integrate from frame to frame, off by default
+argument::coeff
+Coefficient of integration
+
+Examples::
+
+code::
+
+
+(
+{
+
+var in, fft, chroma;
+
+//in = SinOsc.ar(440,0,0.1);
+in= SoundIn.ar;
+
+fft = FFT(LocalBuf(2048), in);
+
+chroma=Chromagram.kr(fft);
+
+chroma.poll;
+
+Out.ar(0,Pan2.ar(in));
+}.play
+)
+
+
+
+//n TET display
+
+n= 12; //19, 24
+
+(
+x = {
+
+var in, fft, chroma;
+
+//in = SinOsc.ar(440,0,0.1);
+in= SoundIn.ar;
+
+fft = FFT(LocalBuf(2048), in);
+
+chroma=Chromagram.kr(fft, 2048, n);
+
+//chroma=Chromagram.kr(fft, 2048, n, 36.midicps, 7, 1, 0.9);
+
+Out.kr(0,chroma);
+}.play;
+
+c= Bus.new('control', 0, n);
+
+)
+
+
+
+//poll coefficients snapshot
+c.getn(n,{arg val; {val.plot;}.defer});
+
+
+
+//Continuous graphical display of Chromagram values; free routine before closing window
+
+(
+var ms;
+
+w=Window.new((n.asString)++" chroma coefficients", Rect(200,400,n*20+50,300));
+
+ms= MultiSliderView.new(w, Rect(10,10,n*20,280));
+
+ms.value_(Array.fill(n,0.0));
+ms.valueThumbSize_(20.0);
+ms.indexThumbSize_(20.0);
+ms.gap_(0);
+
+w.front;
+
+r= {
+
+inf.do{
+
+c.getn(n,{arg val; {ms.value_(val)}.defer});
+
+0.04.wait; //25 frames per second
+};
+
+}.fork;
+
+w.onClose = {
+r.stop;
+c.free;
+x.free;
+};
+
+)
+
+
+
+b.free;
+
+
+::
diff --git a/source/SCMIRUGens/sc/HelpSource/Classes/FeatureSave.schelp b/source/SCMIRUGens/sc/HelpSource/Classes/FeatureSave.schelp
new file mode 100644
index 0000000..e3a1169
--- /dev/null
+++ b/source/SCMIRUGens/sc/HelpSource/Classes/FeatureSave.schelp
<at> <at> -0,0 +1,38 <at> <at>
+class:: FeatureSave
+summary:: Storing feature data from UGens in NRT mode
+categories:: UGens>Analysis
+keyword:: NRT mode, feature data
+
+Description::
+
+Create files of feature data from analysis UGens in NRT mode.
+
+
+classmethods::
+
+method::kr
+
+argument::features
+input feature array for sampling on triggers
+argument::trig
+Trigger input, one stored feature vector at each trigger. Note that trig must be at least (-0.01) to
trigger, to allow bufnums of 0 to act as a trigger when driving things from FFT analysis
+
+Examples::
+
+code::
+
+//Should really only do this in NRT, but does work if low load in RT
+(
+a = {
+
+~featuresave = FeatureSave.kr(SinOsc.kr,Impulse.kr(10)-0.5);
+
+}.play
+)
+
+s.sendMsg("/u_cmd", a.nodeID, ~featuresave.synthIndex, "createfile", "testfile2.data")
+
+s.sendMsg("/u_cmd", a.nodeID, ~featuresave.synthIndex, "closefile")
+
+
+::
diff --git a/source/SCMIRUGens/sc/HelpSource/Classes/SensoryDissonance.schelp b/source/SCMIRUGens/sc/HelpSource/Classes/SensoryDissonance.schelp
new file mode 100644
index 0000000..21784ba
--- /dev/null
+++ b/source/SCMIRUGens/sc/HelpSource/Classes/SensoryDissonance.schelp
<at> <at> -0,0 +1,77 <at> <at>
+class:: SensoryDissonance
+summary:: Perceptual feature modeling sensory dissonance
+related:: Classes/Chromagram
+categories:: UGens>Analysis
+keyword:: psychoacoustic measure, sensory dissonance
+
+Description::
+
+Sensory Dissonance model, measuring roughness between pairs of prominent spectral peaks. Follows the
algorithm in William A. Sethares (1998) Consonance-Based Spectral Mappings. CMJ 22(1): 56-72.
+
+In usual use, you probably won't care about the other arguments; just pass an FFT in, assuming FFT size 2048
by default.
+
+
+classmethods::
+
+method::kr
+
+
+argument::fft
+input fft chain, that is, from an FFT UGen
+argument::maxpeaks
+Maximum number of spectral peaks detected; cannot be modulated, initialisation only.
+argument::peakthreshold
+Minimum spectral power detection threshold for a peak
+argument::norm
+Normalisation factor. Calculated for you in the UGen class if you don't provide one, but you can
experiment here. In combination with the next argument and maxpeaks, allows you to have alternative
range outputs if you so desire.
+argument::clamp
+Clamps very high dissonances, in default mode will end up with sensory dissonance measure in range 0.0 to 1.0
+
+Examples::
+
+code::
+
+
+(
+{
+
+var in, fft, dissonance;
+
+//in = SinOsc.ar(MouseX.kr(100,1000),0,0.1);
+//in = Mix(SinOsc.ar([440,MouseX.kr(440,880)],0,0.1));
+in= SoundIn.ar;
+
+fft = FFT(LocalBuf(2048), in);
+
+dissonance=SensoryDissonance.kr(fft);
+
+dissonance.poll;
+
+Out.ar(0,Pan2.ar(0.1*Blip.ar(100,(dissonance.sqrt)*200)));
+}.play
+)
+
+
+
+//different fftsize, max num peaks, own normalisation, avoid clamping by setting high value (more CPU
cost)
+(
+{
+
+var in, fft, dissonance;
+
+//in = SinOsc.ar(MouseX.kr(100,1000),0,0.1);
+//in = Mix(SinOsc.ar([440,MouseX.kr(440,880)],0,0.1));
+in= SoundIn.ar;
+
+fft = FFT(LocalBuf(4096), in);
+
+dissonance=SensoryDissonance.kr(fft,500,1.0,1.0,999999);
+
+dissonance.poll;
+
+Out.ar(0,SinOsc.ar(dissonance*0.1,0,0.1));
+}.play
+)
+
+
+::
-----------------------------------------------------------------------
Summary of changes:
source/CMakeLists.txt | 1 +
source/SCMIRUGens/Chromagram.cpp | 332 ++++++++++++++++++++
source/SCMIRUGens/FeatureSave.cpp | 213 +++++++++++++
source/SCMIRUGens/SensoryDissonance.cpp | 327 +++++++++++++++++++
source/SCMIRUGens/sc/Classes/Chromagram.sc | 13 +
source/SCMIRUGens/sc/Classes/FeatureSave.sc | 10 +
source/SCMIRUGens/sc/Classes/SensoryDissonance.sc | 11 +
.../sc/HelpSource/Classes/Chromagram.schelp | 135 ++++++++
.../sc/HelpSource/Classes/FeatureSave.schelp | 38 +++
.../sc/HelpSource/Classes/SensoryDissonance.schelp | 77 +++++
10 files changed, 1157 insertions(+), 0 deletions(-)
create mode 100644 source/SCMIRUGens/Chromagram.cpp
create mode 100644 source/SCMIRUGens/FeatureSave.cpp
create mode 100644 source/SCMIRUGens/SensoryDissonance.cpp
create mode 100644 source/SCMIRUGens/sc/Classes/Chromagram.sc
create mode 100644 source/SCMIRUGens/sc/Classes/FeatureSave.sc
create mode 100644 source/SCMIRUGens/sc/Classes/SensoryDissonance.sc
create mode 100644 source/SCMIRUGens/sc/HelpSource/Classes/Chromagram.schelp
create mode 100644 source/SCMIRUGens/sc/HelpSource/Classes/FeatureSave.schelp
create mode 100644 source/SCMIRUGens/sc/HelpSource/Classes/SensoryDissonance.schelp
hooks/post-receive
--
--
sc3-plugins
_______________________________________________
sc-dev mailing list
info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-dev/
search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/