-
Notifications
You must be signed in to change notification settings - Fork 32
/
Spectrum.cs
99 lines (86 loc) · 3.88 KB
/
Spectrum.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using OpenTK;
using StorybrewCommon.Animations;
using StorybrewCommon.Scripting;
using StorybrewCommon.Storyboarding;
using System;
using System.Linq;
namespace StorybrewScripts
{
/// <summary>
/// An example of a spectrum effect.
/// </summary>
public class Spectrum : StoryboardObjectGenerator
{
[Group("Timing")]
[Configurable] public int StartTime = 0;
[Configurable] public int EndTime = 10000;
[Configurable] public int BeatDivisor = 16;
[Group("Sprite")]
[Configurable] public string SpritePath = "sb/bar.png";
[Configurable] public OsbOrigin SpriteOrigin = OsbOrigin.BottomLeft;
[Configurable] public Vector2 SpriteScale = new Vector2(1, 100);
[Group("Bars")]
[Configurable] public Vector2 Position = new Vector2(0, 400);
[Configurable] public float Width = 640;
[Configurable] public int BarCount = 96;
[Configurable] public int LogScale = 600;
[Configurable] public OsbEasing FftEasing = OsbEasing.InExpo;
[Configurable] public float MinimalHeight = 0.05f;
[Group("Optimization")]
[Configurable] public double Tolerance = 0.2;
[Configurable] public int CommandDecimals = 1;
[Configurable] public int FrequencyCutOff = 16000;
public override void Generate()
{
if (StartTime == EndTime && Beatmap.HitObjects.FirstOrDefault() != null)
{
StartTime = (int)Beatmap.HitObjects.First().StartTime;
EndTime = (int)Beatmap.HitObjects.Last().EndTime;
}
EndTime = Math.Min(EndTime, (int)AudioDuration);
StartTime = Math.Min(StartTime, EndTime);
var bitmap = GetMapsetBitmap(SpritePath);
var heightKeyframes = new KeyframedValue<float>[BarCount];
for (var i = 0; i < BarCount; i++)
heightKeyframes[i] = new KeyframedValue<float>(null);
var fftTimeStep = Beatmap.GetTimingPointAt(StartTime).BeatDuration / BeatDivisor;
var fftOffset = fftTimeStep * 0.2;
for (var time = (double)StartTime; time < EndTime; time += fftTimeStep)
{
var fft = GetFft(time + fftOffset, BarCount, null, FftEasing, FrequencyCutOff);
for (var i = 0; i < BarCount; i++)
{
var height = (float)Math.Log10(1 + fft[i] * LogScale) * SpriteScale.Y / bitmap.Height;
if (height < MinimalHeight) height = MinimalHeight;
heightKeyframes[i].Add(time, height);
}
}
var layer = GetLayer("Spectrum");
var barWidth = Width / BarCount;
for (var i = 0; i < BarCount; i++)
{
var keyframes = heightKeyframes[i];
keyframes.Simplify1dKeyframes(Tolerance, h => h);
var bar = layer.CreateSprite(SpritePath, SpriteOrigin, new Vector2(Position.X + i * barWidth, Position.Y));
bar.CommandSplitThreshold = 300;
bar.ColorHsb(StartTime, (i * 360.0 / BarCount) + Random(-10.0, 10.0), 0.6 + Random(0.4), 1);
bar.Additive(StartTime, EndTime);
var scaleX = SpriteScale.X * barWidth / bitmap.Width;
scaleX = (float)Math.Floor(scaleX * 10) / 10.0f;
var hasScale = false;
keyframes.ForEachPair(
(start, end) =>
{
hasScale = true;
bar.ScaleVec(start.Time, end.Time,
scaleX, start.Value,
scaleX, end.Value);
},
MinimalHeight,
s => (float)Math.Round(s, CommandDecimals)
);
if (!hasScale) bar.ScaleVec(StartTime, scaleX, MinimalHeight);
}
}
}
}