Commit 7b67c9c1 by PLN (Algolia)

viz: v2

parent 9a16f5db
/** /**
* Background class * Background class - Improved version
* *
* Creates a dynamic cyberpunk background with subtle animations * Creates a dynamic cyberpunk background with subtle animations
* Reduced visual noise for better event visibility
*/ */
class Background { class Background {
// Background properties // Background properties
...@@ -10,19 +11,19 @@ class Background { ...@@ -10,19 +11,19 @@ class Background {
color accentColor2; color accentColor2;
// Movement properties // Movement properties
float noiseScale = 0.02; float noiseScale = 0.01; // Reduced from 0.02 for subtler pattern
float noiseOffset = 0; float noiseOffset = 0;
float noiseSpeed = 0.005; float noiseSpeed = 0.003; // Reduced from 0.005 for slower movement
// Timing // Timing
float cps = 0.5; float cps = 0.5;
float lastCycleTime = 0; float lastCycleTime = 0;
Background() { Background() {
// Dark cyberpunk colors // Darker cyberpunk colors for better contrast with events
bgColor = color(10, 12, 18); bgColor = color(5, 7, 12); // Darker than original
accentColor1 = color(0, 70, 100); accentColor1 = color(0, 50, 80); // More subtle
accentColor2 = color(60, 0, 80); accentColor2 = color(40, 0, 60); // More subtle
} }
void update() { void update() {
...@@ -39,58 +40,60 @@ class Background { ...@@ -39,58 +40,60 @@ class Background {
void display() { void display() {
// Create gradient background // Create gradient background
noiseDetail(8, 0.5); noiseDetail(4, 0.4); // Simplified noise
// Fill with base color // Fill with base color - more transparent for more visible motion trails
noStroke(); noStroke();
fill(bgColor, 40); // Semi-transparent for motion blur effect fill(bgColor, 30); // Reduced from 40
rect(0, 0, width, height); rect(0, 0, width, height);
// Add subtle noise pattern // Add subtle noise pattern
float motionFactor = sin(millis() * 0.001) * 0.5 + 0.5; float motionFactor = sin(millis() * 0.0005) * 0.5 + 0.5; // Slowed from 0.001
loadPixels(); // Reduced noise pattern density - iterate every 8 pixels instead of 4
for (int y = 0; y < height; y += 4) { for (int y = 0; y < height; y += 8) {
for (int x = 0; x < width; x += 4) { for (int x = 0; x < width; x += 8) {
float noiseVal = noise(x * noiseScale, y * noiseScale, noiseOffset); float noiseVal = noise(x * noiseScale, y * noiseScale, noiseOffset);
if (noiseVal > 0.7) { // Only draw higher noise values (reduced density)
if (noiseVal > 0.8) { // Increased from 0.7
color pixelColor; color pixelColor;
// Create different zones // Create different zones
if (noiseVal > 0.85) { if (noiseVal > 0.9) { // Increased from 0.85
// Highlight areas // Highlight areas
pixelColor = lerpColor(accentColor1, accentColor2, pixelColor = lerpColor(accentColor1, accentColor2,
sin(x * 0.01 + millis() * 0.0005) * 0.5 + 0.5); sin(x * 0.005 + millis() * 0.0002) * 0.5 + 0.5);
pixelColor = color(red(pixelColor), green(pixelColor), blue(pixelColor), pixelColor = color(red(pixelColor), green(pixelColor), blue(pixelColor),
20 + 20 * motionFactor); 15 + 10 * motionFactor); // Reduced from 20+20
} else { } else {
// Subtle accent // Subtle accent
pixelColor = lerpColor(bgColor, accentColor1, 0.3); pixelColor = lerpColor(bgColor, accentColor1, 0.2); // Reduced from 0.3
pixelColor = color(red(pixelColor), green(pixelColor), blue(pixelColor), 10); pixelColor = color(red(pixelColor), green(pixelColor), blue(pixelColor), 8); // Reduced from 10
} }
// Draw 4x4 pixel block for better performance // Draw 8x8 pixel block for better performance and subtler texture
fill(pixelColor); fill(pixelColor);
rect(x, y, 4, 4); rect(x, y, 8, 8);
} }
} }
} }
// Draw horizontal scan lines // Draw horizontal scan lines - fewer and more subtle
drawScanlines(); drawScanlines();
} }
void drawScanlines() { void drawScanlines() {
stroke(255, 8); // Fewer scan lines (every 8 pixels instead of 4)
stroke(255, 5); // Reduced from 8
strokeWeight(1); strokeWeight(1);
for (int y = 0; y < height; y += 4) { for (int y = 0; y < height; y += 8) {
line(0, y, width, y); line(0, y, width, y);
} }
// Draw brighter scanline that moves // Draw brighter scanline that moves
float movingScanline = (millis() % 5000) / 5000.0 * height; float movingScanline = (millis() % 8000) / 8000.0 * height; // Slower movement (5000 to 8000)
stroke(255, 15); stroke(255, 10); // Reduced from 15
strokeWeight(2); strokeWeight(2);
line(0, movingScanline, width, movingScanline); line(0, movingScanline, width, movingScanline);
} }
......
/** /**
* Grid class * Grid class - Improved version
* *
* Creates a cyberpunk grid with pulse effects that react to the music * Creates a cyberpunk grid with pulse effects that react to the music
* Reduced number of lines for cleaner visuals
*/ */
class Grid { class Grid {
// Grid properties // Grid properties
...@@ -17,9 +17,18 @@ class Grid { ...@@ -17,9 +17,18 @@ class Grid {
color gridColor; color gridColor;
color accentColor; color accentColor;
// Reduced line counts for cleaner visuals
int verticalLines = 10; // reduced from 20
int horizontalLines = 8; // reduced from 15
int polarCircles = 5; // reduced from 10
int polarRadials = 8; // reduced from 16
// Alpha values for better visibility
int defaultAlpha = 30; // reduced from 50
Grid() { Grid() {
gridColor = color(0, 150, 180, 50); gridColor = color(0, 150, 180, defaultAlpha);
accentColor = color(0, 255, 255, 100); accentColor = color(0, 255, 255, 80);
} }
void update() { void update() {
...@@ -44,25 +53,31 @@ class Grid { ...@@ -44,25 +53,31 @@ class Grid {
void drawStandardGrid() { void drawStandardGrid() {
strokeWeight(1); strokeWeight(1);
// Draw vertical lines // Draw vertical lines (reduced count)
float verticalSpacing = width / 20.0; float verticalSpacing = width / (float)verticalLines;
for (int i = 0; i <= 20; i++) { for (int i = 0; i <= verticalLines; i++) {
float x = i * verticalSpacing; float x = i * verticalSpacing;
float intensity = pulseIntensity * (1 - abs((x / width) - 0.5) * 2); float intensity = pulseIntensity * (1 - abs((x / width) - 0.5) * 2);
// Only draw lines with enough visibility
if (intensity > 0.05 || i % 2 == 0) {
stroke(lerpColor(gridColor, accentColor, intensity)); stroke(lerpColor(gridColor, accentColor, intensity));
line(x, 0, x, height); line(x, 0, x, height);
} }
}
// Draw horizontal lines // Draw horizontal lines (reduced count)
float horizontalSpacing = height / 15.0; float horizontalSpacing = height / (float)horizontalLines;
for (int i = 0; i <= 15; i++) { for (int i = 0; i <= horizontalLines; i++) {
float y = i * horizontalSpacing; float y = i * horizontalSpacing;
float intensity = pulseIntensity * (1 - abs((y / height) - 0.5) * 2); float intensity = pulseIntensity * (1 - abs((y / height) - 0.5) * 2);
// Only draw lines with enough visibility
if (intensity > 0.05 || i % 2 == 0) {
stroke(lerpColor(gridColor, accentColor, intensity)); stroke(lerpColor(gridColor, accentColor, intensity));
line(0, y, width, y); line(0, y, width, y);
} }
}
// Draw horizon line with stronger pulse // Draw horizon line with stronger pulse
stroke(lerpColor(gridColor, accentColor, pulseIntensity)); stroke(lerpColor(gridColor, accentColor, pulseIntensity));
...@@ -74,21 +89,20 @@ class Grid { ...@@ -74,21 +89,20 @@ class Grid {
pushMatrix(); pushMatrix();
translate(width / 2, height / 2); translate(width / 2, height / 2);
// Draw circular grid // Draw circular grid (reduced count)
noFill(); noFill();
for (int i = 1; i <= 10; i++) { for (int i = 1; i <= polarCircles; i++) {
float radius = i * (min(width, height) / 20.0); float radius = i * (min(width, height) / (polarCircles * 2.0));
float intensity = pulseIntensity * (1 - (i / 10.0) * 0.8); float intensity = pulseIntensity * (1 - (i / (float)polarCircles) * 0.8);
stroke(lerpColor(gridColor, accentColor, intensity)); stroke(lerpColor(gridColor, accentColor, intensity));
strokeWeight(1 + intensity * 2); strokeWeight(1 + intensity * 2);
ellipse(0, 0, radius * 2, radius * 2); ellipse(0, 0, radius * 2, radius * 2);
} }
// Draw radial lines // Draw radial lines (reduced count)
int numRadials = 16; for (int i = 0; i < polarRadials; i++) {
for (int i = 0; i < numRadials; i++) { float angle = i * TWO_PI / polarRadials;
float angle = i * TWO_PI / numRadials;
float intensity = pulseIntensity * 0.8; float intensity = pulseIntensity * 0.8;
stroke(lerpColor(gridColor, accentColor, intensity)); stroke(lerpColor(gridColor, accentColor, intensity));
...@@ -102,7 +116,7 @@ class Grid { ...@@ -102,7 +116,7 @@ class Grid {
} }
void drawHexGrid() { void drawHexGrid() {
float hexSize = 40; float hexSize = 60; // Increased from 40 for fewer hexagons
float horizontalSpacing = hexSize * 1.5; float horizontalSpacing = hexSize * 1.5;
float verticalSpacing = hexSize * sqrt(3); float verticalSpacing = hexSize * sqrt(3);
...@@ -110,8 +124,8 @@ class Grid { ...@@ -110,8 +124,8 @@ class Grid {
strokeWeight(1 + pulseIntensity * 2); strokeWeight(1 + pulseIntensity * 2);
noFill(); noFill();
for (int row = -1; row < height / verticalSpacing + 1; row++) { for (int row = -1; row < height / verticalSpacing + 1; row += 2) { // Skip rows
for (int col = -1; col < width / horizontalSpacing + 1; col++) { for (int col = -1; col < width / horizontalSpacing + 1; col += 2) { // Skip columns
float xCenter = col * horizontalSpacing + ((row % 2 == 0) ? 0 : horizontalSpacing / 2); float xCenter = col * horizontalSpacing + ((row % 2 == 0) ? 0 : horizontalSpacing / 2);
float yCenter = row * verticalSpacing; float yCenter = row * verticalSpacing;
...@@ -119,7 +133,7 @@ class Grid { ...@@ -119,7 +133,7 @@ class Grid {
float distFromCenter = dist(xCenter, yCenter, width/2, height/2) / (width/2); float distFromCenter = dist(xCenter, yCenter, width/2, height/2) / (width/2);
float intensity = pulseIntensity * (1 - distFromCenter * 0.7); float intensity = pulseIntensity * (1 - distFromCenter * 0.7);
if (intensity > 0.05) { if (intensity > 0.05 || (row % 4 == 0 && col % 4 == 0)) {
stroke(lerpColor(gridColor, accentColor, intensity)); stroke(lerpColor(gridColor, accentColor, intensity));
drawHexagon(xCenter, yCenter, hexSize); drawHexagon(xCenter, yCenter, hexSize);
} }
......
/** /**
* ParVaguesViz - Cyberpunk TidalCycles Visualizer * ParVaguesViz - Cyberpunk TidalCycles Visualizer (Improved)
* *
* A Processing-based visualizer that works with SuperDirt OSC messages * A Processing-based visualizer that works with SuperDirt OSC messages
* to create cyberpunk-style visualizations for TidalCycles performances. * to create cyberpunk-style visualizations for TidalCycles performances.
...@@ -37,9 +37,9 @@ MetadataSystem metadataSystem; ...@@ -37,9 +37,9 @@ MetadataSystem metadataSystem;
SampleAnalyzer sampleAnalyzer; SampleAnalyzer sampleAnalyzer;
// UI settings // UI settings
boolean debug = false; boolean debug = true; // Start with debug ON to troubleshoot
boolean showHelp = false; boolean showHelp = false;
boolean showMetadata = false; boolean showMetadata = true; // Show metadata by default for better visibility
PFont debugFont; PFont debugFont;
PFont titleFont; PFont titleFont;
PFont metadataFont; PFont metadataFont;
...@@ -51,7 +51,10 @@ float currentCycle = 0; ...@@ -51,7 +51,10 @@ float currentCycle = 0;
float elapsedTime = 0; float elapsedTime = 0;
float lastBeatTime = 0; float lastBeatTime = 0;
// Colors (cyberpunk palette) // Settings for improved visibility
float fadeAmount = 20; // Lower = more motion blur, higher = clearer screen
// Colors (enhanced cyberpunk palette) - Increased brightness
color[] orbitColors = { color[] orbitColors = {
#00FFFF, // Cyan (d1 - kick) #00FFFF, // Cyan (d1 - kick)
#FF00FF, // Magenta (d2 - snare) #FF00FF, // Magenta (d2 - snare)
...@@ -71,6 +74,10 @@ color[] orbitColors = { ...@@ -71,6 +74,10 @@ color[] orbitColors = {
#FFFFFF #FFFFFF
}; };
// OSC message receive counter and timestamp for debugging
int oscMessageCount = 0;
float lastOscTime = 0;
void setup() { void setup() {
// Apply Processing 4.x compatibility fixes // Apply Processing 4.x compatibility fixes
checkProcessingVersion(); checkProcessingVersion();
...@@ -80,9 +87,15 @@ void setup() { ...@@ -80,9 +87,15 @@ void setup() {
frameRate(60); frameRate(60);
smooth(8); smooth(8);
// Initialize OSC // Initialize OSC with enhanced error handling
try {
oscP5 = new OscP5(this, listenPort); oscP5 = new OscP5(this, listenPort);
superdirtAddress = new NetAddress("127.0.0.1", listenPort); superdirtAddress = new NetAddress("127.0.0.1", listenPort);
println("OSC initialized on port " + listenPort);
} catch (Exception e) {
println("ERROR initializing OSC: " + e.getMessage());
println("Try restarting SuperDirt and this visualizer");
}
// Initialize components // Initialize components
trackManager = new TrackManager(); trackManager = new TrackManager();
...@@ -105,13 +118,17 @@ void setup() { ...@@ -105,13 +118,17 @@ void setup() {
// Print startup message // Print startup message
println("ParVaguesViz started"); println("ParVaguesViz started");
println("Listening for SuperDirt OSC messages on port " + listenPort); println("Listening for SuperDirt OSC messages on port " + listenPort);
println("CONTROLS: D=Debug, H=Help, G=GridStyle, F=Fullscreen, R=Reset, M=Metadata");
// Generate a test pattern to verify visualization is working
generateTestPattern();
} }
void draw() { void draw() {
// Update timing // Update timing
elapsedTime = millis() / 1000.0; elapsedTime = millis() / 1000.0;
// Clear background with fade effect // Clear background with fade effect (lower alpha for more motion trails)
background.update(); background.update();
background.display(); background.display();
...@@ -144,10 +161,29 @@ void draw() { ...@@ -144,10 +161,29 @@ void draw() {
if (showHelp) { if (showHelp) {
drawHelp(); drawHelp();
} }
// Check for OSC timeout (no messages received in the last 5 seconds)
if (oscMessageCount > 0 && millis() - lastOscTime > 5000) {
// Draw OSC timeout warning
fill(255, 0, 0, 200);
textAlign(CENTER);
textSize(18);
text("WARNING: No OSC messages received in the last 5 seconds", width/2, 50);
text("Check that SuperDirt is running and sending to port " + listenPort, width/2, 75);
}
} }
// Handle OSC messages // Handle OSC messages
void oscEvent(OscMessage msg) { void oscEvent(OscMessage msg) {
// Update OSC stats
oscMessageCount++;
lastOscTime = millis();
// Detailed debug logging for OSC messages
if (debug) {
println("OSC message received: " + msg.addrPattern());
}
// Check for metadata messages // Check for metadata messages
if (msg.addrPattern().equals("/parvagues/metadata")) { if (msg.addrPattern().equals("/parvagues/metadata")) {
metadataSystem.processMetadataMessage(msg); metadataSystem.processMetadataMessage(msg);
...@@ -172,32 +208,46 @@ void handleDirtMessage(OscMessage msg) { ...@@ -172,32 +208,46 @@ void handleDirtMessage(OscMessage msg) {
float gain = 1.0; float gain = 1.0;
float pan = 0.5; float pan = 0.5;
// Debug output
if (debug) {
println("Processing dirt/play message: " + msg.typetag());
}
// Extract all parameters from the message // Extract all parameters from the message
try {
for (int i = 0; i < msg.typetag().length(); i++) { for (int i = 0; i < msg.typetag().length(); i++) {
String paramName = msg.get(i).stringValue(); String paramName = msg.get(i).stringValue();
if (paramName.equals("orbit")) { if (paramName.equals("orbit") && i+1 < msg.typetag().length()) {
orbit = msg.get(i+1).intValue(); orbit = msg.get(i+1).intValue();
} }
else if (paramName.equals("s")) { else if (paramName.equals("s") && i+1 < msg.typetag().length()) {
sound = msg.get(i+1).stringValue(); sound = msg.get(i+1).stringValue();
} }
else if (paramName.equals("cycle")) { else if (paramName.equals("cycle") && i+1 < msg.typetag().length()) {
cycle = msg.get(i+1).floatValue(); cycle = msg.get(i+1).floatValue();
} }
else if (paramName.equals("delta")) { else if (paramName.equals("delta") && i+1 < msg.typetag().length()) {
delta = msg.get(i+1).floatValue(); delta = msg.get(i+1).floatValue();
} }
else if (paramName.equals("gain")) { else if (paramName.equals("gain") && i+1 < msg.typetag().length()) {
gain = msg.get(i+1).floatValue(); gain = msg.get(i+1).floatValue();
} }
else if (paramName.equals("pan")) { else if (paramName.equals("pan") && i+1 < msg.typetag().length()) {
pan = msg.get(i+1).floatValue(); pan = msg.get(i+1).floatValue();
} }
} }
} catch (Exception e) {
println("Error processing OSC message: " + e.getMessage());
}
// Only process valid messages with an orbit // Only process valid messages with an orbit
if (orbit >= 0) { if (orbit >= 0) {
// Debug output
if (debug) {
println("Event: orbit=" + orbit + ", sound=" + sound + ", gain=" + gain + ", pan=" + pan);
}
// Update metadata system with sample information // Update metadata system with sample information
metadataSystem.updateFromSample(orbit, sound); metadataSystem.updateFromSample(orbit, sound);
...@@ -230,6 +280,10 @@ void updateCPS(OscMessage msg) { ...@@ -230,6 +280,10 @@ void updateCPS(OscMessage msg) {
// Update components with new timing // Update components with new timing
grid.setCPS(cps); grid.setCPS(cps);
background.setCPS(cps); background.setCPS(cps);
if (debug) {
println("CPS updated: " + cps + " (BPM: " + bpm + ")");
}
} }
} }
...@@ -237,25 +291,40 @@ void updateCPS(OscMessage msg) { ...@@ -237,25 +291,40 @@ void updateCPS(OscMessage msg) {
void keyPressed() { void keyPressed() {
if (key == 'd' || key == 'D') { if (key == 'd' || key == 'D') {
debug = !debug; debug = !debug;
println("Debug mode: " + (debug ? "ON" : "OFF"));
} else if (key == 'h' || key == 'H') { } else if (key == 'h' || key == 'H') {
showHelp = !showHelp; showHelp = !showHelp;
} else if (key == 'g' || key == 'G') { } else if (key == 'g' || key == 'G') {
grid.toggleStyle(); grid.toggleStyle();
println("Grid style changed");
} else if (key == 'f' || key == 'F') { } else if (key == 'f' || key == 'F') {
// Use the compatible fullscreen toggle // Use the compatible fullscreen toggle
handleFullscreenToggle(); handleFullscreenToggle();
println("Toggled fullscreen");
} else if (key == 'r' || key == 'R') { } else if (key == 'r' || key == 'R') {
// Reset all visuals // Reset all visuals
trackManager.reset(); trackManager.reset();
particleSystem.reset(); particleSystem.reset();
println("Visualization reset");
// Generate test pattern after reset
generateTestPattern();
} else if (key == 'm' || key == 'M') { } else if (key == 'm' || key == 'M') {
// Toggle metadata display // Toggle metadata display
showMetadata = !showMetadata; showMetadata = !showMetadata;
println("Metadata display: " + (showMetadata ? "ON" : "OFF"));
} else if (key == 't' || key == 'T') {
// Generate test pattern
generateTestPattern();
println("Test pattern generated");
} }
} }
// Debug information display // Debug information display
void drawDebugInfo() { void drawDebugInfo() {
fill(0, 180);
noStroke();
rect(5, 5, 300, 150, 5);
fill(255); fill(255);
textFont(debugFont); textFont(debugFont);
textAlign(LEFT); textAlign(LEFT);
...@@ -265,11 +334,12 @@ void drawDebugInfo() { ...@@ -265,11 +334,12 @@ void drawDebugInfo() {
text("Cycle: " + nf(currentCycle, 0, 2), 10, 50); text("Cycle: " + nf(currentCycle, 0, 2), 10, 50);
text("Active Tracks: " + trackManager.getActiveTrackCount(), 10, 65); text("Active Tracks: " + trackManager.getActiveTrackCount(), 10, 65);
text("Particles: " + particleSystem.getParticleCount(), 10, 80); text("Particles: " + particleSystem.getParticleCount(), 10, 80);
text("Tracked Samples: " + sampleAnalyzer.getSampleCount(), 10, 95); text("OSC Messages: " + oscMessageCount, 10, 95);
text("Last OSC: " + nf((millis() - lastOscTime)/1000, 0, 1) + "s ago", 10, 110);
// Add hint about metadata // Add hints
fill(200); fill(200);
text("Press 'M' to toggle metadata display", 10, 125); text("T = Test Pattern, M = Metadata, H = Help", 10, 140);
} }
// Draw metadata overlay // Draw metadata overlay
...@@ -295,6 +365,7 @@ void drawMetadataOverlay() { ...@@ -295,6 +365,7 @@ void drawMetadataOverlay() {
if (activeOrbits.size() == 0) { if (activeOrbits.size() == 0) {
text("No active tracks", width - 300, y); text("No active tracks", width - 300, y);
text("Try pressing T to generate a test pattern", width - 300, y + 25);
} else { } else {
for (Integer orbit : activeOrbits) { for (Integer orbit : activeOrbits) {
TrackMetadata metadata = metadataSystem.getMetadata(orbit); TrackMetadata metadata = metadataSystem.getMetadata(orbit);
...@@ -307,7 +378,8 @@ void drawMetadataOverlay() { ...@@ -307,7 +378,8 @@ void drawMetadataOverlay() {
// Draw most recent sample // Draw most recent sample
fill(200); fill(200);
if (metadata.recentSamples.size() > 0) { if (metadata.recentSamples.size() > 0) {
text("Sample: " + metadata.recentSamples.get(metadata.recentSamples.size() - 1), width - 300, y + 40); text("Sample: " + metadata.recentSamples.get(metadata.recentSamples.size() - 1),
width - 300, y + 40);
} }
// Add analyzed features if available // Add analyzed features if available
...@@ -334,15 +406,16 @@ void drawMetadataOverlay() { ...@@ -334,15 +406,16 @@ void drawMetadataOverlay() {
// Help information display // Help information display
void drawHelp() { void drawHelp() {
fill(0, 180); // Semi-transparent background
fill(0, 220);
noStroke(); noStroke();
rect(width/2 - 200, height/2 - 150, 400, 300); rect(width/2 - 200, height/2 - 170, 400, 340, 10);
fill(255); fill(255);
textFont(titleFont); textFont(titleFont);
textAlign(CENTER); textAlign(CENTER);
text("ParVaguesViz Controls", width/2, height/2 - 120); text("ParVaguesViz Controls", width/2, height/2 - 140);
textFont(debugFont); textFont(debugFont);
textAlign(LEFT); textAlign(LEFT);
...@@ -354,22 +427,63 @@ void drawHelp() { ...@@ -354,22 +427,63 @@ void drawHelp() {
"F - Toggle fullscreen", "F - Toggle fullscreen",
"R - Reset visuals", "R - Reset visuals",
"M - Toggle metadata display", "M - Toggle metadata display",
"T - Generate test pattern",
"", "",
"Automatically visualizes tracks d1-d16", "Automatically visualizes tracks d1-d16",
"Special visualization for d8 breakbeats", "Special visualization for d8 breakbeats",
"No TidalCycles configuration needed" "No TidalCycles configuration needed",
"",
"If no events are visible, check that:",
"1. SuperDirt is running on port 57120",
"2. Your TidalCycles pattern is active",
"3. Press T to generate a test pattern"
}; };
for (int i = 0; i < helpText.length; i++) { for (int i = 0; i < helpText.length; i++) {
text(helpText[i], width/2 - 180, height/2 - 80 + i * 20); text(helpText[i], width/2 - 180, height/2 - 100 + i * 20);
} }
} }
// Check if currently fullscreen // Generate a test pattern to verify visualization is working
boolean isFullScreen() { void generateTestPattern() {
if (isProcessing4) { // Create events for different tracks to check visualization
return width == displayWidth && height == displayHeight; for (int orbit = 0; orbit < 12; orbit++) {
} else { String sound = "";
return width == displayWidth && height == displayHeight; float gain = 0.8;
float pan = 0.5;
float delta = 0.25;
// Create appropriate sample names for each orbit
switch(orbit) {
case 0:
sound = "kick";
break;
case 1:
sound = "snare";
break;
case 2:
sound = "hihat";
break;
case 3:
sound = "bass";
break;
case 7:
sound = "jungle_breaks";
break;
default:
sound = "sample" + orbit;
} }
// Create test event
trackManager.addEvent(orbit, sound, gain, pan, delta);
metadataSystem.updateFromSample(orbit, sound);
// Add test metadata
TrackMetadata metadata = metadataSystem.getMetadata(orbit);
metadata.name = "Test d" + (orbit + 1);
}
// Trigger effects
grid.trigger(0.5);
glitchEffect.trigger(0.2);
} }
/** /**
* TrackManager class * TrackManager class - Improved version
* *
* Handles the management and visualization of TidalCycles tracks (d1-d16) * Handles the management and visualization of TidalCycles tracks (d1-d16)
* Each track has its own visual representation and effects * Enhanced visibility for events and track visualization
*/ */
class TrackManager { class TrackManager {
ArrayList<Track> tracks; ArrayList<Track> tracks;
...@@ -36,15 +36,15 @@ class TrackManager { ...@@ -36,15 +36,15 @@ class TrackManager {
} }
void display() { void display() {
// Display active events first (behind tracks)
for (SoundEvent event : activeEvents) {
event.display();
}
// Display all tracks // Display all tracks
for (Track track : tracks) { for (Track track : tracks) {
track.display(); track.display();
} }
// Display all active events
for (SoundEvent event : activeEvents) {
event.display();
}
} }
void addEvent(int orbit, String sound, float gain, float pan, float delta) { void addEvent(int orbit, String sound, float gain, float pan, float delta) {
...@@ -57,30 +57,41 @@ class TrackManager { ...@@ -57,30 +57,41 @@ class TrackManager {
// Create new event with appropriate visualization style based on orbit and sound // Create new event with appropriate visualization style based on orbit and sound
SoundEvent event = createEvent(orbit, sound, gain, pan, delta); SoundEvent event = createEvent(orbit, sound, gain, pan, delta);
activeEvents.add(event); activeEvents.add(event);
// Debug output to help identify events
if (debug) {
println("Added event: orbit=" + orbit + ", sound=" + sound + ", gain=" + gain);
}
} }
SoundEvent createEvent(int orbit, String sound, float gain, float pan, float delta) { SoundEvent createEvent(int orbit, String sound, float gain, float pan, float delta) {
// Different visualization based on orbit (track number) // Different visualization based on orbit (track number)
// ENHANCED: Increased default size and visibility for all event types
if (sound.contains("break") || sound.contains("jungle")) {
return new BreakbeatEvent(orbit, sound, gain, pan, delta);
}
switch(orbit) { switch(orbit) {
case 0: // d1 - typically kick case 0: // d1 - typically kick
return new KickEvent(orbit, sound, gain, pan, delta); return new KickEvent(orbit, sound, gain * 1.5, pan, delta);
case 1: // d2 - typically snare case 1: // d2 - typically snare
return new SnareEvent(orbit, sound, gain, pan, delta); return new SnareEvent(orbit, sound, gain * 1.5, pan, delta);
case 2: // d3 - typically hats or percussion case 2: // d3 - typically hats or percussion
return new HihatEvent(orbit, sound, gain, pan, delta); return new HihatEvent(orbit, sound, gain * 1.3, pan, delta);
case 3: // d4 - typically bass case 3: // d4 - typically bass
return new BassEvent(orbit, sound, gain, pan, delta); return new BassEvent(orbit, sound, gain * 1.5, pan, delta);
case 7: // d8 - typically breaks
return new BreakbeatEvent(orbit, sound, gain * 1.2, pan, delta);
default: // Other instruments default: // Other instruments
if (sound.contains("suns") || sound.contains("key")) { if (sound.contains("suns") || sound.contains("key")) {
return new MelodicEvent(orbit, sound, gain, pan, delta); return new MelodicEvent(orbit, sound, gain * 1.4, pan, delta);
} else if (sound.contains("break") || sound.contains("jungle")) {
return new BreakEvent(orbit, sound, gain, pan, delta);
} else if (sound.contains("voice") || sound.contains("voc")) { } else if (sound.contains("voice") || sound.contains("voc")) {
return new VoiceEvent(orbit, sound, gain, pan, delta); return new VoiceEvent(orbit, sound, gain * 1.3, pan, delta);
} else if (sound.contains("riser") || sound.contains("fx")) { } else if (sound.contains("riser") || sound.contains("fx")) {
return new FXEvent(orbit, sound, gain, pan, delta); return new FXEvent(orbit, sound, gain * 1.5, pan, delta);
} else { } else {
return new SoundEvent(orbit, sound, gain, pan, delta); return new SoundEvent(orbit, sound, gain * 1.4, pan, delta);
} }
} }
} }
...@@ -119,10 +130,10 @@ class TrackManager { ...@@ -119,10 +130,10 @@ class TrackManager {
} }
/** /**
* Track class * Track class - Improved version
* *
* Represents a single TidalCycles track (d1-d16) * Represents a single TidalCycles track (d1-d16)
* Maintains state and provides visual representation * Enhanced visibility and layout
*/ */
class Track { class Track {
int orbit; int orbit;
...@@ -148,41 +159,42 @@ class Track { ...@@ -148,41 +159,42 @@ class Track {
this.historyGain = new ArrayList<Float>(); this.historyGain = new ArrayList<Float>();
// Visual initialization // Visual initialization - INCREASED heights for better visibility
this.baseHeight = height / 32.0; this.baseHeight = height / 24.0; // Changed from 32.0
this.targetHeight = baseHeight; this.targetHeight = baseHeight;
this.currentHeight = baseHeight; this.currentHeight = baseHeight;
} }
void update() { void update() {
// Decay activity over time // Slower decay for better visibility
activity *= 0.95; activity *= 0.97; // Changed from 0.95
// Update height with smooth animation // Update height with smooth animation
currentHeight = lerp(currentHeight, targetHeight, 0.2); currentHeight = lerp(currentHeight, targetHeight, 0.2);
// Reset target height if activity is low // Reset target height if activity is low
if (activity < 0.1) { if (activity < 0.05) { // Changed from 0.1
targetHeight = baseHeight; targetHeight = baseHeight;
active = false; active = false;
} }
} }
void display() { void display() {
if (activity < 0.05) return; // Don't display inactive tracks if (activity < 0.02) return; // Lower threshold for visibility - Changed from 0.05
float yPos = map(orbit, 0, 15, height * 0.1, height * 0.9); // Better vertical distribution - Changed from 0.1 and 0.9 to 0.05 and 0.95
float trackWidth = width * 0.8; float yPos = map(orbit, 0, 15, height * 0.05, height * 0.95);
float xOffset = width * 0.1; float trackWidth = width * 0.9; // Wider tracks - Changed from 0.8
float xOffset = width * 0.05; // Changed from 0.1
// Draw track background with trail effect // Draw track background with trail effect
noStroke(); noStroke();
fill(red(trackColor), green(trackColor), blue(trackColor), activity * 150); fill(red(trackColor), green(trackColor), blue(trackColor), activity * 180); // Increased from 150
rect(xOffset, yPos - currentHeight/2, trackWidth, currentHeight, 5); rect(xOffset, yPos - currentHeight/2, trackWidth, currentHeight, 5);
// Draw glowing edge // Draw glowing edge
stroke(trackColor, activity * 255); stroke(trackColor, activity * 255);
strokeWeight(2); strokeWeight(2 + activity); // Increased from 2
noFill(); noFill();
rect(xOffset, yPos - currentHeight/2, trackWidth, currentHeight, 5); rect(xOffset, yPos - currentHeight/2, trackWidth, currentHeight, 5);
...@@ -192,16 +204,24 @@ class Track { ...@@ -192,16 +204,24 @@ class Track {
// Draw activity meter // Draw activity meter
float meterWidth = map(activity, 0, 1, 0, trackWidth); float meterWidth = map(activity, 0, 1, 0, trackWidth);
noStroke(); noStroke();
fill(trackColor, activity * 200); fill(trackColor, activity * 220); // Increased from 200
rect(xOffset, yPos - currentHeight/3, meterWidth, currentHeight/3, 5); rect(xOffset, yPos - currentHeight/3, meterWidth, currentHeight/3, 5);
// Add label for active tracks
if (activity > 0.5) {
fill(255, activity * 255);
textAlign(LEFT, CENTER);
textSize(12);
text("d" + (orbit + 1), xOffset + 10, yPos);
}
} }
void drawGlow(float x, float y, float w, float h) { void drawGlow(float x, float y, float w, float h) {
// Create glow effect using multiple transparent strokes // Enhanced glow effect
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
float alpha = map(i, 0, 4, activity * 100, 0); float alpha = map(i, 0, 4, activity * 150, 0); // Increased from 100
stroke(red(trackColor), green(trackColor), blue(trackColor), alpha); stroke(red(trackColor), green(trackColor), blue(trackColor), alpha);
strokeWeight(i * 2 + 2); strokeWeight(i * 2 + 3); // Increased from i*2+2
noFill(); noFill();
rect(x, y - currentHeight/2, w, currentHeight, 5); rect(x, y - currentHeight/2, w, currentHeight, 5);
} }
...@@ -220,8 +240,8 @@ class Track { ...@@ -220,8 +240,8 @@ class Track {
historyGain.remove(0); historyGain.remove(0);
} }
// Update visual properties // Update visual properties - MORE DRAMATIC HEIGHT CHANGE
targetHeight = baseHeight + (gain * baseHeight * 2); targetHeight = baseHeight + (gain * baseHeight * 4); // Changed from 2
} }
boolean isActive() { boolean isActive() {
...@@ -238,7 +258,7 @@ class Track { ...@@ -238,7 +258,7 @@ class Track {
} }
/** /**
* SoundEvent class * SoundEvent class - Improved version
* *
* Base class for visualizing individual sound events * Base class for visualizing individual sound events
*/ */
...@@ -264,16 +284,16 @@ class SoundEvent { ...@@ -264,16 +284,16 @@ class SoundEvent {
this.pan = pan; this.pan = pan;
this.delta = delta; this.delta = delta;
this.birthTime = millis(); this.birthTime = millis();
this.lifespan = 500 + (gain * 500); // Duration based on gain this.lifespan = 800 + (gain * 700); // Longer duration - Changed from 500
// Initialize visuals // Initialize visuals
this.eventColor = orbitColors[orbit]; this.eventColor = orbitColors[orbit];
this.size = 20 + (gain * 60); this.size = 30 + (gain * 80); // Larger size - Changed from 20+(gain*60)
this.alpha = 255; this.alpha = 255;
// Position based on pan value // Better spread across the screen - Changed from width*0.3/0.7 to 0.2/0.8
float xPos = map(pan, 0, 1, width * 0.3, width * 0.7); float xPos = map(pan, 0, 1, width * 0.2, width * 0.8);
float yPos = map(orbit, 0, 15, height * 0.2, height * 0.8); float yPos = map(orbit, 0, 15, height * 0.1, height * 0.9);
this.position = new PVector(xPos, yPos); this.position = new PVector(xPos, yPos);
} }
...@@ -281,11 +301,11 @@ class SoundEvent { ...@@ -281,11 +301,11 @@ class SoundEvent {
// Calculate age // Calculate age
float age = millis() - birthTime; float age = millis() - birthTime;
// Fade out as the event ages // Slower fade out
alpha = map(age, 0, lifespan, 255, 0); alpha = map(age, 0, lifespan, 255, 0);
// Grow size slightly over time // Grow size slightly over time
size = 20 + (gain * 60) * (1 + (age / lifespan) * 0.5); size = 30 + (gain * 80) * (1 + (age / lifespan) * 0.6); // Changed from 20+(gain*60)*(1+(age/lifespan)*0.5)
} }
void display() { void display() {
...@@ -302,10 +322,10 @@ class SoundEvent { ...@@ -302,10 +322,10 @@ class SoundEvent {
void drawGlow(float x, float y, float s) { void drawGlow(float x, float y, float s) {
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
float glowAlpha = map(i, 0, 4, alpha * 0.5, 0); float glowAlpha = map(i, 0, 4, alpha * 0.7, 0); // Increased from 0.5
fill(red(eventColor), green(eventColor), blue(eventColor), glowAlpha); fill(red(eventColor), green(eventColor), blue(eventColor), glowAlpha);
noStroke(); noStroke();
ellipse(x, y, s + (i * 10), s + (i * 10)); ellipse(x, y, s + (i * 12), s + (i * 12)); // Increased from i*10
} }
} }
......
# ParVagues Visualization Metadata
# Format: orbit:name:type:prop1=value1,prop2=value2,...
0:Test d1:kick
1:Test d2:snare
2:Drums:hihat
#!/bin/bash #!/bin/bash
# Direct launcher script for ParVaguesViz # Simple launcher script for ParVaguesViz
# This uses what we've learned works on your system
# Get the full path to the sketch directory
SKETCH_DIR=$(cd "$(dirname "$0")" && pwd)
# Colors for terminal output # Colors for terminal output
GREEN='\033[0;32m' GREEN='\033[0;32m'
BLUE='\033[0;34m' BLUE='\033[0;34m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
# Print banner # Print banner
...@@ -22,20 +19,61 @@ echo "██║ ██║ ██║██║ ██║ ╚████╔ ...@@ -22,20 +19,61 @@ echo "██║ ██║ ██║██║ ██║ ╚████╔
echo "╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝" echo "╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝"
echo -e " TIDALCYCLES VISUALIZER\n${NC}" echo -e " TIDALCYCLES VISUALIZER\n${NC}"
# Set Java options to fix module restrictions # Get the full path to the sketch directory
export _JAVA_OPTIONS="--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED --add-opens=java.desktop/java.awt=ALL-UNNAMED -Djava.awt.headless=false -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true" SKETCH_DIR=$(cd "$(dirname "$0")" && pwd)
# Check if Processing is installed
if ! command -v processing &> /dev/null && ! command -v processing-java &> /dev/null; then
echo -e "${RED}Error: Processing not found!${NC}"
echo "Please make sure Processing is installed and in your PATH."
echo "You can download it from: https://processing.org/download"
exit 1
fi
echo -e "${YELLOW}Starting ParVaguesViz...${NC}" # Check if SuperDirt might be running
echo -e "${BLUE}Controls:${NC}" if ! command -v lsof &> /dev/null || ! lsof -i :57120 &> /dev/null; then
echo -e "${YELLOW}Warning: No process seems to be listening on port 57120.${NC}"
echo "Make sure SuperDirt is running in SuperCollider before starting TidalCycles."
echo -e "Typical SuperCollider startup: ${GREEN}SuperDirt.start${NC}"
echo ""
fi
# Print troubleshooting tips
echo -e "${YELLOW}Troubleshooting tips:${NC}"
echo "1. If no visualization appears, press 'T' to generate a test pattern"
echo "2. Debug mode is ON by default, press 'D' to toggle it"
echo "3. Make sure SuperDirt is running on port 57120"
echo -e "\n${BLUE}Controls:${NC}"
echo " D - Toggle debug info" echo " D - Toggle debug info"
echo " H - Toggle help screen" echo " H - Toggle help screen"
echo " G - Change grid style" echo " G - Change grid style"
echo " F - Toggle fullscreen" echo " F - Toggle fullscreen"
echo " R - Reset visualization" echo " R - Reset visualization"
echo " M - Toggle metadata display" echo " M - Toggle metadata display"
echo echo " T - Generate test pattern"
echo ""
# Set Java options to fix module restrictions (important for Processing 4.x)
export _JAVA_OPTIONS="--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED --add-opens=java.desktop/java.awt=ALL-UNNAMED -Djava.awt.headless=false -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true"
# Launch Processing with the full path to the main sketch # Launch Processing sketch
echo -e "${GREEN}Launching visualizer...${NC}" echo -e "${GREEN}Launching visualizer...${NC}"
cd "$SKETCH_DIR" echo "Sketch directory: $SKETCH_DIR"
processing "$SKETCH_DIR/ParVaguesViz.pde"
# Try different launch methods
if command -v processing &> /dev/null; then
# Preferred method: Use the Processing GUI
cd "$SKETCH_DIR"
processing "$SKETCH_DIR/ParVaguesViz.pde"
elif command -v processing-java &> /dev/null; then
# Alternative: Use processing-java command line
processing-java --sketch="$SKETCH_DIR" --run
else
# Last resort: Try direct Java execution
echo -e "${RED}Could not find Processing launcher. Trying direct execution...${NC}"
cd "$SKETCH_DIR"
java -jar "$SKETCH_DIR/ParVaguesViz.jar"
fi
echo -e "${GREEN}Visualizer closed.${NC}"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment