Skip to content

Commit 1be52b7

Browse files
committed
Adding generic FindComponentByName to configurer API, got CaptureCompare working on 2 simultaneous sources
1 parent 0edc721 commit 1be52b7

File tree

6 files changed

+125
-30
lines changed

6 files changed

+125
-30
lines changed

ColorChord.NET-API/ColorChordAPI.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ public static class ColorChordAPI
66
{
77
/// <summary>Use this version as return value for <see cref="Extensions.IExtension.APIVersion"/> in your extension.</summary>
88
/// <remarks>This allows ColorChord.NET to know if the installed version of your extension is compatible.</remarks>
9-
public const uint APIVersion = 22;
9+
public const uint APIVersion = 23;
1010

1111
public static IConfigurer Configurer;
1212
}

ColorChord.NET-API/Config/IConfigurer.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,10 @@ public interface IConfigurer
5353
/// <param name="config">The config section of a component which needs to find a controller, the <see cref="ConfigNames.CONTROLLER_NAME"/> key will be used to find it by name.</param>
5454
/// <returns>The controller instance if it was found, null otherwise.</returns>
5555
public Controller? FindController(Dictionary<string, object> config);
56+
57+
/// <summary>Finds a specific component by its name. More specific methods of this interface should be preferred in most cases.</summary>
58+
/// <param name="componentType">The type of component to find</param>
59+
/// <param name="componentName">The "Name" parameter of that component to search for, ignored in the case of <see cref="Component.Source"/> or <see cref="Component.NoteFinder"/> if there is only 1 loaded of that type.</param>
60+
/// <returns>THe component if found, null otherwise</returns>
61+
public object? FindComponentByName(Component componentType, string componentName);
5662
}

ColorChord.NET/Config/Configurer.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public sealed class ConfigurerInst : IConfigurer
2525
public IVisualizer? FindVisualizer(IOutput target, Dictionary<string, object> config, Type acceptableFormat) => Configurer.FindVisualizer(target, config, acceptableFormat);
2626
public IOutput? FindOutput(Dictionary<string, object> config) => Configurer.FindOutput(config);
2727
public Controller? FindController(Dictionary<string, object> config) => Configurer.FindController(config);
28+
public object? FindComponentByName(Component componentType, string componentName) => Configurer.FindComponentByName(componentType, componentName);
2829
}
2930

3031
public static class Configurer
@@ -262,6 +263,44 @@ public static bool Configure(object targetObj, Dictionary<string, object> config
262263
return Controller;
263264
}
264265

266+
/// <summary>Finds a specific component by its name. More specific methods of this interface should be preferred in most cases.</summary>
267+
/// <param name="componentType">The type of component to find</param>
268+
/// <param name="componentName">The "Name" parameter of that component to search for, ignored in the case of <see cref="Component.Source"/> or <see cref="Component.NoteFinder"/> if there is only 1 loaded of that type.</param>
269+
/// <returns>THe component if found, null otherwise</returns>
270+
public static object? FindComponentByName(Component componentType, string componentName)
271+
{
272+
if (componentType == Component.Source)
273+
{
274+
IAudioSource? Source;
275+
if (ColorChord.SourceInsts.Count == 1) { Source = ColorChord.SourceInsts.First().Value; }
276+
else { ColorChord.SourceInsts.TryGetValue(componentName, out Source); }
277+
return Source;
278+
}
279+
else if (componentType == Component.NoteFinder)
280+
{
281+
NoteFinderCommon? NoteFinder;
282+
if (ColorChord.NoteFinderInsts.Count == 1) { NoteFinder = ColorChord.NoteFinderInsts.First().Value; }
283+
else { ColorChord.NoteFinderInsts.TryGetValue(componentName, out NoteFinder); }
284+
return NoteFinder;
285+
}
286+
else if (componentType == Component.Visualizers)
287+
{
288+
ColorChord.VisualizerInsts.TryGetValue(componentName, out IVisualizer? Visualizer);
289+
return Visualizer;
290+
}
291+
else if (componentType == Component.Outputs)
292+
{
293+
ColorChord.OutputInsts.TryGetValue(componentName, out IOutput? Output);
294+
return Output;
295+
}
296+
else if (componentType == Component.Controllers)
297+
{
298+
ColorChord.ControllerInsts.TryGetValue(componentName, out Controller? Controller);
299+
return Controller;
300+
}
301+
return null;
302+
}
303+
265304
/// <summary>Checks the config to see if a reasonable value is provided, otherwise uses the default and outputs a warning.</summary>
266305
/// <param name="config">The configuration to read from.</param>
267306
/// <param name="fltAttr">The attribute on the item to configure.</param>

