Skip to content

Commit

Permalink
In-CavernPipe layout change and 4.1.3 support
Browse files Browse the repository at this point in the history
  • Loading branch information
VoidXH committed Jan 20, 2025
1 parent 1cd3ee0 commit ed05709
Show file tree
Hide file tree
Showing 26 changed files with 421 additions and 112 deletions.
13 changes: 13 additions & 0 deletions Cavern.WPF/Consts/Language.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ public static class Language {
public static void Error(string message) =>
MessageBox.Show(message, (string)GetCommonStrings()["TErro"], MessageBoxButton.OK, MessageBoxImage.Error);

/// <summary>
/// Show a warning <paramref name="message"/> with the title in the user's language.
/// </summary>
public static MessageBoxResult Warning(string message) =>
MessageBox.Show(message, (string)GetCommonStrings()["TWarn"], MessageBoxButton.OK, MessageBoxImage.Warning);

/// <summary>
/// Show a warning <paramref name="message"/> with the title in the user's language.
/// </summary>
public static MessageBoxResult Warning(string message, MessageBoxButton buttons) =>
MessageBox.Show(message, (string)GetCommonStrings()["TWarn"], buttons, MessageBoxImage.Warning);

/// <summary>
/// Return a channel's name in the user's language or fall back to its short name.
/// </summary>
Expand Down Expand Up @@ -73,6 +85,7 @@ public static string Translate(this ReferenceChannel channel) {
ReferenceChannel.TopRearLeft => (string)dictionary["SpTRL"],
ReferenceChannel.TopRearCenter => (string)dictionary["SpTRC"],
ReferenceChannel.TopRearRight => (string)dictionary["SpTRR"],
ReferenceChannel.Unknown => (string)dictionary["SpUnk"],
_ => channel.GetShortName()
};
}
Expand Down
47 changes: 47 additions & 0 deletions Cavern.WPF/Consts/LanguageExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;

using Cavern.Channels;

namespace Cavern.WPF.Consts {
/// <summary>
/// Extension functions for calculating translated text.
/// </summary>
public static class LanguageExtensions {
/// <summary>
/// Display how a set of spatial <paramref name="channels"/> shall be wired for regular audio interfaces.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void DisplayWiring(this ReferenceChannel[] channels) => channels.DisplayWiring(null);

/// <summary>
/// Display how a set of spatial <paramref name="channels"/> shall be wired for regular audio interfaces when some channels are
/// <paramref name="matrixed"/> into 8 channels to be extracted when the speaker is wired to two positive terminals. These matrixed channels
/// are not part of the base <paramref name="channels"/>.
/// </summary>
public static void DisplayWiring(this ReferenceChannel[] channels,
(ReferenceChannel source, ReferenceChannel posPhase, ReferenceChannel negPhase)[] matrixed) {
ResourceDictionary language = Language.GetChannelSelectorStrings();
ChannelPrototype[] prototypes = ChannelPrototype.Get(channels);
if (channels.Length > 8) {
MessageBox.Show(string.Format((string)language["Over8"], string.Join(string.Empty, prototypes.Select(x => "\n- " + x.Name)),
(string)language["WrGui"]));
return;
}

StringBuilder output = new StringBuilder();
ReferenceChannel[] standard = ChannelPrototype.GetStandardMatrix(prototypes.Length);
for (int i = 0; i < prototypes.Length; i++) {
output.AppendLine(string.Format((string)language["ChCon"], channels[i].Translate(), standard[i].Translate()));
}
if (matrixed != null) {
for (int i = 0; i < matrixed.Length; i++) {
output.AppendLine(string.Format((string)language["ChCMx"],
matrixed[i].source.Translate(), matrixed[i].posPhase.Translate(), matrixed[i].negPhase.Translate()));
}
}
MessageBox.Show(output.ToString(), (string)language["WrGui"]);
}
}
}
8 changes: 8 additions & 0 deletions Cavern.WPF/Resources/ChannelSelectorStrings.hu-HU.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,12 @@
<system:String x:Key="SpTRL">Felső hátsó bal</system:String>
<system:String x:Key="SpTRC">Felső hátsó közép</system:String>
<system:String x:Key="SpTRR">Felső hátsó jobb</system:String>
<system:String x:Key="SpUnk">Ismeretlen</system:String>

