audioVisualizerShapes function

AudioVisualizerShapes audioVisualizerShapes({
  1. required AudioVisualizerStyle style,
  2. required double width,
  3. required double height,
  4. required List<double> levels,
  5. double? barFill,
})

The shapes style draws for levels, one level per band from 0 to 1, in a box of width by height whose top-left corner is the origin.

barFill is how much of its share a bar fills; see LayerAudioVisualizer.barFill. null takes the style's own, as does a value outside above 0 to 1, which the native renderers never receive.

The Android, iOS and macOS renderers compute the same shapes from the same numbers; a change here has to be made there too.

Implementation

AudioVisualizerShapes audioVisualizerShapes({
  required AudioVisualizerStyle style,
  required double width,
  required double height,
  required List<double> levels,
  double? barFill,
}) {
  final count = levels.length;
  if (count == 0 || width <= 0 || height <= 0) {
    return const AudioVisualizerShapes();
  }
  double level(int band) => audioVisualizerUnitLevel(levels[band]);
  final fill = barFill != null && barFill > 0 && barFill <= 1 ? barFill : null;

  switch (style) {
    case AudioVisualizerStyle.bars:
    case AudioVisualizerStyle.mirroredBars:
      final slot = width / count;
      final barWidth = slot * (fill ?? audioVisualizerBarFill);
      // A silent bar is a dot as wide as the bar.
      final minHeight = math.min(barWidth, height);
      return AudioVisualizerShapes(
        bars: [
          for (var band = 0; band < count; band++)
            _bar(
              left: band * slot + (slot - barWidth) / 2,
              width: barWidth,
              height: math.min(
                height,
                math.max(minHeight, level(band) * height),
              ),
              boxHeight: height,
              mirrored: style == AudioVisualizerStyle.mirroredBars,
            ),
        ],
      );
    case AudioVisualizerStyle.circle:
      final radius = math.min(width, height) / 2;
      final bars = count * 2;
      final ring = radius * audioVisualizerCircleInnerRadius;
      final barWidth = math.min(
        2 * math.pi * ring / bars * (fill ?? audioVisualizerCircleBarFill),
        (radius - ring) / 2,
      );
      final maxLength = math.max(0.0, radius - ring - barWidth);
      return AudioVisualizerShapes(
        bars: [
          for (var bar = 0; bar < bars; bar++)
            AudioVisualizerBar(
              left: -barWidth / 2,
              // The bands run from the top down both sides of the ring.
              top:
                  -(ring +
                      barWidth +
                      level(bar < count ? bar : bars - 1 - bar) * maxLength),
              right: barWidth / 2,
              bottom: -ring,
              radius: barWidth / 2,
              pivotX: width / 2,
              pivotY: height / 2,
              rotation: 2 * math.pi * (bar + 0.5) / bars,
            ),
        ],
      );
    case AudioVisualizerStyle.wave:
      return AudioVisualizerShapes(wave: _waveOutline(width, height, levels));
  }
}