-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathAnalyzeSound.java
More file actions
299 lines (254 loc) · 9.61 KB
/
Copy pathAnalyzeSound.java
File metadata and controls
299 lines (254 loc) · 9.61 KB
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
import processing.core.*;
import processing.data.*;
import processing.opengl.*;
import ddf.minim.analysis.*;
import ddf.minim.*;
import java.applet.*;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.MouseEvent;
import java.awt.event.KeyEvent;
import java.awt.event.FocusEvent;
import java.awt.Image;
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.zip.*;
import java.util.regex.*;
public class AnalyzeSound extends PApplet {
/**
* This sketch demonstrates how to use an FFT to analyze
* the audio being generated by an AudioPlayer.
* <p>
* FFT stands for Fast Fourier Transform, which is a
* method of analyzing audio that allows you to visualize
* the frequency content of a signal. You've seen
* visualizations like this before in music players
* and car stereos.
*/
final static String file = "jingle.mp3";//"C:/Users/Eugene/Documents/Processing/AnalyzeSound/application.windows64/[Dubstep] - Noisestorm - Breakdown [Monstercat Release].mp3";//"C:/Users/Eugene/Desktop/Hey Soul Sister.mp3";//"C:/Users/Eugene/Downloads/[Electro] - Rogue - Adventure Time [Monstercat Release].mp3";//"C:/Users/Eugene/Desktop/Hey Soul Sister.mp3";//"C:/Users/Eugene/Desktop/Everyday - Carly Comando.mp3";//"C:/Users/Eugene/Documents/1005198.mp3";
Minim minim;
AudioPlayer jingle;
FFT fft;
double[] previous;
int[] timeSinceChange;
int sampleRate = 1024;
int frames = 0;
boolean barGraphDisplay = true;
final static String songReference = "song";
private final static String widthReference = "width";
private final static String heightReference = "height";
private final static String numBarsReference = "bars";
private final static String cutoffReference = "cutoff";
private int numBars = 100;
private double cutoffFrequency = 0.4f;
static Hashtable<String, String> params=new Hashtable<String, String>();
/**
dynamicsize taken from http://www.processinghacks.com/hacks/dynamicsize
@author toxi (http://www.processinghacks.com/user/toxi)
*/
// this table is used to store all command line parameters
// in the form: name=value
// here we overwrite PApplet's main entry point (for application mode)
// we're parsing all commandline arguments and copy only the relevant ones
static public void main(String args[]) {
String[] newArgs=new String[args.length+1];
/*********************************************************
/* IMPORTANT: replace this with the name of your sketch *
/*********************************************************/
newArgs[0]="AnalyzeSound";
for(int i=0; i<args.length; i++) {
newArgs[i+1]=args[i];
println(args[i]);
if (args[i].indexOf("=")!=-1) {
String[] pair=split(args[i], '=');
params.put(pair[0],pair[1]);
}
}
println("Parameters given: "+params);
// pass on to PApplet entry point
PApplet.main(newArgs);
}
// now we also overwrite the default param() function
// if we're not online (i.e. running as application), the new function
// will use the Hashtable to find the param
public String param(String id) {
if (online) return super.param(id);
else return (String)params.get(id);
}
public int iParam(String id, int defaultValue){
try{
return Integer.parseInt(param(id));
}
catch(Exception e){}
return defaultValue;
}
public String sParam(String id, String defaultValue)
{
String param = param(id);
if(param == null)
return defaultValue;
return param;
}
public double dParam(String id, double defaultValue){
try{
return Double.parseDouble(param(id));
}
catch(Exception e){}
return defaultValue;
}
public void setup()
{
String song = sParam(songReference, file);
int inputWidth = iParam(widthReference, 512);//512);
int inputHeight = iParam(heightReference, 200);//);
int inputBars = iParam(numBarsReference, 8);//102);
double cutoffFrequency = Math.max(0.01f, Math.min(dParam(cutoffReference, 0.4f),1));
println("Analyzing & Playing "+song);
println(inputWidth+"x"+inputHeight+" window, "+inputBars+" bars.");
println("Cutoff frequency:"+cutoffFrequency);
frame.setTitle("MusicVisualizer++ by Eugene Raether");
//frame.setResizable(true);
size(inputWidth, inputHeight, P3D);
this.cutoffFrequency = cutoffFrequency;
this.numBars = inputBars;
minim = new Minim(this);
// specify that we want the audio buffers of the AudioPlayer
// to be 1024 samples long because our FFT needs to have
// a power-of-two buffer size and this is a good size.
jingle = minim.loadFile(song, sampleRate);
// loop the file indefinitely
jingle.loop();
// create an FFT object that has a time-domain buffer
// the same size as jingle's sample buffer
// note that this needs to be a power of two
// and that it means the size of the spectrum will be half as large.
fft = new FFT( jingle.bufferSize(), jingle.sampleRate() );
}
public void draw()
{
background(0);
stroke(255);
// perform a forward FFT on the samples in jingle's mix buffer,
// which contains the mix of both the left and right channels of the file
fft.forward( jingle.mix );
/*
for(int i = 0; i < fft.specSize(); i++)
{
// draw the line for frequency band i, scaling it up a bit so we can see it
line( i, height, i, height - fft.getBand(i)*multiplier );
}
*/
stroke(0, 255, 0);
//scale((float)(1+Math.pow(Math.sin(frames*Math.PI/360),2)*-0.1));
/*camera(55, 55+mouseX/60, -180, // eyeX, eyeY, eyeZ
55,55,55, // centerX, centerY, centerZ
0, 0, 1); // upX, upY, upZ*/
// camera();
// rotateX((float)(Math.sin(Math.PI*frames/640)/12));//(float)Math.sin(frames*Math.PI/24)/8);
//rotateX((float)(mouseX/(double)width*2*Math.PI));//(float)(Math.sin(-Math.PI*frames/640)/12));
//translate(0,0,-mouseY);
//translate(-width/2, -height/2);
int maxRangeUsed = (int)(fft.specSize()*this.cutoffFrequency);
double widthMultiplier = width/(double)maxRangeUsed;
int bands = this.numBars;//width/5;//, maxRangeUsed/4);//(int)((maxRangeUsed/4));
if (previous == null)
{
previous = new double[bands];
timeSinceChange = new int[bands];
}
int numBandsMergedTogether = Math.max(maxRangeUsed/bands,1);
float strokeWidth = (float)Math.max(numBandsMergedTogether/2.0f*widthMultiplier, 1);
PShape path = createShape();
path.noFill();
path.stroke(255);
path.strokeWeight(2);
int maxTotal = 255;
double multiplier = height-1;
colorMode(HSB, 360, 100, 100);
double particleDescentMultiplier = 0.030f;
double exponentialAmplificationMultiplier = 0.7f;//mouseX/(double)width;//0.8;
smooth();
for (int i=0;i<bands;i++)
{
double total = 0;
for (int j=0;j<numBandsMergedTogether;j++)
{
total += fft.getBand(i*numBandsMergedTogether+j);
}
total = (Math.min(total/Math.pow(numBandsMergedTogether, 0.5f), maxTotal)*Math.sqrt(i+1))/(double)maxTotal;
if(total > 0.85f)
{
double absMax = 3.5f;
if(total >= absMax)
total = absMax;
total = 0.85f + Math.pow((total-0.85f)/5,3);
}
total = Math.pow(total,exponentialAmplificationMultiplier);
int threshold = 10;
if (timeSinceChange[i] > threshold)
previous[i] -= (Math.pow(timeSinceChange[i] - threshold, 0.2f)-1)*particleDescentMultiplier;
if (previous[i] < total)
{
previous[i] = total;
timeSinceChange[i] = 0;
//previous[i] = previous[i] + (total-previous[i])*2;
//timeSinceChange[i] = 9;
}
timeSinceChange[i]++;
int xValue = (int)((i+0.5f)*numBandsMergedTogether*widthMultiplier);
double sat = 1-total;
if(barGraphDisplay)
{ stroke((int)(100*sat+20), 100, 100);
//line(xValue, height, xValue, (int)(height - total*multiplier) );
int startX = (int)(xValue-strokeWidth/2.0f);
int endX = (int)(xValue+strokeWidth/2.0f)+1;
generateGradient(startX, height, endX, (int)(height - total*multiplier), 120, (int)(120*sat),100,100);//100,100,120, 100,100,(int)(120*sat) );
// stroke(0, 0, 100);
// strokeWeight(strokeWidth);
generateGradient(startX, (int)(height-previous[i]*multiplier), endX, (int)(height-previous[i]*multiplier-height/66),80,80,(int)(40*Math.sin(frames*Math.PI/360.0f)),100);//80,0,0,100,0,0);
//path.vertex((int)(xValue), (int)(height-previous[i]*multiplier));
}
path.vertex((int)(xValue), (int)(height - total*multiplier) );
}
float songAvg = 0;
//smooth out curve
for (int i=0;i<path.getVertexCount();i++)
{
songAvg += path.getVertex(i).y;
int avgVertexY = 0;
int smoothing = 0;
int startIndex = Math.max(i-smoothing, 0);
int endIndex = Math.min(i+smoothing, bands-1);
for (int x=startIndex;x<=endIndex;x++)
avgVertexY += path.getVertex(x).y;
avgVertexY /= (endIndex-startIndex+1);
path.setVertex(i, path.getVertex(i).x, avgVertexY);
}
smooth();
path.end();
path.stroke(((frames++)*0.1f)%360,100,100);
if(!barGraphDisplay)
shape(path);
}
// Generate a vertical gradient
//System.out.println(startX+","+startY+","+endX+","+endY+","+startSat+","+endSat);
//learn map or lerp or whatever to interpolate all 3
public void generateGradient(int startX, int startY, int endX, int endY, int startSat, int endSat, int hueSat, int brightnessSat) {
colorMode(HSB,360,100,100);
int dX = Math.abs(endX-startX);
int dY = Math.abs(endY-startY);
double changePerPixel = (endSat-startSat)/(double)dY;
strokeWeight(2);
int changePerFrameY = endY > startY ? 1 : -1;
for(int i=0;i<Math.abs(dY);i++){
stroke((int)(startSat+changePerPixel*i),hueSat,brightnessSat);
line(startX, i*changePerFrameY+startY, endX, i*changePerFrameY+startY);
}
}
public void mouseClicked() {
barGraphDisplay = !barGraphDisplay;
println("MouseX:"+mouseX+",MouseY:"+mouseY);
}
}