-
Notifications
You must be signed in to change notification settings - Fork 62
/
cubes.pde
347 lines (272 loc) · 10.1 KB
/
cubes.pde
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
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
import ddf.minim.*;
import ddf.minim.analysis.*;
Minim minim;
AudioPlayer song;
FFT fft;
// Variables qui définissent les "zones" du spectre
// Par exemple, pour les basses, on prend seulement les premières 4% du spectre total
float specLow = 0.03; // 3%
float specMid = 0.125; // 12.5%
float specHi = 0.20; // 20%
// Il reste donc 64% du spectre possible qui ne sera pas utilisé.
// Ces valeurs sont généralement trop hautes pour l'oreille humaine de toute facon.
// Valeurs de score pour chaque zone
float scoreLow = 0;
float scoreMid = 0;
float scoreHi = 0;
// Valeur précédentes, pour adoucir la reduction
float oldScoreLow = scoreLow;
float oldScoreMid = scoreMid;
float oldScoreHi = scoreHi;
// Valeur d'adoucissement
float scoreDecreaseRate = 25;
// Cubes qui apparaissent dans l'espace
int nbCubes;
Cube[] cubes;
//Lignes qui apparaissent sur les cotés
int nbMurs = 500;
Mur[] murs;
void setup()
{
//Faire afficher en 3D sur tout l'écran
fullScreen(P3D);
//Charger la librairie minim
minim = new Minim(this);
//Charger la chanson
song = minim.loadFile("song.mp3");
//Créer l'objet FFT pour analyser la chanson
fft = new FFT(song.bufferSize(), song.sampleRate());
//Un cube par bande de fréquence
nbCubes = (int)(fft.specSize()*specHi);
cubes = new Cube[nbCubes];
//Autant de murs qu'on veux
murs = new Mur[nbMurs];
//Créer tous les objets
//Créer les objets cubes
for (int i = 0; i < nbCubes; i++) {
cubes[i] = new Cube();
}
//Créer les objets murs
//Murs gauches
for (int i = 0; i < nbMurs; i+=4) {
murs[i] = new Mur(0, height/2, 10, height);
}
//Murs droits
for (int i = 1; i < nbMurs; i+=4) {
murs[i] = new Mur(width, height/2, 10, height);
}
//Murs bas
for (int i = 2; i < nbMurs; i+=4) {
murs[i] = new Mur(width/2, height, width, 10);
}
//Murs haut
for (int i = 3; i < nbMurs; i+=4) {
murs[i] = new Mur(width/2, 0, width, 10);
}
//Fond noir
background(0);
//Commencer la chanson
song.play(0);
}
void draw()
{
//Faire avancer la chanson. On draw() pour chaque "frame" de la chanson...
fft.forward(song.mix);
//Calcul des "scores" (puissance) pour trois catégories de son
//D'abord, sauvgarder les anciennes valeurs
oldScoreLow = scoreLow;
oldScoreMid = scoreMid;
oldScoreHi = scoreHi;
//Réinitialiser les valeurs
scoreLow = 0;
scoreMid = 0;
scoreHi = 0;
//Calculer les nouveaux "scores"
for(int i = 0; i < fft.specSize()*specLow; i++)
{
scoreLow += fft.getBand(i);
}
for(int i = (int)(fft.specSize()*specLow); i < fft.specSize()*specMid; i++)
{
scoreMid += fft.getBand(i);
}
for(int i = (int)(fft.specSize()*specMid); i < fft.specSize()*specHi; i++)
{
scoreHi += fft.getBand(i);
}
//Faire ralentir la descente.
if (oldScoreLow > scoreLow) {
scoreLow = oldScoreLow - scoreDecreaseRate;
}
if (oldScoreMid > scoreMid) {
scoreMid = oldScoreMid - scoreDecreaseRate;
}
if (oldScoreHi > scoreHi) {
scoreHi = oldScoreHi - scoreDecreaseRate;
}
//Volume pour toutes les fréquences à ce moment, avec les sons plus haut plus importants.
//Cela permet à l'animation d'aller plus vite pour les sons plus aigus, qu'on remarque plus
float scoreGlobal = 0.66*scoreLow + 0.8*scoreMid + 1*scoreHi;
//Couleur subtile de background
background(scoreLow/100, scoreMid/100, scoreHi/100);
//Cube pour chaque bande de fréquence
for(int i = 0; i < nbCubes; i++)
{
//Valeur de la bande de fréquence
float bandValue = fft.getBand(i);
//La couleur est représentée ainsi: rouge pour les basses, vert pour les sons moyens et bleu pour les hautes.
//L'opacité est déterminée par le volume de la bande et le volume global.
cubes[i].display(scoreLow, scoreMid, scoreHi, bandValue, scoreGlobal);
}
//Murs lignes, ici il faut garder la valeur de la bande précédent et la suivante pour les connecter ensemble
float previousBandValue = fft.getBand(0);
//Distance entre chaque point de ligne, négatif car sur la dimension z
float dist = -25;
//Multiplier la hauteur par cette constante
float heightMult = 2;
//Pour chaque bande
for(int i = 1; i < fft.specSize(); i++)
{
//Valeur de la bande de fréquence, on multiplie les bandes plus loins pour qu'elles soient plus visibles.
float bandValue = fft.getBand(i)*(1 + (i/50));
//Selection de la couleur en fonction des forces des différents types de sons
stroke(100+scoreLow, 100+scoreMid, 100+scoreHi, 255-i);
strokeWeight(1 + (scoreGlobal/100));
//ligne inferieure gauche
line(0, height-(previousBandValue*heightMult), dist*(i-1), 0, height-(bandValue*heightMult), dist*i);
line((previousBandValue*heightMult), height, dist*(i-1), (bandValue*heightMult), height, dist*i);
line(0, height-(previousBandValue*heightMult), dist*(i-1), (bandValue*heightMult), height, dist*i);
//ligne superieure gauche
line(0, (previousBandValue*heightMult), dist*(i-1), 0, (bandValue*heightMult), dist*i);
line((previousBandValue*heightMult), 0, dist*(i-1), (bandValue*heightMult), 0, dist*i);
line(0, (previousBandValue*heightMult), dist*(i-1), (bandValue*heightMult), 0, dist*i);
//ligne inferieure droite
line(width, height-(previousBandValue*heightMult), dist*(i-1), width, height-(bandValue*heightMult), dist*i);
line(width-(previousBandValue*heightMult), height, dist*(i-1), width-(bandValue*heightMult), height, dist*i);
line(width, height-(previousBandValue*heightMult), dist*(i-1), width-(bandValue*heightMult), height, dist*i);
//ligne superieure droite
line(width, (previousBandValue*heightMult), dist*(i-1), width, (bandValue*heightMult), dist*i);
line(width-(previousBandValue*heightMult), 0, dist*(i-1), width-(bandValue*heightMult), 0, dist*i);
line(width, (previousBandValue*heightMult), dist*(i-1), width-(bandValue*heightMult), 0, dist*i);
//Sauvegarder la valeur pour le prochain tour de boucle
previousBandValue = bandValue;
}
//Murs rectangles
for(int i = 0; i < nbMurs; i++)
{
//On assigne à chaque mur une bande, et on lui envoie sa force.
float intensity = fft.getBand(i%((int)(fft.specSize()*specHi)));
murs[i].display(scoreLow, scoreMid, scoreHi, intensity, scoreGlobal);
}
}
//Classe pour les cubes qui flottent dans l'espace
class Cube {
//Position Z de "spawn" et position Z maximale
float startingZ = -10000;
float maxZ = 1000;
//Valeurs de positions
float x, y, z;
float rotX, rotY, rotZ;
float sumRotX, sumRotY, sumRotZ;
//Constructeur
Cube() {
//Faire apparaitre le cube à un endroit aléatoire
x = random(0, width);
y = random(0, height);
z = random(startingZ, maxZ);
//Donner au cube une rotation aléatoire
rotX = random(0, 1);
rotY = random(0, 1);
rotZ = random(0, 1);
}
void display(float scoreLow, float scoreMid, float scoreHi, float intensity, float scoreGlobal) {
//Sélection de la couleur, opacité déterminée par l'intensité (volume de la bande)
color displayColor = color(scoreLow*0.67, scoreMid*0.67, scoreHi*0.67, intensity*5);
fill(displayColor, 255);
//Couleur lignes, elles disparaissent avec l'intensité individuelle du cube
color strokeColor = color(255, 150-(20*intensity));
stroke(strokeColor);
strokeWeight(1 + (scoreGlobal/300));
//Création d'une matrice de transformation pour effectuer des rotations, agrandissements
pushMatrix();
//Déplacement
translate(x, y, z);
//Calcul de la rotation en fonction de l'intensité pour le cube
sumRotX += intensity*(rotX/1000);
sumRotY += intensity*(rotY/1000);
sumRotZ += intensity*(rotZ/1000);
//Application de la rotation
rotateX(sumRotX);
rotateY(sumRotY);
rotateZ(sumRotZ);
//Création de la boite, taille variable en fonction de l'intensité pour le cube
box(100+(intensity/2));
//Application de la matrice
popMatrix();
//Déplacement Z
z+= (1+(intensity/5)+(pow((scoreGlobal/150), 2)));
//Replacer la boite à l'arrière lorsqu'elle n'est plus visible
if (z >= maxZ) {
x = random(0, width);
y = random(0, height);
z = startingZ;
}
}
}
//Classe pour afficher les lignes sur les cotés
class Mur {
//Position minimale et maximale Z
float startingZ = -10000;
float maxZ = 50;
//Valeurs de position
float x, y, z;
float sizeX, sizeY;
//Constructeur
Mur(float x, float y, float sizeX, float sizeY) {
//Faire apparaitre la ligne à l'endroit spécifié
this.x = x;
this.y = y;
//Profondeur aléatoire
this.z = random(startingZ, maxZ);
//On détermine la taille car les murs au planchers ont une taille différente que ceux sur les côtés
this.sizeX = sizeX;
this.sizeY = sizeY;
}
//Fonction d'affichage
void display(float scoreLow, float scoreMid, float scoreHi, float intensity, float scoreGlobal) {
//Couleur déterminée par les sons bas, moyens et élevé
//Opacité déterminé par le volume global
color displayColor = color(scoreLow*0.67, scoreMid*0.67, scoreHi*0.67, scoreGlobal);
//Faire disparaitre les lignes au loin pour donner une illusion de brouillard
fill(displayColor, ((scoreGlobal-5)/1000)*(255+(z/25)));
noStroke();
//Première bande, celle qui bouge en fonction de la force
//Matrice de transformation
pushMatrix();
//Déplacement
translate(x, y, z);
//Agrandissement
if (intensity > 100) intensity = 100;
scale(sizeX*(intensity/100), sizeY*(intensity/100), 20);
//Création de la "boite"
box(1);
popMatrix();
//Deuxième bande, celle qui est toujours de la même taille
displayColor = color(scoreLow*0.5, scoreMid*0.5, scoreHi*0.5, scoreGlobal);
fill(displayColor, (scoreGlobal/5000)*(255+(z/25)));
//Matrice de transformation
pushMatrix();
//Déplacement
translate(x, y, z);
//Agrandissement
scale(sizeX, sizeY, 10);
//Création de la "boite"
box(1);
popMatrix();
//Déplacement Z
z+= (pow((scoreGlobal/150), 2));
if (z >= maxZ) {
z = startingZ;
}
}
}