78 lines
2.4 KiB
C#
78 lines
2.4 KiB
C#
namespace Mimir.Runtime.Synchronization;
|
|
|
|
public sealed record MimirChirpletSymbolDefinition(
|
|
int SymbolId,
|
|
MimirChirpletTone Tone,
|
|
double GapSeconds);
|
|
|
|
public sealed class MimirChirpletSymbolCodebook
|
|
{
|
|
private const int CandidateBandCount = 8;
|
|
private const int CandidateDurationCount = 5;
|
|
private const int CandidateGlideCount = 4;
|
|
private const int CandidateGapCount = 5;
|
|
|
|
private readonly MimirChirpletSymbolDefinition[] symbols;
|
|
|
|
private MimirChirpletSymbolCodebook()
|
|
{
|
|
symbols = BuildSymbols();
|
|
}
|
|
|
|
public static MimirChirpletSymbolCodebook Default { get; } = new();
|
|
|
|
public IReadOnlyList<MimirChirpletSymbolDefinition> Symbols => symbols;
|
|
|
|
public MimirChirpletSymbolDefinition this[int symbolId] => symbols[symbolId];
|
|
|
|
private static MimirChirpletSymbolDefinition[] BuildSymbols()
|
|
{
|
|
var symbols = new MimirChirpletSymbolDefinition[MimirChirpletTimeline.SymbolCount];
|
|
for (var symbol = 0; symbol < symbols.Length; symbol++)
|
|
{
|
|
var band = symbol % CandidateBandCount;
|
|
var glide = symbol / CandidateBandCount;
|
|
var duration = (band + 2 * glide) % CandidateDurationCount;
|
|
var gap = (3 * band + glide) % CandidateGapCount;
|
|
symbols[symbol] = new MimirChirpletSymbolDefinition(
|
|
symbol,
|
|
new MimirChirpletTone(
|
|
0.0,
|
|
DurationForClass(duration),
|
|
StartHzForBand(band),
|
|
EndHzFor(StartHzForBand(band), glide),
|
|
0.82),
|
|
GapForClass(gap));
|
|
}
|
|
|
|
return symbols;
|
|
}
|
|
|
|
private static double StartHzForBand(int band) =>
|
|
6_300.0 * Math.Pow(16_200.0 / 6_300.0, band / (double)(CandidateBandCount - 1));
|
|
|
|
private static double DurationForClass(int durationClass) =>
|
|
0.040 + durationClass * 0.0095;
|
|
|
|
private static double GapForClass(int gapClass) =>
|
|
gapClass switch
|
|
{
|
|
0 => 0.092,
|
|
1 => 0.109,
|
|
2 => 0.128,
|
|
3 => 0.146,
|
|
_ => 0.163,
|
|
};
|
|
|
|
private static double EndHzFor(double startHz, int glideClass)
|
|
{
|
|
var glideSemitones = glideClass switch
|
|
{
|
|
0 => -4.75,
|
|
1 => -1.50,
|
|
2 => 2.25,
|
|
_ => 5.75,
|
|
};
|
|
return Math.Clamp(startHz * Math.Pow(2.0, glideSemitones / 12.0), 6_000.0, 17_200.0);
|
|
}
|
|
}
|