Skip to content

Commit

Permalink
Fixed and expanded sound packs folder scanning code
Browse files Browse the repository at this point in the history
  • Loading branch information
sushiat committed Dec 23, 2023
1 parent 397f421 commit 052582d
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 56 deletions.
196 changes: 140 additions & 56 deletions OpenSky.Agent.Simulator/SpeechSoundPacks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace OpenSky.Agent.Simulator
using System.IO;
using System.Linq;
using System.Media;
using System.Reflection;
using System.Speech.Synthesis;
using System.Text.RegularExpressions;
using System.Threading;
Expand All @@ -20,21 +21,14 @@ namespace OpenSky.Agent.Simulator

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// Speech sound packs manager.
/// Speech soundpacks manager.
/// </summary>
/// <remarks>
/// sushi.at, 24/12/2021.
/// </remarks>
/// -------------------------------------------------------------------------------------------------
public class SpeechSoundPacks
{
/// -------------------------------------------------------------------------------------------------
/// <summary>
/// The single static instance.
/// </summary>
/// -------------------------------------------------------------------------------------------------
public static SpeechSoundPacks Instance { get; private set; }

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// The random generator.
Expand All @@ -49,25 +43,6 @@ public class SpeechSoundPacks
/// -------------------------------------------------------------------------------------------------
private readonly SpeechSynthesizer speech;

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// Initializes the speech sound packs.
/// </summary>
/// <remarks>
/// sushi.at, 31/01/2022.
/// </remarks>
/// <param name="selectedSoundPack">
/// The selected sound pack.
/// </param>
/// <param name="textToSpeechVoice">
/// The text to speech voice.
/// </param>
/// -------------------------------------------------------------------------------------------------
public static void InitializeSpeechSoundPacks(string selectedSoundPack, string textToSpeechVoice)
{
Instance = new SpeechSoundPacks(selectedSoundPack, textToSpeechVoice);
}

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="SpeechSoundPacks"/> class.
Expand All @@ -91,6 +66,7 @@ private SpeechSoundPacks(string selectedSoundPack, string textToSpeechVoice)

// Initialize the speech synthesizer
this.speech = new SpeechSynthesizer();
this.InitLog = $"Preparing TTS module for voice: {textToSpeechVoice}";
if (!string.IsNullOrEmpty(textToSpeechVoice))
{
try
Expand All @@ -99,62 +75,151 @@ private SpeechSoundPacks(string selectedSoundPack, string textToSpeechVoice)
}
catch (Exception ex)
{
Debug.WriteLine("Error setting text-to-speech voice from settings: " + ex);
Debug.WriteLine($"Error setting text-to-speech voice from settings: {ex}");
this.InitLog += $"\r\nError setting text-to-speech voice from settings:\r\n{ex}";
}
}
else
{
this.InitLog += "empty, skipping.";
}

// Scan sound pack folder for recognized wav files
foreach (var soundPackDirectory in Directory.EnumerateDirectories(".\\SoundPacks"))
var localSoundPacksPath = string.Empty;
try
{
var packName = soundPackDirectory.Split('\\').Last();
var packFiles = Directory.GetFiles(soundPackDirectory);
var packDictionary = new Dictionary<SpeechEvent, List<string>>();
foreach (SpeechEvent spEvent in Enum.GetValues(typeof(SpeechEvent)))
localSoundPacksPath = Path.GetDirectoryName(".\\SoundPacks") ?? string.Empty;
if (!localSoundPacksPath.EndsWith("SoundPacks"))
{
if (spEvent != SpeechEvent.ReadyForBoarding)
// Path doesn't exist
localSoundPacksPath = string.Empty;
}
}
catch
{
//Ignore
}

var assemblyLocationSoundPacksPath = string.Empty;
try
{
assemblyLocationSoundPacksPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty;
}
catch
{
//Ignore
}

if (!string.IsNullOrEmpty(assemblyLocationSoundPacksPath))
{
assemblyLocationSoundPacksPath = $"{assemblyLocationSoundPacksPath}\\SoundPacks";
if (!Directory.Exists(assemblyLocationSoundPacksPath))
{
assemblyLocationSoundPacksPath = string.Empty;
}
}