<system:String x:Key="WrGui">Bekötési útmutató</system:String>
<system:String x:Key="ChCon">Kösd a (z) {0} hangszórót a rendszered {1} kimenetére.</system:String>
<system:String x:Key="ChCMx">Kösd a (z) {0} hangszóró + csatlakozóját a(z) {1} kimenet +-ára, valamint a hangszóró - csatlakozóját
a(z) {2} kimenet +-ára.</system:String>
<system:String x:Key="Over8">Nincs szabványos bekötés 8 csatorna felett. Masszívan többcsatornás interfészeknél a csatornák
rendje pontosan az, ami a fájlban is:{0}</system:String>
</ResourceDictionary>
7 changes: 7 additions & 0 deletions Cavern.WPF/Resources/ChannelSelectorStrings.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,11 @@
<system:String x:Key="SpTRL">Top rear left</system:String>
<system:String x:Key="SpTRC">Top rear center</system:String>
<system:String x:Key="SpTRR">Top rear right</system:String>
<system:String x:Key="SpUnk">Unknown</system:String>

<system:String x:Key="WrGui">Wiring guide</system:String>
<system:String x:Key="ChCon">Connect the {0} speaker to your system's {1} output.</system:String>
<system:String x:Key="ChCMx">Connect the {0} speaker's + terminal to the {1} output's + and the speaker's - terminal to the {2} output's +.</system:String>
<system:String x:Key="Over8">There is no standard wiring over 8 channels. For massively multichannel interfaces,
the channel order is exactly as it's in the file:{0}</system:String>
</ResourceDictionary>
1 change: 1 addition & 0 deletions Cavern.WPF/Resources/CommonStrings.hu-HU.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
<system:String x:Key="BtnOk">OK</system:String>
<system:String x:Key="BtnCa">Mégse</system:String>
<system:String x:Key="TErro">Hiba</system:String>
<system:String x:Key="TWarn">Figyelmeztetés</system:String>
<system:String x:Key="ImFmt">Minden támogatott formátum|{0}</system:String>
</ResourceDictionary>
1 change: 1 addition & 0 deletions Cavern.WPF/Resources/CommonStrings.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
<system:String x:Key="BtnOk">OK</system:String>
<system:String x:Key="BtnCa">Cancel</system:String>
<system:String x:Key="TErro">Error</system:String>
<system:String x:Key="TWarn">Warning</system:String>
<system:String x:Key="ImFmt">All supported formats|{0}</system:String>
</ResourceDictionary>
25 changes: 25 additions & 0 deletions Cavern/Channels/ChannelPrototype.Consts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,31 @@ public static readonly ChannelPrototype
/// </summary>
public static readonly ReferenceChannel[] ref300 = { ReferenceChannel.FrontLeft, ReferenceChannel.FrontRight, ReferenceChannel.FrontCenter };

/// <summary>
/// Standard 3.1.2 setup (L, R, C, LFE, TFL, TFR).
/// </summary>
public static readonly ReferenceChannel[] ref312 = { ReferenceChannel.FrontLeft, ReferenceChannel.FrontRight, ReferenceChannel.FrontCenter, ReferenceChannel.ScreenLFE, ReferenceChannel.TopFrontLeft, ReferenceChannel.TopFrontRight };

/// <summary>
/// Standard 4.0.0 setup (L, R, SL, SR).
/// </summary>
public static readonly ReferenceChannel[] ref400 = { ReferenceChannel.FrontLeft, ReferenceChannel.FrontRight, ReferenceChannel.SideLeft, ReferenceChannel.SideRight };

/// <summary>
/// Standard 4.0.4 setup (L, R, RL, RR, TFL, TFR, TRL, TRR).
/// </summary>
public static readonly ReferenceChannel[] ref404 = { ReferenceChannel.FrontLeft, ReferenceChannel.FrontRight, ReferenceChannel.RearLeft, ReferenceChannel.RearRight, ReferenceChannel.TopFrontLeft, ReferenceChannel.TopFrontRight, ReferenceChannel.TopRearLeft, ReferenceChannel.TopRearRight };

