Add ISoundLoader

The interface is to be implemented by all sound loaders, just like ISpriteLoader. All loading goes through the interface. This would allow mods to create their own sound loaders outside the engine.
Also add a SoundFormats property to mod.yaml, where mods can define what sound loaders they will need.
This requires Game.Sound to be initialized after the ModData is loaded.
This commit is contained in:
Pavel Penev
2015-11-19 00:27:22 +02:00
parent e5cb7e03e1
commit 8d56de80ca
5 changed files with 43 additions and 20 deletions

View File

@@ -293,10 +293,11 @@ namespace OpenRA
Settings.Game.Mod = mod; Settings.Game.Mod = mod;
Sound.StopVideo(); Sound.StopVideo();
Sound.Initialize();
ModData = new ModData(mod, !Settings.Server.Dedicated); ModData = new ModData(mod, !Settings.Server.Dedicated);
Sound.Initialize();
using (new PerfTimer("LoadMaps")) using (new PerfTimer("LoadMaps"))
ModData.MapCache.LoadMaps(); ModData.MapCache.LoadMaps();

View File

@@ -72,7 +72,7 @@ namespace OpenRA.Graphics
if (loader.TryParseSprite(stream, out frames)) if (loader.TryParseSprite(stream, out frames))
return frames; return frames;
throw new InvalidDataException(filename + " is not a valid sprite file"); throw new InvalidDataException(filename + " is not a valid sprite file!");
} }
} }
} }

View File

@@ -49,12 +49,14 @@ namespace OpenRA
public readonly Dictionary<string, string> RequiresMods; public readonly Dictionary<string, string> RequiresMods;
public readonly Dictionary<string, Pair<string, int>> Fonts; public readonly Dictionary<string, Pair<string, int>> Fonts;
public readonly string[] SoundFormats = { };
public readonly string[] SpriteFormats = { }; public readonly string[] SpriteFormats = { };
readonly string[] reservedModuleNames = { "Metadata", "Folders", "MapFolders", "Packages", "Rules", readonly string[] reservedModuleNames = { "Metadata", "Folders", "MapFolders", "Packages", "Rules",
"Sequences", "VoxelSequences", "Cursors", "Chrome", "Assemblies", "ChromeLayout", "Weapons", "Sequences", "VoxelSequences", "Cursors", "Chrome", "Assemblies", "ChromeLayout", "Weapons",
"Voices", "Notifications", "Music", "Translations", "TileSets", "ChromeMetrics", "Missions", "Voices", "Notifications", "Music", "Translations", "TileSets", "ChromeMetrics", "Missions",
"ServerTraits", "LoadScreen", "LobbyDefaults", "Fonts", "SupportsMapsFrom", "SpriteFormats", "RequiresMods" }; "ServerTraits", "LoadScreen", "LobbyDefaults", "Fonts", "SupportsMapsFrom", "SoundFormats", "SpriteFormats",
"RequiresMods" };
readonly TypeDictionary modules = new TypeDictionary(); readonly TypeDictionary modules = new TypeDictionary();
readonly Dictionary<string, MiniYaml> yaml; readonly Dictionary<string, MiniYaml> yaml;
@@ -113,6 +115,9 @@ namespace OpenRA
MapCompatibility = compat.ToArray(); MapCompatibility = compat.ToArray();
if (yaml.ContainsKey("SoundFormats"))
SoundFormats = FieldLoader.GetValue<string[]>("SoundFormats", yaml["SoundFormats"].Value);
if (yaml.ContainsKey("SpriteFormats")) if (yaml.ContainsKey("SpriteFormats"))
SpriteFormats = FieldLoader.GetValue<string[]>("SpriteFormats", yaml["SpriteFormats"].Value); SpriteFormats = FieldLoader.GetValue<string[]>("SpriteFormats", yaml["SpriteFormats"].Value);
} }

View File