ColorChord.NET/Outputs/Display/CaptureCompare.cs

Lines changed: 75 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
using ColorChord.NET.API;
2+
using ColorChord.NET.API.Config;
23
using ColorChord.NET.API.Outputs.Display;
34
using ColorChord.NET.API.Visualizers;
45
using ColorChord.NET.API.Visualizers.Formats;
6+
using ColorChord.NET.Config;
57
using OpenTK.Graphics.OpenGL4;
68
using OpenTK.Mathematics;
79
using OpenTK.Windowing.Common;
810
using OpenTK.Windowing.GraphicsLibraryFramework;
911
using System;
12+
using System.Collections.Generic;
1013

1114
namespace ColorChord.NET.Outputs.Display;
1215

13-
public class CaptureCompare : IDisplayMode
16+
public class CaptureCompare : IDisplayMode, IConfigurableAttr
1417
{
1518
private readonly DisplayOpenGL HostWindow;
1619
private readonly IDiscrete1D DataSourceA, DataSourceB;
1720

18-
private const int TEX_HEIGHT = 128;
21+
[ConfigInt("HistoryLength", 16, 16384, 768)]
22+
private int TextureHeight = 768;
1923

2024
private Shader? Shader;
2125

@@ -44,11 +48,17 @@ public class CaptureCompare : IDisplayMode
4448
-1F, 1F, 0F, 0F
4549
};
4650

47-
public CaptureCompare(DisplayOpenGL parent, IVisualizer visualizer)
51+
public CaptureCompare(DisplayOpenGL parent, IVisualizer visualizer, Dictionary<string, object> config)
4852
{
4953
this.HostWindow = parent;
5054
this.DataSourceA = visualizer as IDiscrete1D ?? throw new Exception($"{nameof(CaptureCompare)} cannot use the provided visualizer, as it doesn't support {nameof(IDiscrete1D)} output mode.");
51-
this.DataSourceB = this.DataSourceA; // TODO: Actually read the second one
55+
56+
IDiscrete1D? DataSourceBTemp = null;
57+
if (config.TryGetValue("SecondaryVisualizer", out object? SecondVizNameObj) && SecondVizNameObj is string SecondVizName) { DataSourceBTemp = Configurer.FindComponentByName(Component.Visualizers, SecondVizName) as IDiscrete1D; }
58+
if (DataSourceBTemp == null) { Log.Warn($"{nameof(CaptureCompare)} could not find the secondary visualizer, and is instead using the primary one for both inputs. You may set it using \"SecondaryVisualizer\"."); }
59+
this.DataSourceB = DataSourceBTemp ?? this.DataSourceA;
60+
config.Remove("SecondaryVisualizer");
61+
Configurer.Configure(this, config);
5262
}
5363

5464
public void Load()
@@ -67,37 +77,37 @@ public void Load()
6777
this.TextureHandleCaptureB = GL.GenTexture();
6878
this.TextureWidthA = this.DataSourceA.GetCountDiscrete();
6979
this.TextureWidthB = this.DataSourceB.GetCountDiscrete();
70-
this.NewTextureDataA = new uint[this.TextureWidthA * TEX_HEIGHT];
71-
this.NewTextureDataB = new uint[this.TextureWidthB * TEX_HEIGHT];
80+
this.NewTextureDataA = new uint[this.TextureWidthA * TextureHeight];
81+
this.NewTextureDataB = new uint[this.TextureWidthB * TextureHeight];
7282

7383
// Activate texture
7484
GL.ActiveTexture(TextureUnit.Texture0);
7585
GL.BindTexture(TextureTarget.Texture2D, this.TextureHandleA);
76-
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, this.TextureWidthA, TEX_HEIGHT, 0, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataA);
86+
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, this.TextureWidthA, TextureHeight, 0, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataA);
7787
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
7888
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Nearest);
7989
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
8090
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
8191

8292
GL.ActiveTexture(TextureUnit.Texture1);
8393
GL.BindTexture(TextureTarget.Texture2D, this.TextureHandleB);
84-
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, this.TextureWidthB, TEX_HEIGHT, 0, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataB);
94+
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, this.TextureWidthB, TextureHeight, 0, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataB);
8595
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
8696
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Nearest);
8797
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
8898
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
8999

90100
GL.ActiveTexture(TextureUnit.Texture2);
91101
GL.BindTexture(TextureTarget.Texture2D, this.TextureHandleCaptureA);
92-
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, this.TextureWidthA, TEX_HEIGHT, 0, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataA);
102+
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, this.TextureWidthA, TextureHeight, 0, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataA);
93103
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
94104
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Nearest);
95105
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
96106
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
97107

