Add support for gapless looping music.

This commit is contained in:
Matthias Mailänder
2021-08-22 20:59:13 +02:00
committed by abcdefg30
parent 9916e4c4ac
commit 9b1cec7712
6 changed files with 43 additions and 18 deletions

View File

@@ -137,6 +137,12 @@ namespace OpenRA
soundEngine.Volume = 1f; soundEngine.Volume = 1f;
} }
public void SetMusicLooped(bool loop)
{
Game.Settings.Sound.Repeat = loop;
soundEngine.SetSoundLooping(loop, music);
}
public bool DisableAllSounds { get; set; } public bool DisableAllSounds { get; set; }
public bool DisableWorldSounds { get; set; } public bool DisableWorldSounds { get; set; }
public ISound Play(SoundType type, string name) { return Play(type, null, name, true, WPos.Zero, 1f); } public ISound Play(SoundType type, string name) { return Play(type, null, name, true, WPos.Zero, 1f); }
@@ -202,11 +208,6 @@ namespace OpenRA
public bool MusicPlaying { get; private set; } public bool MusicPlaying { get; private set; }
public MusicInfo CurrentMusic => currentMusic; public MusicInfo CurrentMusic => currentMusic;
public void PlayMusic(MusicInfo m)
{
PlayMusicThen(m, () => { });
}
public void PlayMusicThen(MusicInfo m, Action then) public void PlayMusicThen(MusicInfo m, Action then)
{ {
if (m == null || !m.Exists) if (m == null || !m.Exists)
@@ -221,13 +222,21 @@ namespace OpenRA
return; return;
} }
PlayMusic(m, Game.Settings.Sound.Repeat);
}
public void PlayMusic(MusicInfo m, bool looped = false)
{
if (m == null || !m.Exists)
return;
StopMusic(); StopMusic();
Func<ISoundFormat, ISound> stream = soundFormat => soundEngine.Play2DStream( Func<ISoundFormat, ISound> stream = soundFormat => soundEngine.Play2DStream(
soundFormat.GetPCMInputStream(), soundFormat.Channels, soundFormat.SampleBits, soundFormat.SampleRate, soundFormat.GetPCMInputStream(), soundFormat.Channels, soundFormat.SampleBits, soundFormat.SampleRate,
false, true, WPos.Zero, MusicVolume * m.VolumeModifier); looped, true, WPos.Zero, MusicVolume * m.VolumeModifier);
music = LoadSound(m.Filename, stream);
music = LoadSound(m.Filename, stream);
if (music == null) if (music == null)
{ {
onMusicComplete = null; onMusicComplete = null;

View File

@@ -28,6 +28,7 @@ namespace OpenRA
void StopAllSounds(); void StopAllSounds();
void SetListenerPosition(WPos position); void SetListenerPosition(WPos position);
void SetSoundVolume(float volume, ISound music, ISound video); void SetSoundVolume(float volume, ISound music, ISound video);
void SetSoundLooping(bool looping, ISound sound);
} }
public class SoundDevice public class SoundDevice

View File

@@ -162,13 +162,15 @@ namespace OpenRA.Mods.Common.Traits
if (!SongExists(currentSong) || (CurrentSongIsBackground && IsBackgroundMusicMuted)) if (!SongExists(currentSong) || (CurrentSongIsBackground && IsBackgroundMusicMuted))
return; return;
Game.Sound.PlayMusicThen(currentSong, () => Game.Sound.PlayMusicThen(currentSong, PlayNextSong);
{ }
if (!CurrentSongIsBackground && !Game.Settings.Sound.Repeat)
currentSong = GetNextSong();
Play(); void PlayNextSong()
}); {
if (!CurrentSongIsBackground)
currentSong = GetNextSong();
Play();
} }
public void Play(MusicInfo music) public void Play(MusicInfo music)

View File

