#include "ext.h"
#include <cmath>
#define BUFFERSZ 1000
typedef struct {
long ts, note;
} NoteInfo;
typedef struct {
t_object max_data;
NoteInfo memory[BUFFERSZ];
long writeindex, windowsize, tonic, certainty, mode;
void *outputTonic, *outputCertainty, *outputMode;
} MyObject;
void* object_data = NULL;
void* create_object (long windowsizeinit);
void InputBang (MyObject* mo);
void InputNote (MyObject* mo, long value);
void InputWindowSize (MyObject* mo, long value);
void MessageClear (MyObject* mo);
long midilimit (long value);
void doAnalysis (MyObject* mo);
void storeNoteInMemory (MyObject* mo, long note, long timestamp);
void makeHistogram (double histogram[12], NoteInfo memory[BUFFERSZ],
long writeindex, long curtime, long windowsize);
void main(void) {
setup((t_messlist**)&object_data, (method)create_object,
NULL, sizeof(MyObject), NULL, A_DEFLONG, A_NOTHING);
addbang((method)InputBang);
addint ((method)InputNote);
addinx ((method)InputWindowSize, 1);
}
void* create_object(long windowsizeinit) {
MyObject* mo = (MyObject*)newobject(object_data);
if (windowsizeinit == 0) InputWindowSize(mo, 7000);
else InputWindowSize(mo, windowsizeinit);
MessageClear(mo);
mo->outputMode = intout(mo);
mo->outputCertainty = intout(mo);
mo->outputTonic = intout(mo);
intin(mo, 1);
return mo;
}
void InputBang(MyObject* mo) {
doAnalysis(mo);
outlet_int(mo->outputMode, mo->mode);
outlet_int(mo->outputCertainty, mo->certainty);
outlet_int(mo->outputTonic, mo->tonic);
}
void InputNote(MyObject* mo, long value) {
storeNoteInMemory(mo, value, gettime());
}
void InputWindowSize(MyObject* mo, long value) {
if (value < 10) value = 10;
else if (value > 600000) value = 600000;
mo->windowsize = value;
}
void MessageClear(MyObject* mo) {
int i;
for (i=0; i<BUFFERSZ; i++) {
mo->memory[i].ts = mo->memory[i].note = -1;
}
mo->writeindex = mo->tonic = mo->certainty = mo->mode = 0;
}
long midilimit(long value) {
if (value < 0) return 0;
if (value > 127) return 127;
return value;
}
void storeNoteInMemory(MyObject* mo, long note, long timestamp) {
mo->memory[mo->writeindex].note = midilimit(note);
mo->memory[mo->writeindex].ts = timestamp;
mo->writeindex += 1;
if (mo->writeindex >= BUFFERSZ) mo->writeindex = 0;
}
void makeHistogram(double histogram[12], NoteInfo memory[BUFFERSZ],
long writeindex, long curtime, long windowsize) {
int i;
int index;
for (i=0; i<12; i++) histogram[i] = 0.0;
for (i=0; i<BUFFERSZ; i++) {
index = writeindex - 1 - i;
if (index < 0) index = (index + 2 * BUFFERSZ) % BUFFERSZ;
if (curtime - memory[index].ts > windowsize) break;
if (memory[index].note < 0) break;
histogram[memory[index].note % 12] += 1.0;
}
}
void doAnalysis(MyObject* mo) {
double majorKey[12] =
{6.35, 2.23, 3.48, 2.33, 4.38, 4.09, 2.52, 5.19, 2.39, 3.66, 2.29, 2.88};
double minorKey[12] =
{6.33, 2.68, 3.52, 5.38, 2.60, 3.53, 2.54, 4.75, 3.98, 2.69, 3.34, 3.17};
double major_mean = 3.482500, minor_mean = 3.709167;
double maj_temp, min_temp, temp, mean, r_major[12], r_minor[12];
double maj_numerator, min_numerator, maj_denominator, min_denominator;
double best_key, second_best_key, confidence, total = 0;
int subscript, i, j, sec_pitch_class, pitch_class;
long mode = 0;
double histogram[12];
makeHistogram(histogram, mo->memory, mo->writeindex, gettime(), mo->windowsize);
for (i=0; i<12; i++) total += histogram[i];
mean = total/12.0;
for (i=0; i<12; i++) {
maj_numerator = min_numerator = 0;
maj_denominator = min_denominator = 0;
maj_temp = min_temp = temp = 0;
for (j=0; j<12; j++) {
subscript = (i+j) % 12;
temp += (histogram[subscript] - mean) * (histogram[subscript] - mean);
maj_numerator += (majorKey[j]-major_mean) * (histogram[subscript]-mean);
maj_temp += (majorKey[j] - major_mean) * (majorKey[j] - major_mean);
min_numerator += (minorKey[j]-minor_mean) * (histogram[subscript]-mean);
min_temp += (minorKey[j] - minor_mean) * (minorKey[j] - minor_mean);
}
maj_denominator = sqrt(maj_temp * temp);
min_denominator = sqrt(min_temp * temp);
if (maj_denominator == 0 || min_denominator == 0) {
mo->tonic = mo->certainty = mo->mode;
return;
}
r_major[i] = maj_numerator / maj_denominator;
r_minor[i] = min_numerator / min_denominator;
}
best_key = 0.0;
pitch_class = 0;
for (i=0; i<12; i++) {
if (r_major[i] > best_key) {
best_key = r_major[i];
mode = 0;
pitch_class = i;
}
if (r_minor[i] > best_key) {
best_key = r_minor[i];
mode = 1;
pitch_class = i;
}
}
second_best_key = 0;
sec_pitch_class = 0;
for (i=0; i<12; i++) {
if (r_major[i] != best_key && r_major[i] > second_best_key) {
second_best_key = r_major[i];
sec_pitch_class = i;
}
if (r_minor[i] != best_key && r_minor[i] > second_best_key) {
second_best_key = r_minor[i];
sec_pitch_class = i;
}
}
confidence = (best_key - second_best_key) * 100 * 3.0;
if (confidence > 100.0) confidence = 100.0;
mo->tonic = pitch_class;
mo->certainty = (int)(127.0 * confidence/100.0);
mo->mode = mode;
}
|