- Published on
Beat DJ: Exploring the New Visual System
- Authors
- Name
- Nes Croft
- @nescroft
Beat DJ's New Visual System
The next version of Beat DJ is on the horizon, and it’s bringing an exciting update to its visual capabilities. Here's a sneak peek at the progress.
Video demonstration
Here's what is happening in the video:
The new system revolves around frequency-based visuals that dynamically respond to your audio.
Frequency Bands in Action: The system uses 9 frequency bands that are triggered in real-time by audio playback. As the sound plays, these bands create visual rectangles that move to the right, giving a sense of flow and energy.
Dynamic Sizing: The loudness of the audio determines the size of the rectangles, ensuring that the visuals are as expressive as the music.
Randomized Colors: Colors for the visuals are chosen randomly from the selected theme, making each playback unique and visually stunning.
Feedback System: The system includes a feedback loop that takes the polygons from the previous frame, transforms them to drift toward the center, and gradually makes them more transparent. This creates an ethereal effect that blends past and present visuals seamlessly.
Lightweight Design: This visual system is designed to be lightweight and efficient, ensuring smooth performance even during intense music sessions.
Custom Visual Scripts in C#
What’s particularly exciting is the ability for Beat DJ users to write their own custom visual scripts in C#. Whether you’re an experienced developer or a creative enthusiast, you’ll have the tools to craft visuals tailored to your style. Beat DJ will also come with a growing collection of pre-built examples to inspire and guide you.
Here’s the script that is being used in the video:
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;
using Random = UnityEngine.Random;
public class AdvancedExample : IVisualizer
{
public async Task<List<Polygon>> Generate(int frame, float[] spectrumData, List<Color> colors, int[] activeFreqBandTriggers, List<Polygon> lastPolygons)
{
int sequenceLength = 128;
frame = frame % sequenceLength;
List<Polygon> polygons = new List<Polygon>();
// Overall loudness computation
float loudness = ComputeLoudness(spectrumData);
// Shrink the last polygons
ShrinkLastPolygons(polygons, lastPolygons);
// Add new polygons, Frequency-based visual dynamics with sweeping motion
AddFrequencyBandPolygons(polygons, activeFreqBandTriggers, colors, frame, loudness, sequenceLength);
await Task.Yield(); // Ensure non-blocking behavior
return polygons;
}
private float ComputeLoudness(float[] spectrumData)
{
float sum = 0f;
foreach (float value in spectrumData)
{
sum += value;
}
return Mathf.Clamp01(sum); // Normalized loudness
}
private void AddFrequencyBandPolygons(List<Polygon> polygons, int[] activeFreqBandTriggers, List<Color> colors, int frame, float loudness, int sequenceLength)
{
for (int i = 0; i < activeFreqBandTriggers.Length; i++)
{
int triggers = activeFreqBandTriggers[i];
float baseXPosition = (float)(frame % sequenceLength) / sequenceLength; // Sweeping base position
float bandWidth = 1f / activeFreqBandTriggers.Length; // Divide horizontal space for frequency bands
float sectionHeight = 1f / triggers; // Divide vertical space for the number of triggers
for (int j = 0; j < triggers; j++)
{
float sweepOffset = (baseXPosition + (float)i * bandWidth) % 1f; // Continuous horizontal movement
// Center the polygon in its vertical section
float polygonHeight = sectionHeight * loudness; // Scaled height based on loudness
float centerY = j * sectionHeight + sectionHeight / 2f; // Center of the current section
float startY = centerY - polygonHeight / 2f; // Adjust startY to center the polygon
float endY = centerY + polygonHeight / 2f; // Adjust endY to center the polygon
Polygon freqPolygon = new Polygon
{
Points = new List<Vector2>
{
new Vector2(sweepOffset, startY),
new Vector2(sweepOffset, endY),
new Vector2(sweepOffset + bandWidth * 0.8f, endY),
new Vector2(sweepOffset + bandWidth * 0.8f, startY)
},
PointColors = GenerateGradientColors(colors, Random.Range(0, colors.Count))
};
polygons.Add(freqPolygon);
}
}
}
private List<Color> GenerateGradientColors(List<Color> colors, int index)
{
Color startColor = colors[index % colors.Count];
Color endColor = colors[(index + 1) % colors.Count];
return new List<Color>
{
startColor,
Color.Lerp(startColor, endColor, 0.5f),
endColor,
Color.Lerp(endColor, startColor, 0.5f)
};
}
public void ShrinkLastPolygons(List<Polygon> polygons, List<Polygon> lastPolygons)
{
if (lastPolygons == null)
{
return;
}
foreach (Polygon polygon in lastPolygons)
{
for (int i = 0; i < polygon.Points.Count; i++)
{
Vector2 point = polygon.Points[i];
Vector2 center = new Vector2(0.5f, 0.5f);
Vector2 direction = point - center;
polygon.Points[i] = center + direction * 0.9f;
polygon.PointColors[i] = polygon.PointColors[i] * 0.9f;
}
if (polygon.PointColors[0].r > 0.05f)
{
polygons.Add(polygon);
}
}
}
}
Endless Possibilities
With the ability to switch between visualizers dynamically using scheduling functions, users will have limitless opportunities to create unique combinations and engaging live performances. This new visual system represents a significant leap forward, merging technology and creativity in a seamless, expressive way.
Stay tuned for the release and prepare to explore the vibrant world of Beat DJ’s visuals!