98108
GL.ActiveTexture(TextureUnit.Texture3);
99109
GL.BindTexture(TextureTarget.Texture2D, this.TextureHandleCaptureB);
100-
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, this.TextureWidthB, TEX_HEIGHT, 0, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataB);
110+
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, this.TextureWidthB, TextureHeight, 0, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataB);
101111
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
102112
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Nearest);
103113
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
@@ -139,17 +149,28 @@ public void Load()
139149
public void Dispatch()
140150
{
141151
if (!this.SetupDone) { return; }
142-
bool IsFromA = true;
143-
IDiscrete1D Source = IsFromA ? this.DataSourceA : this.DataSourceB;
144152

145-
int Count = Source.GetCountDiscrete();
146-
uint[] Data = Source.GetDataDiscrete();
147-
if (PopulatedTextureLocA == TEX_HEIGHT - 1) { return; } // Drop this data, we are too behind
148-
lock (NewTextureDataA)
149153
{
150-
Array.Copy(Data, 0, NewTextureDataA, PopulatedTextureLocA * TextureWidthA, Count);
151-
PopulatedTextureLocA++;
154+
int Count = this.DataSourceA.GetCountDiscrete();
155+
uint[] Data = this.DataSourceA.GetDataDiscrete();
156+
if (this.PopulatedTextureLocA >= TextureHeight - 1) { return; } // Drop this data, we are too behind
157+
lock (this.NewTextureDataA)
158+
{
159+
Array.Copy(Data, 0, this.NewTextureDataA, this.PopulatedTextureLocA * TextureWidthA, Count);
160+
this.PopulatedTextureLocA++;
161+
}
152162
}
163+
{
164+
int Count = this.DataSourceB.GetCountDiscrete();
165+
uint[] Data = this.DataSourceB.GetDataDiscrete();
166+
if (this.PopulatedTextureLocB >= TextureHeight - 1) { return; } // Drop this data, we are too behind
167+
lock (this.NewTextureDataB)
168+
{
169+
Array.Copy(Data, 0, this.NewTextureDataB, this.PopulatedTextureLocB * TextureWidthB, Count);
170+
this.PopulatedTextureLocB++;
171+
}
172+
}
173+
153174
this.NewData = true;
154175
}
155176

@@ -163,30 +184,57 @@ public void Render()
163184
if (this.PopulatedTextureLocA != 0)
164185
{
165186
GL.ActiveTexture(TextureUnit.Texture0);
166-
lock (NewTextureDataA)
187+
lock (this.NewTextureDataA)
167188
{
168-
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, this.UploadedTextureLocA, this.TextureWidthA, this.PopulatedTextureLocA, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataA);
169-
this.UploadedTextureLocA = (this.UploadedTextureLocA + this.PopulatedTextureLocA) % TEX_HEIGHT;
170-
GL.Uniform1(this.LocationAdvanceALive, (float)this.UploadedTextureLocA / TEX_HEIGHT);
189+
if (this.UploadedTextureLocA + this.PopulatedTextureLocA < TextureHeight)
190+
{
191+
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, this.UploadedTextureLocA, this.TextureWidthA, this.PopulatedTextureLocA, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataA);
192+
}
193+
else
194+
{
195+
int BottomCount = TextureHeight - this.UploadedTextureLocA;
196+
int TopCount = this.PopulatedTextureLocA - BottomCount;
197+
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, this.UploadedTextureLocA, this.TextureWidthA, BottomCount, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataA);
198+
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, this.TextureWidthA, TopCount, PixelFormat.Rgba, PixelType.UnsignedByte, ref this.NewTextureDataA[this.TextureWidthA * BottomCount]);
199+
}
200+
this.UploadedTextureLocA = (this.UploadedTextureLocA + this.PopulatedTextureLocA) % TextureHeight;
201+
GL.Uniform1(this.LocationAdvanceALive, (float)this.UploadedTextureLocA / TextureHeight);
171202
this.PopulatedTextureLocA = 0;
172203
}
173204
}
174205
if (this.PopulatedTextureLocB != 0)
175206
{
176-
207+
GL.ActiveTexture(TextureUnit.Texture1);
208+
lock (this.NewTextureDataB)
209+
{
210+
if (this.UploadedTextureLocB + this.PopulatedTextureLocB < TextureHeight)
211+
{
212+
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, this.UploadedTextureLocB, this.TextureWidthB, this.PopulatedTextureLocB, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataB);
213+
}
214+
else
215+
{
216+
int BottomCount = TextureHeight - this.UploadedTextureLocB;
217+
int TopCount = this.PopulatedTextureLocB - BottomCount;
218+
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, this.UploadedTextureLocB, this.TextureWidthB, BottomCount, PixelFormat.Rgba, PixelType.UnsignedByte, this.NewTextureDataB);
219+
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, this.TextureWidthB, TopCount, PixelFormat.Rgba, PixelType.UnsignedByte, ref this.NewTextureDataB[this.TextureWidthB * BottomCount]);
220+
}
221+
this.UploadedTextureLocB = (this.UploadedTextureLocB + this.PopulatedTextureLocB) % TextureHeight;
222+
GL.Uniform1(this.LocationAdvanceBLive, (float)this.UploadedTextureLocB / TextureHeight);
223+
this.PopulatedTextureLocB = 0;
224+
}
177225
}
178226
}
179227