/// <summary>
/// Standard 4.1.1 setup (L, R, C, LFE, RC, TFC).
/// </summary>
public static readonly ReferenceChannel[] ref411 = { ReferenceChannel.FrontLeft, ReferenceChannel.FrontRight, ReferenceChannel.FrontCenter, ReferenceChannel.ScreenLFE, ReferenceChannel.RearCenter, ReferenceChannel.TopFrontCenter };

/// <summary>
/// Standard 4.1.3 setup (L, R, C, LFE, RC, TFC, TRL, TRR).
/// </summary>
public static readonly ReferenceChannel[] ref413 = { ReferenceChannel.FrontLeft, ReferenceChannel.FrontRight, ReferenceChannel.FrontCenter, ReferenceChannel.ScreenLFE, ReferenceChannel.RearCenter, ReferenceChannel.TopFrontCenter, ReferenceChannel.TopRearLeft, ReferenceChannel.TopRearRight };

/// <summary>
/// Standard 5.0.0 setup (L, R, C, SL, SR).
/// </summary>
Expand Down Expand Up @@ -194,6 +214,11 @@ public static readonly ChannelPrototype
/// </summary>
public static readonly ReferenceChannel[] wav906 = { ReferenceChannel.FrontLeft, ReferenceChannel.FrontRight, ReferenceChannel.FrontCenter, ReferenceChannel.RearLeft, ReferenceChannel.RearRight, ReferenceChannel.SideLeft, ReferenceChannel.SideRight, ReferenceChannel.WideLeft, ReferenceChannel.WideRight, ReferenceChannel.TopFrontLeft, ReferenceChannel.TopFrontCenter, ReferenceChannel.TopFrontRight, ReferenceChannel.TopRearLeft, ReferenceChannel.TopRearCenter, ReferenceChannel.TopRearRight };

/// <summary>
/// Standard 9.1.0 setup (L, R, C, LFE, RL, RR, SL, SR, WL, WR).
/// </summary>
public static readonly ReferenceChannel[] ref910 = { ReferenceChannel.FrontLeft, ReferenceChannel.FrontRight, ReferenceChannel.FrontCenter, ReferenceChannel.ScreenLFE, ReferenceChannel.RearLeft, ReferenceChannel.RearRight, ReferenceChannel.SideLeft, ReferenceChannel.SideRight, ReferenceChannel.WideLeft, ReferenceChannel.WideRight };

/// <summary>
/// Standard 9.1.4 setup (L, R, C, LFE, RL, RR, SL, SR, WL, WR, TFL, TFR, TRL, TRR).
/// </summary>
Expand Down
15 changes: 14 additions & 1 deletion Cavern/Channels/ChannelPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.Numerics;
using System.Runtime.CompilerServices;

using Cavern.Utilities;

