This file is indexed.

/usr/share/SuperCollider/HelpSource/Classes/KeyTrack.schelp is in supercollider-common 1:3.8.0~repack-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
class:: KeyTrack
summary:: Key tracker
categories:: UGens>Analysis>Pitch
related:: Classes/BeatTrack, Classes/Loudness, Classes/MFCC, Classes/Onsets, Classes/Pitch

description::
A (12TET major/minor) key tracker based on a pitch class profile of energy across FFT bins and matching this to templates for major and minor scales in all transpositions. It assumes a 440 Hz concert A reference. Output is 0-11 C major to B major, 12-23 C minor to B minor.

classmethods::

method:: kr

argument:: chain
[fft] Audio input to track. This must have been pre-analysed by a 4096 size FFT. No other FFT sizes are valid except as noted below.
code::
// With standard hop of half FFT size = 2048 samples
b = Buffer.alloc(s,4096,1); // for sampling rates 44100 and 48000
//b = Buffer.alloc(s,8192,1); // for sampling rates 88200 and 96000
::

argument:: keydecay
[sk] Number of seconds for the influence of a window on the final key decision to decay by 40dB (to 0.01 its original value).

argument:: chromaleak
[sk] Each frame, the chroma values are set to the previous value multiplied by the chromadecay. 0.0 will start each frame afresh with no memory.

examples::

code::
// The following files are test materials on my machine; you will subsitute your own filenames here
// A major
d = Buffer.read(s,"/Volumes/data/stevebeattrack/samples/100.wav");
// F major; hard to track!
d = Buffer.read(s,"/Volumes/data/stevebeattrack/samples/115.wav");

// straight forward since no transients; training set from MIREX2006
// 01 = A major
// 57 = b minor
// 78 e minor
// 08 Bb major
d = Buffer.read(s, "/Users/nickcollins/Desktop/ML/training_wav/78.wav")

b = Buffer.alloc(s, 4096, 1); // for sampling rates 44100 and 48000

(
{
var in, fft, resample;
var key, transientdetection;

in = PlayBuf.ar(1, d, BufRateScale.kr(d), 1, 0, 1);

fft = FFT(b, in);

key=KeyTrack.kr(fft, 2.0, 0.5);

key.poll;

Out.ar(0,Pan2.ar(in));
}.play
)
::



code::
// alternating major and minor chords as a test
(
{
var in, fft, resample;
var key, transientdetection;

in = Mix(SinOsc.ar((60 + [0, MouseX.kr(3, 4).round(1), 7]).midicps, 0, 0.1));

// major dom 7 and minor 7; major keys preferred here
//in = Mix(SinOsc.ar((60 + (MouseY.kr(0, 11).round(1.0)) + [0, MouseX.kr(3, 4).round(1), 7, 10]).midicps, 0, 0.1));

fft = FFT(b, in);

key = KeyTrack.kr(fft);

key.poll;

Out.ar(0,Pan2.ar(in));
}.play
)
::



code::
// Nice to hear what KeyTrack thinks:

d = Buffer.read(s, "/Users/nickcollins/Desktop/ML/training_wav/78.wav")
b = Buffer.alloc(s, 4096, 1); // for sampling rates 44100 and 48000

(
{
var in, fft, resample, chord, rootnote, sympath;
var key, transientdetection;

in = PlayBuf.ar(1, d, BufRateScale.kr(d), 1, 0, 1);

fft = FFT(b, in);

key = KeyTrack.kr(fft, 2.0, 0.5);
key.poll;
key = Median.kr(101, key); // Remove outlier wibbles

chord = if(key<12, #[0, 4, 7], #[0, 3, 7]);
rootnote = if(key<12, key, key-12) + 60;

sympath = SinOsc.ar((rootnote + chord).midicps, 0, 0.4).mean;

Out.ar(0,Pan2.ar(in, -0.5) + Pan2.ar(sympath, 0.5));
}.play
)
::



code::
// Research Notes:
// See the MIREX2006 audio key tracking competition and Emilia Gomez's PhD thesis, Tonal Description of Music Audio Signals

// The following code was used to create the datasets for the UGen, and would be the basis of extensions

// Need one set of bin data for 44100 and one for 48000

// KeyTrack calculations, need to make arrays of FFT bins and weights for each chromatic tone.
// greater resolution, 4096 FFT, avoid lower octaves, too messy there
// 60*6*2 output arrays

(
var fftN, fftBins, binsize;
var midinotes;
var sr;
var wtlist, binlist;

sr = 48000; //44100;

fftN = 4096;
fftBins = fftN.div(2);
binsize = sr / fftN;

midinotes = (33..92); // 60 notes, 55 Hz up to 1661.2187903198 Hz

wtlist = List[];
binlist = List[];

// for each note have six harmonic locations
midinotes.do{ |note|
	var freq, whichbin, lowerbin, prop;

	freq = note.midicps;

	6.do{|j|
		var partialfreq, partialamp;

		partialamp = 1.0 / (j + 1);
		partialfreq = freq * (j + 1);

		whichbin = partialfreq / binsize;
		lowerbin = whichbin.asInteger;
		prop = 1.0 - (whichbin - lowerbin);

		binlist.add(lowerbin).add(lowerbin + 1);
		wtlist.add(prop * partialamp).add((1.0 - prop) * partialamp);

	};

};


Post << (binlist) << nl<< nl;

Post << (wtlist) << nl<< nl;

binlist.size.postln;
wtlist.size.postln;
)
::