-
Notifications
You must be signed in to change notification settings - Fork 81
/
sketch.js
188 lines (136 loc) · 4.7 KB
/
sketch.js
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
182
183
184
185
186
187
188
/*
Pre-analyze a song using the Echo Nest API. It returns a JSON file with every beat, segment, section and more.
Each segment contains a start time, an end time, and an array of pitches. The pitches represent pitch classes
(i.e. C, C#, D, D#, E, F, G, G#, A, A#, B, C).
Each item in the pitches array gets a value between 0 and 1.0 indicating
how much of that pitch class is present in the section.
In this example, each slice of the pie represents one pitch class.
The size of the slices increases for every Echo Nest beat.
And the rotation changes when Echo Nest thinks there is a new section.
-- HOW TO USE THE ECHO NEST ANALYZER --
First, you'll need an API Key from developer.echonest.com.
Then, open up the terminal and make this POST request with your mp3 path and API key:
Then, Upload your file to the Echo Nest by entering this in the commnd line:
curl -F "api_key=[YOURAPIKEY]" -F "filetype=mp3" -F "track=@[PATH]" "http://developer.echonest.com/api/v4/track/upload"
wait for the response...and copy the 'id' which is unique to your track upload.
Paste the ID and your API key into this GET request:
http://developer.echonest.com/api/v4/track/profile?api_key=[YOURAPIKEY]&format=json&id=[YOURTRACKID]&bucket=audio_summary
Click through to analysis_url, and save that JSON file
more info http://developer.echonest.com/raw_tutorials/faqs/faq_03.html
Further reading: http://developer.echonest.com/docs/v4/_static/AnalyzeDocumentation.pdf
*/
var echonestAnalysis;
var cnv;
var notes = new Array(12);
var audioEl;
var maxDiameter;
var rotation = 0;
var rotations;
var rotationIncrement;
var bgColor;
function setup() {
cnv = createCanvas(windowWidth, windowHeight);
noStroke();
bgColor = color(253,254,250, 30);
colorMode(HSB, 255);
maxDiameter = width;
translate(width/2, height/2);
rotations = [0, PI/60, -PI/60, PI/32, -PI/32, PI/18, PI/6, -PI/18, -PI/6, PI/12];
rotationIncrement = rotations[0];
// draw keys
for (var i = 0; i < notes.length; i++) {
var diameter = width/8;
var angle = TWO_PI/notes.length;
var hue = round( map(i, 0, notes.length, 0, 255) );
var c = color(hue, 170, 250, 200);
notes[i] = new Arc(i, diameter, angle, c);
notes[i].draw();
}
loadJSON('../../music/Peter_Johnston_-_La_ere_gymnopedie.json', gotData);
audioEl = createAudio('../../music/Peter_Johnston_-_La_ere_gymnopedie.mp3');
}
function draw() {
background(bgColor);
rotate(rotation += rotationIncrement);
for (var i = 0; i < notes.length; i++) {
notes[i].draw();
}
}
// callback from loadJSON
function gotData(data) {
echonestAnalysis = data;
scheduleSegments(data.segments);
scheduleSections(data.bars);
audioEl.play();
}
// schedule timeline events based on json data
function scheduleSegments(segments) {
for (var i = 0; i < segments.length; i++) {
var seg = segments[i];
if (seg.confidence > 0.01) {
var startTime = seg.start;
var endTime = seg.start + seg.duration;
var pitches = seg.pitches;
audioEl.addCue(startTime, triggerNote, pitches);
audioEl.addCue(endTime, releaseNote);
}
}
}
function scheduleSections(sections) {
for (var i = 0; i < sections.length; i++) {
var section = sections[i];
var startTime = section.start;
audioEl.addCue(startTime, changeRotation, i);
}
}
// callbacks from timeline events
function triggerNote(pitches) {
var pitchThreshold = 0.5;
for (var i = 0; i < notes.length; i++) {
if (pitches[i] > pitchThreshold) {
notes[i].triggerNote(pitches[i]);
notes[i].triggerBeat();
}
}
}
function releaseNote() {
for (var i = 0; i < notes.length; i++) {
notes[i].releaseNote();
}
}
function changeRotation(index) {
rotationIncrement = rotations[index % rotations.length];
}
// Arc class
var Arc = function(index, diameter, angle, c) {
this.index = index;
this.diameter = diameter;
this.extraRad = 1;
this.angle = angle;
this.color = c;
this.alpha = this.color.rgba[3];
this.decayRate = 0.95;
}
Arc.prototype.triggerNote = function(val) {
this.alpha = 255 * val;
this.decayRate = 1 + val/25;
this.color.rgba[3] = this.alpha;
}
Arc.prototype.releaseNote = function() {
this.decayRate = 0.9;
}
Arc.prototype.triggerBeat = function() {
this.extraRad = 100;
this.radRate = 1.3;
}
Arc.prototype.draw = function() {
this.alpha *= this.decayRate;
this.extraRad *= this.radRate * this.decayRate;
this.extraRad = constrain(this.extraRad, 0.01, maxDiameter);
this.radRate *= 0.98;
this.radRate = constrain(this.radRate, 0.9, 1.5);
this.color.rgba[3] = this.alpha;
fill(this.color);
var d = this.diameter + this.extraRad;
arc(0, 0, d, d, this.index*this.angle, (this.index*this.angle) + this.angle);
}