Soniare
We would like to use cookies to help us advertise
Published on

Beat DJ: Exploring the New Visual System

Authors
reactive-gradient-rectangles-with-feedback-in-beat-dj-banner

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!

Download Beat DJ Here