var openSkyFolderPath = Environment.ExpandEnvironmentVariables("%localappdata%\\OpenSky\\SoundPacks");
var openSkyAppDataSoundPacksPath = Directory.Exists(openSkyFolderPath) ? openSkyFolderPath : string.Empty;

this.InitLog += $"\r\n\r\nLocal soundpacks folder : {localSoundPacksPath}";
this.InitLog += $"\r\nAssembly location soundpacks folder: {assemblyLocationSoundPacksPath}";
this.InitLog += $"\r\nOpenSky appdata soundpacks folder : {openSkyAppDataSoundPacksPath}";

var dirsToScan = new List<string>();
if (!string.IsNullOrEmpty(localSoundPacksPath))
{
dirsToScan.Add(localSoundPacksPath);
}

if (!string.IsNullOrEmpty(assemblyLocationSoundPacksPath) && !localSoundPacksPath.ToLowerInvariant().Equals(assemblyLocationSoundPacksPath.ToLowerInvariant()))
{
dirsToScan.Add(assemblyLocationSoundPacksPath);
}

if (!string.IsNullOrEmpty(openSkyAppDataSoundPacksPath))
{
dirsToScan.Add(openSkyAppDataSoundPacksPath);
}

foreach (var packDir in dirsToScan)
{
this.InitLog += $"\r\n\r\nScanning directory for sound packs: {packDir}\r\n";
foreach (var soundPackDirectory in Directory.EnumerateDirectories(packDir))
{
this.InitLog += $"\r\nChecking pack directory: {soundPackDirectory}";
var packName = soundPackDirectory.Split('\\').Last();
var packFiles = Directory.GetFiles(soundPackDirectory);
var packDictionary = new Dictionary<SpeechEvent, List<string>>();
foreach (SpeechEvent spEvent in Enum.GetValues(typeof(SpeechEvent)))
{
var eventConfig = spEvent.GetStringValue();
if (eventConfig?.Contains("|") == true)
if (spEvent != SpeechEvent.ReadyForBoarding)
{
var fileMask = eventConfig.Split('|')[0];
foreach (var packFile in packFiles)
var eventConfig = spEvent.GetStringValue();
if (eventConfig?.Contains("|") == true)
{
if (Regex.IsMatch(packFile, fileMask))
var fileMask = eventConfig.Split('|')[0];
foreach (var packFile in packFiles)
{
if (!packDictionary.ContainsKey(spEvent))
if (Regex.IsMatch(packFile, fileMask))
{
packDictionary.Add(spEvent, new List<string>());
}
if (!packDictionary.ContainsKey(spEvent))
{
packDictionary.Add(spEvent, new List<string>());
}

packDictionary[spEvent].Add(packFile);
packDictionary[spEvent].Add(packFile);
this.InitLog += $"\r\nFound pack file for event {spEvent}: {packFile}";
}
}
}
}
}
}

// Check for special ReadyForBoarding meta event conditions
if (packDictionary.ContainsKey(SpeechEvent.ReadyForBoardingBeginning) && packDictionary.ContainsKey(SpeechEvent.ReadyForBoardingEnd) && packDictionary.ContainsKey(SpeechEvent.Number1) &&
packDictionary.ContainsKey(SpeechEvent.Number2) && packDictionary.ContainsKey(SpeechEvent.Number3) && packDictionary.ContainsKey(SpeechEvent.Number4) && packDictionary.ContainsKey(SpeechEvent.Number5) &&
packDictionary.ContainsKey(SpeechEvent.Number6) && packDictionary.ContainsKey(SpeechEvent.Number7) && packDictionary.ContainsKey(SpeechEvent.Number8) && packDictionary.ContainsKey(SpeechEvent.Number9) &&
packDictionary.ContainsKey(SpeechEvent.Number0))
{
packDictionary.Add(SpeechEvent.ReadyForBoarding, null);
}
// Check for special ReadyForBoarding meta event conditions
if (packDictionary.ContainsKey(SpeechEvent.ReadyForBoardingBeginning) && packDictionary.ContainsKey(SpeechEvent.ReadyForBoardingEnd) && packDictionary.ContainsKey(SpeechEvent.Number1) &&
packDictionary.ContainsKey(SpeechEvent.Number2) && packDictionary.ContainsKey(SpeechEvent.Number3) && packDictionary.ContainsKey(SpeechEvent.Number4) && packDictionary.ContainsKey(SpeechEvent.Number5) &&
packDictionary.ContainsKey(SpeechEvent.Number6) && packDictionary.ContainsKey(SpeechEvent.Number7) && packDictionary.ContainsKey(SpeechEvent.Number8) && packDictionary.ContainsKey(SpeechEvent.Number9) &&
packDictionary.ContainsKey(SpeechEvent.Number0))
{
packDictionary.Add(SpeechEvent.ReadyForBoarding, null);
this.InitLog += $"\r\nMarking meta-event ReadyForBoarding as available for pack: {packName}";
}

