xxxxxxxxxx
144
let song;
let fft;
let spectrum;
let lyricsData;
let currentLyricIndex = 0;
let currentLyricTime = 0;
let nextLyricTime = 0;
let lyricTextOpacity = 0;
function preload() {
song = loadSound("sjlt.mp3");
lyricsData = loadStrings("lyrics.csv");
// img = loadImage("icon.png");
}
function setup() {
createCanvas(500, 500);
fft = new p5.FFT();
// angleMode(DEGREES);
noStroke();
textSize(24);
textAlign(CENTER, CENTER);
fill(0);
if (lyricsData.length > 0) {
let firstTimestamp = lyricsData[0].split("]")[0].substring(1);
currentLyricTime = convertTimestampToSeconds(firstTimestamp);
nextLyricTime = currentLyricTime; // initializeing the nextLyricTime with the same value
}
}
function draw() {
background(255);
// image(img, width - img.width + 5, 0);
//analyze the audio spectrum
spectrum = fft.analyze();
//.analyse() returns Array: spectrum Array of energy (amplitude/volume) values across the frequency spectrum. Lowest energy (silence) = 0, highest possible is 255.
// reposition the origin
translate(width / 2, height / 2);
//to make as many circles as length of array of amplitudes
let numShapes = spectrum.length;
// beginShape();
let radius = 160;
for (let i = 0; i < numShapes; i++) {
// draw shapes based on audio spectrum array
// angle each value in a circle
let angle = map(i, 0, numShapes, 0, 360);
let amp = spectrum[i]/256 // values of the audio spectrum are from 0 to 255, normalizing amplitudes by dividinh by 256 so amplitudes range from 0 to 1
let r = radius + amp * 180;
let x = r * cos(angle);
let y = r * sin(angle);
// the louder a particular frequency band is at a given moment in the song, the larger the corresponding circle will be
//The more beats in a particular part, the more number of circles
// map the normalized amplitude to a range between 5 and 50 to determine the size of the shape
let size = map(amp, 0, 1, 5, 20);
//a gradient fill based on frequency amplitude
let c1 = color(255, 100, 100);
let c2 = color(100, 100, 255);
fill(lerpColor(c1, c2, amp));
// drawing shape
// rect(x,y,size+amp,size+amp)
ellipse(x, y, size, size);
// endShape()
}
// reseting translation
resetMatrix();
// display the current lyrics with color animation
displayLyric();
}
function mouseClicked() {
if (song.isPlaying()) {
song.pause();
noLoop();
} else {
song.play();
loop();
}
}
function displayLyric() {
// check if there are lyrics data and if the current lyrics index is within the length of file
if (lyricsData.length > 0 && currentLyricIndex < lyricsData.length) {
// check if the song is playing and the current audio time exceeds the nextLyricTime
if (song.isPlaying() && song.currentTime() >= nextLyricTime) {
// display the lyric text for the current index with animation
let lyricText = lyricsData[currentLyricIndex].split("]")[1];
// calculating the lerp amount based on lyricTextOpacity for text animation
let lerpAmount = lyricTextOpacity/255;
let lerpedColor = lerpColor(color(255, 100, 100), color(100, 100, 255), lerpAmount);
fill(lerpedColor);
text(lyricText, width / 2, height / 2);
lyricTextOpacity = 255;
// move to the next lyric
currentLyricIndex++;
// updating nextLyricTime with the timestamp of the next lyric
if (currentLyricIndex < lyricsData.length) {
let nextTimestamp = lyricsData[currentLyricIndex].split("]")[0].substring(1);
nextLyricTime = convertTimestampToSeconds(nextTimestamp);
}
} else {
// if the song is not at the next lyric yet, continue displaying the text
if (lyricTextOpacity > 0) {
let lyricText = lyricsData[currentLyricIndex - 1].split("]")[1];
// decrease text opacity
lyricTextOpacity -= 2;
let lerpAmount = lyricTextOpacity / 255;
let lerpedColor = lerpColor(color(255, 100, 100), color(100, 100, 255), lerpAmount);
fill(lerpedColor);
text(lyricText, width / 2, height / 2);
}
}
}
}
function convertTimestampToSeconds(timestamp) {
let timeParts = timestamp.split(":");
let minutes = float(timeParts[0]);
let seconds = float(timeParts[1]);
return minutes * 60 + seconds;
}