namespace Cavern.Channels {
/// <summary>
/// Light audio channel information structure.
Expand Down Expand Up @@ -192,13 +194,24 @@ public static ReferenceChannel GetReference(Channel source) {
}
Vector3 cubicalPos = source.CubicalPos;
for (int i = 0; i < AlternativePositions.Length; i++) {
if (AlternativePositions[i] == cubicalPos) {
if (AlternativePositions[i].CloseTo(cubicalPos, .05f)) {
return (ReferenceChannel)i;
}
}
return ReferenceChannel.Unknown;
}

/// <summary>
/// Get which channels this layout represents.
/// </summary>
public static ReferenceChannel[] GetReferences(Channel[] source) {
ReferenceChannel[] result = new ReferenceChannel[source.Length];
for (int i = 0; i < source.Length; i++) {
result[i] = GetReference(source[i]);
}
return result;
}

/// <summary>
/// Convert a mapping of <see cref="ReferenceChannel"/>s to channel name initials.
/// </summary>
Expand Down
82 changes: 82 additions & 0 deletions Cavern/Internals/Configuration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using System.Globalization;
using System.IO;

namespace Cavern.Internals {
/// <summary>
/// Functions to modify Cavern's global configuration. See <see cref="IKnowWhatIAmDoing"/> for warnings.
/// </summary>
public static class CavernConfiguration {
/// <summary>
/// These are very wild waters and you should really evaluate if you need these functions or not.
/// You are given the power to modify the user's global settings which are reflected in all Cavern
/// products and applications/games built on Cavern. If the user is not properly prompted that for
/// example, the speakers are getting reordered in all applications, they can blame Cavern for bugs
/// it doesn't have. Your page names, prompts, and UIs should completely convey that the user is
/// editing the GLOBAL settings. You should really make it sure they WANT to do EXACTLY what is
/// being called from here. To be safe and always support the Cavern ecosystem properly, just ask
/// the user to use the Cavern Driver. If they never used Cavern Driver, Cavern falls back to 5.1,
/// which is the only safe option to mix to any channel layout with limited system knowledge.
/// If you're extra sure you won't break the user's setup, set this to true to use the class.
/// </summary>
public static bool IKnowWhatIAmDoing { get; set; }

/// <summary>
/// Get the path of the folder that contains Cavern's configuration files.
/// </summary>
public static string GetPath() {
if (!IKnowWhatIAmDoing) {
throw new DevHasNoIdeaException();
}

string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Cavern");
if (!Directory.Exists(path)) {
Directory.CreateDirectory(path);
}
return path;
}

/// <summary>
/// Overwrite the global environment (including channel layout) used by all applications built on Cavern.
/// </summary>
public static void SaveCurrentLayoutAsDefault() => SaveCurrentLayoutAs("Save");

/// <summary>
/// Save an environment (including channel layout) preset option that can be recalled in the Cavern Driver.
/// </summary>
public static void SaveCurrentLayoutAsPreset(string presetName) => SaveCurrentLayoutAs(presetPrefix + presetName);

/// <summary>
/// Delete a preset that was saved with <see cref="SaveCurrentLayoutAsPreset(string)"/>.
/// </summary>
public static void DeletePreset(string presetName) => File.Delete(Path.Combine(GetPath(), $"{presetPrefix}{presetName}.dat"));

/// <summary>
/// Save an environment (including channel layout) preset option that can be recalled in the Cavern Driver.
/// </summary>
static void SaveCurrentLayoutAs(string presetName) {
Channel[] channels = Listener.Channels;
string[] save = new string[channels.Length * 3 + 7];
save[0] = channels.Length.ToString();
int savePos = 1;
for (int i = 0; i < channels.Length; i++) {
save[savePos] = channels[i].X.ToString(CultureInfo.InvariantCulture);
save[savePos + 1] = channels[i].Y.ToString(CultureInfo.InvariantCulture);
save[savePos + 2] = channels[i].LFE.ToString();
savePos += 3;
}
save[savePos] = ((int)Listener.EnvironmentType).ToString();
save[savePos + 1] = Listener.EnvironmentSize.X.ToString(CultureInfo.InvariantCulture);
save[savePos + 2] = Listener.EnvironmentSize.Y.ToString(CultureInfo.InvariantCulture);
save[savePos + 3] = Listener.EnvironmentSize.Z.ToString(CultureInfo.InvariantCulture);
save[savePos + 4] = Listener.HeadphoneVirtualizer.ToString();
save[savePos + 5] = string.Empty; // Was: environment compensation
File.WriteAllLines(Path.Combine(GetPath(), presetName + ".dat"), save);
}

/// <summary>
/// The name of all environment preset files in Cavern's configuration folder start with this.
/// </summary>
const string presetPrefix = "CavernPreset_";
}
}
15 changes: 15 additions & 0 deletions Cavern/Internals/_Exceptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Cavern.Internals {
/// <summary>
/// Tells if the developer used something without properly understanding what it does.
/// </summary>
public class DevHasNoIdeaException : Exception {
const string message = "The developer is very irresponsible.";

/// <summary>
/// Tells if the developer used something without properly understanding what it does.
/// </summary>
public DevHasNoIdeaException() : base(message) { }
}
}
6 changes: 6 additions & 0 deletions Cavern/Utilities/VectorExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public static class VectorExtensions {
/// </summary>
internal const float Sqrt2p2 = .7071067811f;

/// <summary>
/// Check if all 3 components are at max <paramref name="epsilon"/> apart for the two vectors.
/// </summary>
public static bool CloseTo(this Vector3 vector, Vector3 other, float epsilon) =>
Math.Abs(vector.X - other.X) < epsilon && Math.Abs(vector.Y - other.Y) < epsilon && Math.Abs(vector.Z - other.Z) < epsilon;

/// <summary>
/// Returns a vector that's the same direction as the source vector, but it's on the side of a 2x2x2 cube.
/// </summary>
Expand Down
8 changes: 7 additions & 1 deletion CavernSamples/CavernPipeServer/CavernPipeRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ public class CavernPipeRenderer : IDisposable {
/// </summary>
public event OnMetersAvailable MetersAvailable;

/// <summary>
/// Exceptions coming from the rendering thread are passed down from this event.
/// </summary>
public event Action<Exception> OnException;

/// <summary>
/// Protocol message decoder.
/// </summary>
Expand Down Expand Up @@ -96,8 +101,9 @@ void RenderThread() {
streamDumper.WriteBlock(reRender, 0, reRender.LongLength);
}
}
} catch {
} catch (Exception e) {
Dispose();
OnException?.Invoke(e);
}
}