180228
if (this.DoCaptureA)
181229
{
182-
GL.CopyImageSubData(this.TextureHandleA, ImageTarget.Texture2D, 0, 0, 0, 0, this.TextureHandleCaptureA, ImageTarget.Texture2D, 0, 0, 0, 0, this.TextureWidthA, TEX_HEIGHT, 1);
183-
GL.Uniform1(this.LocationAdvanceACapture, (float)this.UploadedTextureLocA / TEX_HEIGHT);
230+
GL.CopyImageSubData(this.TextureHandleA, ImageTarget.Texture2D, 0, 0, 0, 0, this.TextureHandleCaptureA, ImageTarget.Texture2D, 0, 0, 0, 0, this.TextureWidthA, TextureHeight, 1);
231+
GL.Uniform1(this.LocationAdvanceACapture, (float)this.UploadedTextureLocA / TextureHeight);
184232
this.DoCaptureA = false;
185233
}
186234
if (this.DoCaptureB)
187235
{
188-
GL.CopyImageSubData(this.TextureHandleA, ImageTarget.Texture2D, 0, 0, 0, 0, this.TextureHandleCaptureB, ImageTarget.Texture2D, 0, 0, 0, 0, this.TextureWidthA, TEX_HEIGHT, 1);
189-
GL.Uniform1(this.LocationAdvanceBCapture, (float)this.UploadedTextureLocA / TEX_HEIGHT);
236+
GL.CopyImageSubData(this.TextureHandleB, ImageTarget.Texture2D, 0, 0, 0, 0, this.TextureHandleCaptureB, ImageTarget.Texture2D, 0, 0, 0, 0, this.TextureWidthB, TextureHeight, 1);
237+
GL.Uniform1(this.LocationAdvanceBCapture, (float)this.UploadedTextureLocB / TextureHeight);
190238
this.DoCaptureB = false;
191239
}
192240

ColorChord.NET/Outputs/Display/Shaders/CaptureCompare.frag

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,13 @@ void main()
5050
{
5151
if (TexCoord.y < 0.5) // A
5252
{
53+
// 1.0~0.5 0.5~1.0 - 0 0.5 - *
5354
TextureColour = texture(TextureUnitALive, (vec2(1.0 - TexCoord.y, TexCoord.x) - vec2(0.0, HorizontalSplit - (AdvanceALive / 2.0))) * vec2(2.0, 1.0 / (1.0 - HorizontalSplit)));
5455
}
5556
else // B
5657
{
57-
TextureColour = texture(TextureUnitBLive, (TexCoord - vec2(HorizontalSplit, 0.5)) * vec2(1.0 / (1.0 - HorizontalSplit), 2.0));
58+
//
59+
TextureColour = texture(TextureUnitBLive, (vec2(1.0 - TexCoord.y, TexCoord.x) - vec2(0.5, HorizontalSplit - (AdvanceALive / 2.0))) * vec2(2.0, 1.0 / (1.0 - HorizontalSplit)));
5860
}
5961
}
6062

ColorChord.NET/Visualizers/NoteFinderPassthrough.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void GetData()
4040
{
4141
ReadOnlySpan<float> RawData = this.NoteFinder.AllBinValues;
4242
if (this.Data.Length != RawData.Length) { this.Data = new uint[RawData.Length]; }
43-
for (int i = 0; i < RawData.Length; i++) { this.Data[i] = VisualizerTools.CCToRGB((i % 24) / 24F, 1F, MathF.Pow(RawData[i] * 4.5F, 2F)); }
43+
for (int i = 0; i < RawData.Length; i++) { this.Data[i] = VisualizerTools.CCToRGB((float)i / this.NoteFinder.BinsPerOctave, 1F, MathF.Pow(RawData[i] * 4.5F, 2F)); }
4444
foreach (IOutput Out in this.Outputs) { Out.Dispatch(); }
4545
}
4646

0 commit comments

Comments
 (0)