Skip to content

Commit

Permalink
Greatly clean up audio code (YARC-Official#407)
Browse files Browse the repository at this point in the history
* Replace audio isSpeedup flag with a direct speed value
Gets rid of the depenency on PlayMode in the audio code

* Clean up song preview contexts
They don't need to be interfaced, they're already designed to work with any backend lol
Also fixed a couple warnings in SongSelection

* Add SetPosition method to IStemChannel

* Rework BassMoggStem
Heavily de-duplicated code and simplified things, and created an interface for it

* Account for channels that aren't part of a mixer when setting position

* Split out .mogg-specific mixing code into its own mixer

* Move audio code to a YARG.Audio namespace

* Remove unused using directives in audio code

* Fix BASS.FX and BASS.Mix versions not being logged correctly

* Accidentally broke song previews lol
  • Loading branch information
TheNathannator authored Jun 2, 2023
1 parent f0a4b16 commit 612c0e4
Show file tree
Hide file tree
Showing 31 changed files with 367 additions and 515 deletions.
2 changes: 1 addition & 1 deletion Assets/Script/Audio/AudioEnums.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace YARG {
namespace YARG.Audio {
public enum SongStem {
Master = -2,
Sfx = -1,
Expand Down
3 changes: 1 addition & 2 deletions Assets/Script/Audio/AudioHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace YARG {
namespace YARG.Audio {
public static class AudioHelpers {
public static readonly IList<string> SupportedStems = new[] {
"song",
Expand Down
81 changes: 54 additions & 27 deletions Assets/Script/Audio/Bass/BassAudioManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using ManagedBass;
using ManagedBass.Fx;
using ManagedBass.Mix;
using UnityEngine;
using XboxSTFS;
using YARG.Serialization;
using YARG.Song;
using Debug = UnityEngine.Debug;

namespace YARG {
namespace YARG.Audio.BASS {
public class BassAudioManager : MonoBehaviour, IAudioManager {
public bool UseStarpowerFx { get; set; }
public bool IsChipmunkSpeedup { get; set; }
Expand All @@ -31,14 +30,6 @@ public class BassAudioManager : MonoBehaviour, IAudioManager {
public float CurrentPositionF => (float) GetPosition();
public float AudioLengthF { get; private set; }

private IPreviewContext _currentPreviewContext;
public IPreviewContext PreviewContext {
get {
_currentPreviewContext ??= new BassPreviewContext(this);
return _currentPreviewContext;
}
}

private double[] _stemVolumes;

private int _opusHandle;
Expand Down Expand Up @@ -97,8 +88,8 @@ public void Initialize() {

Debug.Log($"BASS Successfully Initialized");
Debug.Log($"BASS: {Bass.Version}");
Debug.Log($"BASS.FX: {Bass.Version}");
Debug.Log($"BASS.Mix: {Bass.Version}");
Debug.Log($"BASS.FX: {BassFx.Version}");
Debug.Log($"BASS.Mix: {BassMix.Version}");

Debug.Log($"Update Period: {Bass.UpdatePeriod}");
Debug.Log($"Device Buffer Length: {Bass.DeviceBufferLength}");
Expand Down Expand Up @@ -163,7 +154,7 @@ public void LoadSfx() {
Debug.Log("Finished loading SFX");
}

public void LoadSong(ICollection<string> stems, bool isSpeedUp, params SongStem[] ignoreStems) {
public void LoadSong(ICollection<string> stems, float speed, params SongStem[] ignoreStems) {
Debug.Log("Loading song");
UnloadSong();

Expand All @@ -190,7 +181,7 @@ public void LoadSong(ICollection<string> stems, bool isSpeedUp, params SongStem[
}

var stemChannel = new BassStemChannel(this, stemPath, songStem);
if (stemChannel.Load(isSpeedUp, PlayMode.Play.speed) != 0) {
if (stemChannel.Load(speed) != 0) {
Debug.LogError($"Failed to load stem! {stemPath}");
Debug.LogError($"Bass Error: {Bass.LastError}");
continue;
Expand All @@ -216,17 +207,19 @@ public void LoadSong(ICollection<string> stems, bool isSpeedUp, params SongStem[
IsAudioLoaded = true;
}

public void LoadMogg(ExtractedConSongEntry exConSong, bool isSpeedUp, params SongStem[] ignoreStems) {
public void LoadMogg(ExtractedConSongEntry exConSong, float speed, params SongStem[] ignoreStems) {
Debug.Log("Loading mogg song");
UnloadSong();

// Process MOGG data
byte[] moggArray = exConSong.LoadMoggFile();

if (BitConverter.ToUInt32(moggArray, 0) != 0xA)
throw new Exception("Original unencrypted mogg replaced by an encrpyted mogg");

moggArray = moggArray[BitConverter.ToInt32(moggArray, 4)..];

// Initialize stream
int moggStreamHandle = Bass.CreateStream(moggArray, 0, moggArray.Length, BassFlags.Prescan | BassFlags.Decode | BassFlags.AsyncFile);
if (moggStreamHandle == 0) {
Debug.LogError($"Failed to load mogg file or position: {Bass.LastError}");
Expand All @@ -239,13 +232,52 @@ public void LoadMogg(ExtractedConSongEntry exConSong, bool isSpeedUp, params Son
exConSong.StemMaps.Remove(stem);
}

_mixer = new BassStemMixer(this, moggStreamHandle, exConSong.StemMaps, exConSong.MatrixRatios);
// Initialize mixer
_mixer = new BassMoggStemMixer(this, moggStreamHandle);
if (!_mixer.Create()) {
throw new Exception($"Failed to create mixer: {Bass.LastError}");
}

if (!_mixer.SetupMogg(isSpeedUp)) {
throw new Exception($"Failed to setup MOGG channels: {Bass.LastError}");
// Split stream into multiple channels
var stemMaps = exConSong.StemMaps;
var matrixRatios = exConSong.MatrixRatios;
var splitStreams = new int[matrixRatios.GetLength(0)];

var channelMap = new int[2];
channelMap[1] = -1;

for (var i = 0; i < splitStreams.Length; i++) {
channelMap[0] = i;

int splitHandle = BassMix.CreateSplitStream(moggStreamHandle, BassFlags.Decode | BassFlags.SplitPosition, channelMap);
if (splitHandle == 0) {
throw new Exception($"Failed to create MOGG stream handle: {Bass.LastError}");
}

splitStreams[i] = splitHandle;
}

// Set up channels
foreach ((var stem, int[] channelIndexes) in stemMaps) {
int[] channelStreams = channelIndexes.Select(i => splitStreams[i]).ToArray();

var matrixes = new List<float[]>();
foreach (var channelIndex in channelIndexes) {
var matrix = new float[2];
matrix[0] = matrixRatios[channelIndex, 0];
matrix[1] = matrixRatios[channelIndex, 1];
matrixes.Add(matrix);
}

var channel = new BassMoggStemChannel(this, stem, channelStreams, matrixes);
if (channel.Load(speed) < 0) {
throw new Exception($"Failed to load MOGG stem channel: {Bass.LastError}");
}

int code = _mixer.AddChannel(channel);
if (code != 0) {
throw new Exception($"Failed to add MOGG stem channel to mixer: {Bass.LastError}");
}
}

Debug.Log($"Loaded {_mixer.StemsLoaded} stems");
Expand All @@ -257,7 +289,7 @@ public void LoadMogg(ExtractedConSongEntry exConSong, bool isSpeedUp, params Son
IsAudioLoaded = true;
}

public void LoadCustomAudioFile(string audioPath) {
public void LoadCustomAudioFile(string audioPath, float speed) {
Debug.Log("Loading custom audio file");
UnloadSong();

Expand All @@ -267,7 +299,7 @@ public void LoadCustomAudioFile(string audioPath) {
}

var stemChannel = new BassStemChannel(this, audioPath, SongStem.Song);
if (stemChannel.Load(false, PlayMode.Play.speed) != 0) {
if (stemChannel.Load(speed) != 0) {
Debug.LogError($"Failed to load stem! {audioPath}");
Debug.LogError($"Bass Error: {Bass.LastError}");
return;
Expand Down Expand Up @@ -335,11 +367,6 @@ public void Pause() {
IsPlaying = _mixer.IsPlaying;
}

public void DisposePreviewContext() {
_currentPreviewContext?.Dispose();
_currentPreviewContext = null;
}

public void FadeIn(float maxVolume) {
Play(true);
if (IsPlaying) {
Expand Down
2 changes: 1 addition & 1 deletion Assets/Script/Audio/Bass/BassHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using ManagedBass.DirectX8;
using ManagedBass.Fx;

namespace YARG {
namespace YARG.Audio.BASS {
public static class BassHelpers {

public const float SONG_VOLUME_MULTIPLIER = 0.7f;
Expand Down
Loading

0 comments on commit 612c0e4

Please sign in to comment.