xxxxxxxxxx
134
let song;
let fft;
let spectrum;
let lyricsData; // Array to store lyrics data
let currentLyricIndex = 0; // Variable to keep track of the current lyric
let currentLyricTime = 0; // Variable to keep track of the current lyric's timestamp
let nextLyricTime = 0; // Variable to keep track of the next lyric's timestamp
let lyricTextOpacity = 0; // Variable to control text opacity
function preload() {
song = loadSound("sjlt.mp3");
// Load the CSV file containing lyrics data
lyricsData = loadStrings("lyrics.csv");
}
function setup() {
createCanvas(600, 600);
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; // initializing the nextLyricTime with the same value
}
}
function draw() {
background(255);
// image(img, width - img.width + 5, 0);
//analyze the audio spectrum
spectrum = fft.analyze();
// reposition the origin
translate(width / 2, height / 2);
//to make as many bars as the length of the array of amplitudes
let numBars = spectrum.length;
let barHeight = 10; // Height of each bar
for (let i = 0; i < numBars; i++) {
// Draw bars based on audio spectrum array
let angle = map(i, 0, numBars, 0, 360);
let amp = spectrum[i] / 256; // values of the audio spectrum are from 0 to 255, normalizing amplitudes by dividing by 256 so amplitudes range from 0 to 1
let r = 150 + amp * 350; // Adjust the radius based on amplitude
// Calculate the length of the bar based on amplitude
let barLength = map(amp, 0, 1, 10, 150); // Adjust the range as needed
// Apply a gradient fill based on frequency amplitude
let c1 = color(255, 100, 100);
let c2 = color(100, 100, 255);
fill(lerpColor(c1, c2, amp));
// Calculate the position of the bar
let x1 = r * cos(angle);
let y1 = r * sin(angle);
let x2 = x1; // Vertical bars have the same x-coordinates
let y2 = y1 - barLength; // Adjust the y-coordinate for the top of the bar
// Draw the bar
rectMode(CORNERS); // Set the mode to draw rectangles from the top-left corner
rect(x1, y1, x2, y2);
}
// Reset translation and rotation
resetMatrix();
// Display the current lyric with 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 lyric index is within bounds
if (lyricsData.length > 0 && currentLyricIndex < lyricsData.length) {
// Check if the song is playing and the current audio playback 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];
// Set text opacity to 100%
fill(0, 0, 0, 255);
text(lyricText, width / 2, height / 2);
// Animate text opacity
lyricTextOpacity = 255;
// Move to the next lyric
currentLyricIndex++;
// Update nextLyricTime with the timestamp of the next lyric if available
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;
// Set text opacity
fill(0, lyricTextOpacity);
text(lyricText, width / 2, height / 2);
}
}
}
}
function convertTimestampToSeconds(timestamp) {
let timeParts = timestamp.split(":");
let minutes = parseFloat(timeParts[0]);
let seconds = parseFloat(timeParts[1]);
return minutes * 60 + seconds;
}