Difference between revisions of "Modding talk:Audio"
Jump to navigation
Jump to search
Pathoschild (talk | contribs) (→Track list export: + sortable) |
Pathoschild (talk | contribs) (→Track list export: update code) |
||
Line 24: | Line 24: | ||
{ | { | ||
string soundIdLabel = sound.Id.ToString("X").ToLower().PadLeft(8, '0'); | string soundIdLabel = sound.Id.ToString("X").ToLower().PadLeft(8, '0'); | ||
− | output.AppendLine($"|-\n| <tt>{sound.Name}</tt>\n| <tt>{soundIdLabel}</tt>\n| "); | + | output.AppendLine($"|-\n| <tt>{sound.Name}</tt>\n| data-sort-value=\"{sound.Id}\"| <tt>{soundIdLabel}</tt>\n| "); |
} | } | ||
Line 81: | Line 81: | ||
// export tracks | // export tracks | ||
− | foreach (int id in ids) | + | if (ids.Any()) |
+ | { | ||
+ | foreach (int id in ids) | ||
+ | { | ||
+ | yield return new SoundInfo | ||
+ | { | ||
+ | Category = category, | ||
+ | Name = name, | ||
+ | Id = id | ||
+ | }; | ||
+ | } | ||
+ | } | ||
+ | else | ||
{ | { | ||
yield return new SoundInfo | yield return new SoundInfo | ||
Line 87: | Line 99: | ||
Category = category, | Category = category, | ||
Name = name, | Name = name, | ||
− | Id = | + | Id = 0 |
}; | }; | ||
} | } | ||
Line 118: | Line 130: | ||
} | } | ||
</syntaxhighlight>}} | </syntaxhighlight>}} | ||
− | —<small>[[User:Pathoschild|Pathoschild]] ([[User talk:Pathoschild|talk]]) | + | —<small>[[User:Pathoschild|Pathoschild]] ([[User talk:Pathoschild|talk]]) 03:22, 17 October 2021 (UTC)</small> |
Revision as of 03:22, 17 October 2021
Track list export
The initial track list was exported with this quick code, which can be run as a C# mod:
source code |
---|
/// <summary>The main entry point for the mod.</summary>
public class ModEntry : Mod
{
/*********
** Public methods
*********/
/// <inheritdoc />
public override void Entry(IModHelper helper)
{
helper.Events.GameLoop.GameLaunched += (_, _) =>
{
StringBuilder output = new();
foreach (var categoryGroup in this.GetTracks().GroupBy(p => p.Category).OrderBy(p => p.Key))
{
output.AppendLine($"==={categoryGroup.Key}===");
output.AppendLine("{| class=\"wikitable sortable\"");
output.AppendLine("|-\n! name\n! soundbank ID\n! description");
foreach (SoundInfo sound in categoryGroup.OrderBy(p => p.Name).ThenBy(p => p.Id))
{
string soundIdLabel = sound.Id.ToString("X").ToLower().PadLeft(8, '0');
output.AppendLine($"|-\n| <tt>{sound.Name}</tt>\n| data-sort-value=\"{sound.Id}\"| <tt>{soundIdLabel}</tt>\n| ");
}
output.AppendLine("|}");
output.AppendLine();
}
string result = output.ToString();
this.Monitor.Log(result, LogLevel.Info);
};
}
/*********
** Private methods
*********/
/// <summary>Extract the music/sound tracks from the game's soundbank.</summary>
private IEnumerable<SoundInfo> GetTracks()
{
SoundBank soundBank = this.Helper.Reflection.GetField<SoundBank>(Game1.soundBank, "soundBank").GetValue();
Dictionary<string, CueDefinition> cues = this.Helper.Reflection.GetField<Dictionary<string, CueDefinition>>(soundBank, "_cues").GetValue();
foreach (var entry in cues)
{
foreach (XactSoundBankSound sound in entry.Value.sounds)
{
HashSet<int> ids = new();
// from main sound info
string name = entry.Key;
string category = this.GetCategoryName(sound.categoryID);
if (sound.trackIndex != 0)
ids.Add(sound.trackIndex);
// from variants
if (sound.soundClips != null)
{
foreach (XactClip clip in sound.soundClips)
{
foreach (var rawClipEvent in clip.clipEvents)
{
if (rawClipEvent is not PlayWaveEvent clipEvent)
{
this.Monitor.Log($"Unexpected clip event type '{rawClipEvent.GetType().FullName}'.", LogLevel.Error);
continue;
}
foreach (var variant in clipEvent.GetVariants())
{
if (variant.track != 0)
ids.Add(variant.track);
}
}
}
}
// export tracks
if (ids.Any())
{
foreach (int id in ids)
{
yield return new SoundInfo
{
Category = category,
Name = name,
Id = id
};
}
}
else
{
yield return new SoundInfo
{
Category = category,
Name = name,
Id = 0
};
}
}
}
}
/// <summary>Get a human-readable name for a raw audio category ID.</summary>
/// <param name="categoryId">The raw category ID.</param>
private string GetCategoryName(uint categoryId)
{
// the categories seem to be arbitrarily defined for Stardew Valley;
// these are approximate labels based on the tracks in each group.
return categoryId switch
{
2 => "Music",
3 => "Sound",
4 => "Music (ambient)",
5 => "Footsteps",
_ => categoryId.ToString()
};
}
}
public class SoundInfo
{
public string Category { get; set; }
public string Name { get; set; }
public int Id { get; set; }
}
|
—Pathoschild (talk) 03:22, 17 October 2021 (UTC)