// Does the pack contain any recognized files?
if (packDictionary.Count > 0)
{
this.SoundPacks.Add(packName, packDictionary);
// Does the pack contain any recognized files?
if (packDictionary.Count > 0)
{
this.SoundPacks.Add(packName, packDictionary);
this.InitLog += $"\r\nPack {packName} has valid events, adding to list.\r\n";
}
else
{
this.InitLog += $"\r\nPack {packName} has NO valid events!!!, skipping.\r\n";
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error initializing sound packs: {ex}");
this.InitLog += $"\r\n\r\nError initializing sound packs:\r\n{ex}";
}
}

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// The single static instance.
/// </summary>
/// -------------------------------------------------------------------------------------------------
public static SpeechSoundPacks Instance { get; private set; }

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// Gets the initialize log.
/// </summary>
/// -------------------------------------------------------------------------------------------------
public string InitLog { get; private set; }

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the selected sound pack.
Expand All @@ -169,6 +234,25 @@ private SpeechSoundPacks(string selectedSoundPack, string textToSpeechVoice)
/// -------------------------------------------------------------------------------------------------
public Dictionary<string, Dictionary<SpeechEvent, List<string>>> SoundPacks { get; } = new();

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// Initializes the speech sound packs.
/// </summary>
/// <remarks>
/// sushi.at, 31/01/2022.
/// </remarks>
/// <param name="selectedSoundPack">
/// The selected sound pack.
/// </param>
/// <param name="textToSpeechVoice">
/// The text to speech voice.
/// </param>
/// -------------------------------------------------------------------------------------------------
public static void InitializeSpeechSoundPacks(string selectedSoundPack, string textToSpeechVoice)
{
Instance = new SpeechSoundPacks(selectedSoundPack, textToSpeechVoice);
}

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// Play the specified speech event from the selected or randomized sound pack, or use TTS as a
Expand Down
1 change: 1 addition & 0 deletions OpenSky.Agent.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ OpenSky project ${CurrentDate.Year}&#xD;
<s:Boolean x:Key="/Default/UserDictionary/Words/=PMDG/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=POSI/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=SEATBELTS/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=soundpacks/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Syncfusion/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Templated/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Vatsim/@EntryIndexedValue">True</s:Boolean>
Expand Down
7 changes: 7 additions & 0 deletions OpenSky.Agent/Views/Models/SoundPackTesterViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ public string FlightNumber
}
}

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// Gets the initialize log.
/// </summary>
/// -------------------------------------------------------------------------------------------------
public string InitLog => SpeechSoundPacks.Instance.InitLog;

/// -------------------------------------------------------------------------------------------------
/// <summary>
/// Gets the play speech event command.
Expand Down
6 changes: 6 additions & 0 deletions OpenSky.Agent/Views/SoundPackTester.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,11 @@
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<GroupBox>
<GroupBox.Header>
<TextBlock>Sound pack initialization log</TextBlock>
</GroupBox.Header>
<TextBox MinLines="40" MaxLines="40" VerticalScrollBarVisibility="Auto" IsReadOnly="True" FontFamily="Consolas" Text="{Binding InitLog, Mode=OneWay}" />
</GroupBox>
</StackPanel>
</controls:OpenSkyWindow>

0 comments on commit 052582d

Please sign in to comment.