@@ -78,7 +78,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var repeatCheckbox = panel.Get<CheckboxWidget>("REPEAT"); var repeatCheckbox = panel.Get<CheckboxWidget>("REPEAT");
repeatCheckbox.IsChecked = () => Game.Settings.Sound.Repeat; repeatCheckbox.IsChecked = () => Game.Settings.Sound.Repeat;
repeatCheckbox.OnClick = () => Game.Settings.Sound.Repeat ^= true; repeatCheckbox.OnClick = () => Game.Sound.SetMusicLooped(!Game.Settings.Sound.Repeat);
repeatCheckbox.IsDisabled = () => musicPlaylist.CurrentSongIsBackground; repeatCheckbox.IsDisabled = () => musicPlaylist.CurrentSongIsBackground;
panel.Get<LabelWidget>("TIME_LABEL").GetText = () => panel.Get<LabelWidget>("TIME_LABEL").GetText = () =>

View File

@@ -56,6 +56,7 @@ namespace OpenRA.Platforms.Default
public void StopSound(ISound sound) { } public void StopSound(ISound sound) { }
public void StopAllSounds() { } public void StopAllSounds() { }
public void SetListenerPosition(WPos position) { } public void SetListenerPosition(WPos position) { }
public void SetSoundLooping(bool looping, ISound sound) { }
public void Dispose() { } public void Dispose() { }
} }

View File

@@ -66,7 +66,7 @@ namespace OpenRA.Platforms.Default
if (devicesPtr == IntPtr.Zero || AL10.alGetError() != AL10.AL_NO_ERROR) if (devicesPtr == IntPtr.Zero || AL10.alGetError() != AL10.AL_NO_ERROR)
{ {
Log.Write("sound", "Failed to query OpenAL device list using {0}", label); Log.Write("sound", "Failed to query OpenAL device list using {0}", label);
return new string[0]; return Array.Empty<string>();
} }
var devices = new List<string>(); var devices = new List<string>();
@@ -103,7 +103,7 @@ namespace OpenRA.Platforms.Default
if (ALC11.alcIsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT")) if (ALC11.alcIsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT"))
return QueryDevices("ALC_ENUMERATION_EXT", ALC10.ALC_DEVICE_SPECIFIER); return QueryDevices("ALC_ENUMERATION_EXT", ALC10.ALC_DEVICE_SPECIFIER);
return new string[] { }; return Array.Empty<string>();
} }
internal static int MakeALFormat(int channels, int bits) internal static int MakeALFormat(int channels, int bits)
@@ -137,8 +137,7 @@ namespace OpenRA.Platforms.Default
for (var i = 0; i < PoolSize; i++) for (var i = 0; i < PoolSize; i++)
{ {
var source = 0U; AL10.alGenSources(1, out var source);
AL10.alGenSources(1, out source);
if (AL10.alGetError() != AL10.AL_NO_ERROR) if (AL10.alGetError() != AL10.AL_NO_ERROR)
{ {
Log.Write("sound", "Failed generating OpenAL source {0}", i); Log.Write("sound", "Failed generating OpenAL source {0}", i);
@@ -346,6 +345,11 @@ namespace OpenRA.Platforms.Default
AL10.alListenerf(EFX.AL_METERS_PER_UNIT, .01f); AL10.alListenerf(EFX.AL_METERS_PER_UNIT, .01f);
} }
public void SetSoundLooping(bool looping, ISound sound)
{
((OpenAlSound)sound)?.SetLooping(looping);
}
~OpenAlSoundEngine() ~OpenAlSoundEngine()
{ {
Dispose(false); Dispose(false);
@@ -518,6 +522,14 @@ namespace OpenRA.Platforms.Default
StopSource(); StopSource();
AL10.alSourcei(Source, AL10.AL_BUFFER, 0); AL10.alSourcei(Source, AL10.AL_BUFFER, 0);
} }
public void SetLooping(bool looping)
{
if (done)
return;
AL10.alSourcei(Source, AL10.AL_LOOPING, looping ? AL10.AL_TRUE : AL10.AL_FALSE);
}
} }
class OpenAlAsyncLoadSound : OpenAlSound class OpenAlAsyncLoadSound : OpenAlSound