@@ -25,6 +25,7 @@ namespace OpenRA
public readonly ObjectCreator ObjectCreator; public readonly ObjectCreator ObjectCreator;
public readonly WidgetLoader WidgetLoader; public readonly WidgetLoader WidgetLoader;
public readonly MapCache MapCache; public readonly MapCache MapCache;
public readonly ISoundLoader[] SoundLoaders;
public readonly ISpriteLoader[] SpriteLoaders; public readonly ISpriteLoader[] SpriteLoaders;
public readonly ISpriteSequenceLoader SpriteSequenceLoader; public readonly ISpriteSequenceLoader SpriteSequenceLoader;
public readonly RulesetCache RulesetCache; public readonly RulesetCache RulesetCache;
@@ -60,6 +61,18 @@ namespace OpenRA
RulesetCache.LoadingProgress += HandleLoadingProgress; RulesetCache.LoadingProgress += HandleLoadingProgress;
MapCache = new MapCache(this); MapCache = new MapCache(this);
var soundLoaders = new List<ISoundLoader>();
foreach (var format in Manifest.SoundFormats)
{
var loader = ObjectCreator.FindType(format + "Loader");
if (loader == null || !loader.GetInterfaces().Contains(typeof(ISoundLoader)))
throw new InvalidOperationException("Unable to find a sound loader for type '{0}'.".F(format));
soundLoaders.Add((ISoundLoader)ObjectCreator.CreateBasic(loader));
}
SoundLoaders = soundLoaders.ToArray();
var spriteLoaders = new List<ISpriteLoader>(); var spriteLoaders = new List<ISpriteLoader>();
foreach (var format in Manifest.SpriteFormats) foreach (var format in Manifest.SpriteFormats)
{ {

View File

@@ -9,14 +9,19 @@
#endregion #endregion
using System; using System;
using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using OpenRA.FileFormats;
using OpenRA.GameRules; using OpenRA.GameRules;
using OpenRA.Primitives; using OpenRA.Primitives;
namespace OpenRA namespace OpenRA
{ {
public interface ISoundLoader
{
bool TryParseSound(Stream stream, string fileName, out byte[] rawData, out int channels, out int sampleBits, out int sampleRate);
}
public sealed class Sound : IDisposable public sealed class Sound : IDisposable
{ {
readonly ISoundEngine soundEngine; readonly ISoundEngine soundEngine;
@@ -51,22 +56,21 @@ namespace OpenRA
return null; return null;
} }
if (filename.ToLowerInvariant().EndsWith("wav")) using (var stream = Game.ModData.ModFiles.Open(filename))
using (var s = Game.ModData.ModFiles.Open(filename)) {
return LoadWave(new WavLoader(s)); byte[] rawData;
int channels;
int sampleBits;
int sampleRate;
foreach (var loader in Game.ModData.SoundLoaders)
{
stream.Position = 0;
if (loader.TryParseSound(stream, filename, out rawData, out channels, out sampleBits, out sampleRate))
return soundEngine.AddSoundSourceFromMemory(rawData, channels, sampleBits, sampleRate);
}
using (var s = Game.ModData.ModFiles.Open(filename)) throw new InvalidDataException(filename + " is not a valid sound file!");
return LoadSoundRaw(AudLoader.LoadSound(s), 1, 16, 22050); }
}
ISoundSource LoadWave(WavLoader wave)
{
return soundEngine.AddSoundSourceFromMemory(wave.RawOutput, wave.Channels, wave.BitsPerSample, wave.SampleRate);
}
ISoundSource LoadSoundRaw(byte[] rawData, int channels, int sampleBits, int sampleRate)
{
return soundEngine.AddSoundSourceFromMemory(rawData, channels, sampleBits, sampleRate);
} }
public void Initialize() public void Initialize()
@@ -121,7 +125,7 @@ namespace OpenRA
public void PlayVideo(byte[] raw, int channels, int sampleBits, int sampleRate) public void PlayVideo(byte[] raw, int channels, int sampleBits, int sampleRate)
{ {
rawSource = LoadSoundRaw(raw, channels, sampleBits, sampleRate); rawSource = soundEngine.AddSoundSourceFromMemory(raw, channels, sampleBits, sampleRate);
video = soundEngine.Play2D(rawSource, false, true, WPos.Zero, InternalSoundVolume, false); video = soundEngine.Play2D(rawSource, false, true, WPos.Zero, InternalSoundVolume, false);
} }