Expand Down
1 change: 1 addition & 0 deletions CavernSamples/CavernPipeServer/CavernPipeServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Cavern.Format\Cavern.Format.csproj" />
<ProjectReference Include="..\..\Cavern.WPF\Cavern.WPF.csproj" />
</ItemGroup>
<ItemGroup>
<_DeploymentManifestIconFile Remove="..\Icon.ico" />
Expand Down
5 changes: 3 additions & 2 deletions CavernSamples/CavernPipeServer/ChannelMeters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using Cavern;
using Cavern.Channels;
using Cavern.WPF.Consts;

namespace CavernPipeServer {
/// <summary>
Expand Down Expand Up @@ -38,7 +39,7 @@ public class ChannelMeters(Panel canvas, TextBlock labelProto, ProgressBar barPr
/// so the <see cref="Listener.Channels"/> are what will be rendered.
/// </summary>
public virtual void Enable() {
string[] channels = ChannelPrototype.GetNames(Listener.Channels);
ReferenceChannel[] channels = ChannelPrototype.GetReferences(Listener.Channels);
displays = new (TextBlock, ProgressBar)[channels.Length];
movingPeaks = new float[channels.Length];
for (int i = 0; i < channels.Length; i++) {
Expand All @@ -47,7 +48,7 @@ public virtual void Enable() {
Margin = new Thickness(labelProto.Margin.Left, marginTop, labelProto.Margin.Right, 0),
HorizontalAlignment = labelProto.HorizontalAlignment,
VerticalAlignment = labelProto.VerticalAlignment,
Text = channels[i]
Text = channels[i].Translate()
};
ProgressBar progressBar = new ProgressBar {
Margin = new Thickness(barProto.Margin.Left, marginTop, barProto.Margin.Right, 0),
Expand Down
6 changes: 0 additions & 6 deletions CavernSamples/CavernPipeServer/Consts/Language.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ static class Language {
/// </summary>
public static ResourceDictionary GetMainWindowStrings() => mainWindowCache ??= GetFor("MainWindowStrings");

/// <summary>
/// Show the message in an error dialog with the localized &quot;Error&quot; title.
/// </summary>
public static void ShowError(string message) =>
MessageBox.Show(message, (string)GetMainWindowStrings()["Error"], MessageBoxButton.OK, MessageBoxImage.Error);

/// <summary>
/// Get the translation of a resource file in the user's language, or in English if a translation couldn't be found.
/// </summary>
Expand Down
Loading

0 comments on commit ed05709

Please sign in to comment.