diff --git a/OmniConverter/Extensions/Audio/AudioEngine.cs b/OmniConverter/Extensions/Audio/AudioEngine.cs deleted file mode 100644 index 6a4a3d4..0000000 --- a/OmniConverter/Extensions/Audio/AudioEngine.cs +++ /dev/null @@ -1,37 +0,0 @@ -using CSCore; -using System; - -namespace OmniConverter -{ - public enum EngineID - { - Unknown = -1, - BASS = 0, - XSynth = 1, - FluidSynth = 2, - MAX = FluidSynth - } - - public abstract class AudioEngine : IDisposable - { - protected bool _disposed = false; - public bool Initialized { get; protected set; } = false; - public WaveFormat WaveFormat { get; protected set; } = new(48000, 32, 2); - public Settings CachedSettings { get; protected set; } - - public AudioEngine(WaveFormat waveFormat, Settings settings, bool defaultInit = true) - { - CachedSettings = settings; - WaveFormat = waveFormat; - Initialized = defaultInit; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected abstract void Dispose(bool disposing); - } -} diff --git a/OmniConverter/Extensions/Audio/MIDIRenderer.cs b/OmniConverter/Extensions/Audio/Renderers/AudioRenderer.cs similarity index 53% rename from OmniConverter/Extensions/Audio/MIDIRenderer.cs rename to OmniConverter/Extensions/Audio/Renderers/AudioRenderer.cs index f2a999b..d204168 100644 --- a/OmniConverter/Extensions/Audio/MIDIRenderer.cs +++ b/OmniConverter/Extensions/Audio/Renderers/AudioRenderer.cs @@ -1,5 +1,4 @@ using CSCore; -using ManagedBass.Fx; using System; namespace OmniConverter @@ -34,12 +33,48 @@ enum MIDIEventType Unknown4 = 0xFD }; - public abstract class MIDIRenderer : ISampleSource + public enum EngineID { - protected readonly object Lock = new object(); - protected long streamLength = 0; + Unknown = -1, + BASS = 0, + XSynth = 1, + FluidSynth = 2, + MAX = FluidSynth + } + + public abstract class AudioEngine : IDisposable + { + protected bool _disposed = false; + protected bool _init = false; + protected WaveFormat _waveFormat = new(48000, 32, 2); + protected Settings _cachedSettings; + + public AudioEngine(Settings settings, bool defaultInit = true) + { + _cachedSettings = settings; + _waveFormat = new(settings.Synth.SampleRate, 32, 2); + _init = defaultInit; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public Settings GetCachedSettings() => _cachedSettings; + public WaveFormat GetWaveFormat() => _waveFormat; + public bool IsInitialized() => _init; + + protected abstract void Dispose(bool disposing); + } + + public abstract class AudioRenderer : ISampleSource + { + protected Settings _cachedSettings; + protected readonly object _lock = new object(); + protected long _streamLength = 0; - protected double Volume { get; set; } public string UniqueID { get; protected set; } = IDGenerator.GetID(); public bool CanSeek { get; protected set; } = false; public WaveFormat WaveFormat { get; protected set; } = new(48000, 32, 2); @@ -48,7 +83,12 @@ public abstract class MIDIRenderer : ISampleSource public ulong ActiveVoices { get; protected set; } = 0; public float RenderingTime { get; protected set; } = 0.0f; - public MIDIRenderer(WaveFormat waveFormat, double volume, bool defaultInt = true) { WaveFormat = waveFormat; Volume = volume; Initialized = defaultInt; } + public AudioRenderer(AudioEngine audioEngine, bool defaultInt = true) + { + WaveFormat = audioEngine.GetWaveFormat(); + _cachedSettings = audioEngine.GetCachedSettings(); + Initialized = defaultInt; + } public abstract void SystemReset(); public abstract bool SendCustomFXEvents(int channel, short reverb, short chorus); @@ -56,10 +96,11 @@ public abstract class MIDIRenderer : ISampleSource public abstract unsafe int Read(float[] buffer, int offset, long delta, int count); public abstract void RefreshInfo(); public abstract void SendEndEvent(); - public virtual long Position { get { return streamLength; } set { } } - public virtual long Length { get { return streamLength; } } + public virtual long Position { get { return _streamLength; } set { } } + public virtual long Length { get { return _streamLength; } } public int Read(float[] buffer, int offset, int count) => Read(buffer, offset, 0, count); + public void Dispose() { Dispose(true); diff --git a/OmniConverter/Extensions/Audio/Renderers/BASSRenderer.cs b/OmniConverter/Extensions/Audio/Renderers/BASSRenderer.cs index 24bd70c..02fb8fc 100644 --- a/OmniConverter/Extensions/Audio/Renderers/BASSRenderer.cs +++ b/OmniConverter/Extensions/Audio/Renderers/BASSRenderer.cs @@ -16,7 +16,7 @@ public class BASSEngine : AudioEngine private int FlacPlug = 0; private MidiFontEx[]? _bassArray; - public BASSEngine(CSCore.WaveFormat waveFormat, Settings settings) : base(waveFormat, settings, false) + public BASSEngine(Settings settings) : base(settings, false) { /* -+++------. @@ -45,7 +45,7 @@ . .#+ -+- -++. */ - if (Bass.Init(Bass.NoSoundDevice, waveFormat.SampleRate, DeviceInitFlags.Default)) + if (Bass.Init(Bass.NoSoundDevice, _cachedSettings.WaveFormat.SampleRate, DeviceInitFlags.Default)) { _bassArray = InitializeSoundFonts(); @@ -55,17 +55,17 @@ . .#+ -+- if (tmp != 0) { // Subtract 1 because BASS uses -1 for no interpolation, 0 for linear and so on - var interp = ((int)CachedSettings.Synth.Interpolation) + var interp = ((int)_cachedSettings.Synth.Interpolation) .LimitToRange((int)GlobalSynthSettings.InterpolationType.None, (int)GlobalSynthSettings.InterpolationType.Max) - 1; - Bass.Configure(Configuration.MidiVoices, CachedSettings.Synth.MaxVoices); + Bass.Configure(Configuration.MidiVoices, _cachedSettings.Synth.MaxVoices); Bass.Configure(Configuration.SRCQuality, interp); Bass.Configure(Configuration.SampleSRCQuality, interp); Bass.StreamFree(tmp); - Initialized = true; + _init = true; if (FlacPlug == 0) Debug.PrintToConsole(Debug.LogType.Warning, "BASSFLAC failed to load, this could lead to incorrect opcode handling when using SFZ based SoundFonts using FLAC samples."); @@ -90,10 +90,10 @@ protected override void Dispose(bool disposing) if (FlacPlug != 0) Bass.PluginFree(FlacPlug); - if (Initialized) + if (_init) Bass.Free(); - Initialized = false; + _init = false; _disposed = true; } @@ -101,7 +101,7 @@ protected override void Dispose(bool disposing) { var _bassArray = new List(); - foreach (SoundFont sf in CachedSettings.SoundFontsList) + foreach (SoundFont sf in _cachedSettings.SoundFontsList) { if (!sf.Enabled) { @@ -187,7 +187,7 @@ private void FreeSoundFontsArray() public MidiFontEx[]? GetSoundFontsArray() => _bassArray; } - public class BASSRenderer : MIDIRenderer + public class BASSRenderer : AudioRenderer { private readonly BassFlags Flags; public int Handle { get; private set; } = 0; @@ -197,20 +197,23 @@ public class BASSRenderer : MIDIRenderer private VolumeFxParameters? VolParam = null; private MidiFontEx[]? SfArray = []; - public BASSRenderer(BASSEngine bass) : base(bass.WaveFormat, bass.CachedSettings.Synth.Volume, false) + public BASSRenderer(BASSEngine bass) : base(bass, false) { if (UniqueID == string.Empty) return; + if (bass == null) + return; + reference = bass; bool isFloat = WaveFormat.WaveFormatTag == AudioEncoding.IeeeFloat; Flags = BassFlags.Decode | BassFlags.MidiDecayEnd; Debug.PrintToConsole(Debug.LogType.Message, $"Stream unique ID: {UniqueID}"); - Flags |= (reference.CachedSettings.Synth.Interpolation > GlobalSynthSettings.InterpolationType.Linear) ? BassFlags.SincInterpolation : BassFlags.Default; - Flags |= reference.CachedSettings.BASS.DisableEffects ? BassFlags.MidiNoFx : BassFlags.Default; - Flags |= reference.CachedSettings.BASS.NoteOff1 ? BassFlags.MidiNoteOff1 : BassFlags.Default; + Flags |= (_cachedSettings.Synth.Interpolation > GlobalSynthSettings.InterpolationType.Linear) ? BassFlags.SincInterpolation : BassFlags.Default; + Flags |= _cachedSettings.Synth.DisableEffects ? BassFlags.MidiNoFx : BassFlags.Default; + Flags |= _cachedSettings.BASS.NoteOff1 ? BassFlags.MidiNoteOff1 : BassFlags.Default; Flags |= isFloat ? BassFlags.Float : BassFlags.Default; Handle = BassMidi.CreateStream(16, Flags, WaveFormat.SampleRate); @@ -223,7 +226,7 @@ public BASSRenderer(BASSEngine bass) : base(bass.WaveFormat, bass.CachedSettings if (IsError("Unable to set volume FX.")) return; - Bass.ChannelSetAttribute(Handle, ChannelAttribute.MidiKill, Convert.ToDouble(reference.CachedSettings.Synth.KilledNoteFading)); + Bass.ChannelSetAttribute(Handle, ChannelAttribute.MidiKill, Convert.ToDouble(_cachedSettings.Synth.KilledNoteFading)); SfArray = reference.GetSoundFontsArray(); if (SfArray != null) @@ -237,7 +240,7 @@ public BASSRenderer(BASSEngine bass) : base(bass.WaveFormat, bass.CachedSettings VolParam = new VolumeFxParameters(); VolParam.fCurrent = 1.0f; - VolParam.fTarget = (float)Volume; + VolParam.fTarget = (float)_cachedSettings.Synth.Volume; VolParam.fTime = 0.0f; VolParam.lCurve = 1; Bass.FXSetParameters(VolHandle, VolParam); @@ -260,7 +263,7 @@ public override unsafe int Read(float[] buffer, int offset, long delta, int coun { int ret = 0; - lock (Lock) + lock (_lock) { fixed (float* buff = buffer) { @@ -305,19 +308,10 @@ public override void SendEvent(byte[] data) switch ((MIDIEventType)(status & 0xF0)) { case MIDIEventType.NoteOn: - if (reference.CachedSettings.Event.FilterVelocity && param2 >= reference.CachedSettings.Event.VelocityLow && param2 <= reference.CachedSettings.Event.VelocityHigh) - return; - - if (reference.CachedSettings.Event.FilterKey && (param1 < reference.CachedSettings.Event.KeyLow || param1 > reference.CachedSettings.Event.KeyHigh)) - return; - eventParams = param2 << 8 | param1; break; case MIDIEventType.NoteOff: - if (reference.CachedSettings.Event.FilterKey && (param1 < reference.CachedSettings.Event.KeyLow || param1 > reference.CachedSettings.Event.KeyHigh)) - return; - eventParams = param1; break; @@ -388,7 +382,7 @@ protected override void Dispose(bool disposing) if (disposing) { - lock (Lock) + lock (_lock) Bass.StreamFree(Handle); } diff --git a/OmniConverter/Extensions/Audio/Renderers/FluidSynthRenderer.cs b/OmniConverter/Extensions/Audio/Renderers/FluidSynthRenderer.cs index 830a7bd..64070a2 100644 --- a/OmniConverter/Extensions/Audio/Renderers/FluidSynthRenderer.cs +++ b/OmniConverter/Extensions/Audio/Renderers/FluidSynthRenderer.cs @@ -10,11 +10,10 @@ namespace OmniConverter public class FluidSynthEngine : AudioEngine { private NFluidsynth.Settings _fluidSynthSettings; - private Settings _cachedSettings; public readonly object SFLock = new object(); - public unsafe FluidSynthEngine(CSCore.WaveFormat waveFormat, Settings settings) : base(waveFormat, settings, false) + public unsafe FluidSynthEngine(Settings settings) : base(settings, false) { Debug.PrintToConsole(Debug.LogType.Message, $"Preparing FluidSynth settings..."); @@ -30,7 +29,7 @@ public unsafe FluidSynthEngine(CSCore.WaveFormat waveFormat, Settings settings) _cachedSettings = settings; - Initialized = true; + _init = true; Debug.PrintToConsole(Debug.LogType.Message, $"FluidSynth settings prepared..."); @@ -42,7 +41,7 @@ protected override void Dispose(bool disposing) if (_disposed) return; - if (Initialized) + if (_init) { _fluidSynthSettings.Dispose(); } @@ -54,7 +53,7 @@ protected override void Dispose(bool disposing) public Settings GetConverterSettings() => _cachedSettings; } - public class FluidSynthRenderer : MIDIRenderer + public class FluidSynthRenderer : AudioRenderer { public Synth? handle { get; private set; } = null; private bool noMoreData = false; @@ -69,7 +68,7 @@ public class FluidSynthRenderer : MIDIRenderer private FluidSynthEngine reference; - public FluidSynthRenderer(FluidSynthEngine fluidsynth) : base(fluidsynth.WaveFormat, fluidsynth.CachedSettings.Synth.Volume, false) + public FluidSynthRenderer(FluidSynthEngine fluidsynth) : base(fluidsynth, false) { reference = fluidsynth; @@ -83,8 +82,31 @@ public FluidSynthRenderer(FluidSynthEngine fluidsynth) : base(fluidsynth.WaveFor handle = new(reference.GetFluidSynthSettings()); var tmp = reference.GetConverterSettings(); + var interp = FluidInterpolation.Linear; + + switch (tmp.Synth.Interpolation) + { + case GlobalSynthSettings.InterpolationType.None: + interp = FluidInterpolation.None; + break; + + case GlobalSynthSettings.InterpolationType.Point8: + case GlobalSynthSettings.InterpolationType.Point16: + interp = FluidInterpolation.FourthOrder; + break; + + case GlobalSynthSettings.InterpolationType.Point32: + case GlobalSynthSettings.InterpolationType.Point64: + interp = FluidInterpolation.SeventhOrder; + break; + + case GlobalSynthSettings.InterpolationType.Linear: + default: + break; + } handle.Gain = (float)tmp.Synth.Volume; + handle.SetInterpolationMethod(-1, interp); // FluidSynth "thread-safe API" moment lock (reference.SFLock) @@ -147,7 +169,7 @@ public override unsafe int Read(float[] buffer, int offset, long delta, int coun Array.Clear(bufOutL, 0, bufOutL.Length); Array.Clear(bufOutR, 0, bufOutR.Length); - lock (Lock) + lock (_lock) { fixed (float* buff = buffer) { @@ -163,7 +185,7 @@ public override unsafe int Read(float[] buffer, int offset, long delta, int coun } } - streamLength += count; + _streamLength += count; return count; } @@ -201,11 +223,6 @@ public override void SendEvent(byte[] data) switch ((MIDIEventType)(status & 0xF0)) { case MIDIEventType.NoteOn: - if (reference.CachedSettings.Event.FilterVelocity && param2 >= reference.CachedSettings.Event.VelocityLow && param2 <= reference.CachedSettings.Event.VelocityHigh) - return; - if (reference.CachedSettings.Event.FilterKey && (param1 < reference.CachedSettings.Event.KeyLow || param1 > reference.CachedSettings.Event.KeyHigh)) - return; - if (param1 == 0) { handle.NoteOff(chan, param1); @@ -214,9 +231,6 @@ public override void SendEvent(byte[] data) return; case MIDIEventType.NoteOff: - if (reference.CachedSettings.Event.FilterKey && (param1 < reference.CachedSettings.Event.KeyLow || param1 > reference.CachedSettings.Event.KeyHigh)) - return; - handle.NoteOff(chan, param1); return; diff --git a/OmniConverter/Extensions/Audio/Renderers/XSynthRenderer.cs b/OmniConverter/Extensions/Audio/Renderers/XSynthRenderer.cs index 9d28719..b3f5cc6 100644 --- a/OmniConverter/Extensions/Audio/Renderers/XSynthRenderer.cs +++ b/OmniConverter/Extensions/Audio/Renderers/XSynthRenderer.cs @@ -177,7 +177,7 @@ public class XSynthEngine : AudioEngine private StreamParams _streamParams; private GroupOptions _groupOptions; - public unsafe XSynthEngine(CSCore.WaveFormat waveFormat, Settings settings) : base(waveFormat, settings, false) + public unsafe XSynthEngine(Settings settings) : base(settings, false) { var libraryVersion = GetVersionInt(); if (libraryVersion >> 8 != APIVersion >> 8) @@ -188,30 +188,32 @@ public unsafe XSynthEngine(CSCore.WaveFormat waveFormat, Settings settings) : ba Debug.PrintToConsole(Debug.LogType.Message, $"Preparing XSynth..."); + var waveFormat = GetWaveFormat(); + _streamParams = GenDefault_StreamParams(); _groupOptions = GenDefault_GroupOptions(); - _streamParams.audio_channels = (ChannelCount)waveFormat.Channels; + _streamParams.audio_channels = (ChannelCount)_waveFormat.Channels; _streamParams.sample_rate = (uint)waveFormat.SampleRate; _groupOptions.stream_params = _streamParams; _groupOptions.channels = 16; - _groupOptions.fade_out_killing = !CachedSettings.Synth.KilledNoteFading; + _groupOptions.fade_out_killing = !_cachedSettings.Synth.KilledNoteFading; _groupOptions.parallelism = GenDefault_ParallelismOptions(); - switch (CachedSettings.XSynth.Threading) + switch (_cachedSettings.XSynth.Threading) { case XSynthSettings.ThreadingType.None: _groupOptions.parallelism.channel = -1; _groupOptions.parallelism.key = -1; break; case XSynthSettings.ThreadingType.PerChannel: - _groupOptions.parallelism.channel = CachedSettings.Render.ThreadsCount; + _groupOptions.parallelism.channel = _cachedSettings.Render.ThreadsCount; _groupOptions.parallelism.key = -1; break; case XSynthSettings.ThreadingType.PerKey: - _groupOptions.parallelism.channel = CachedSettings.Render.ThreadsCount; - _groupOptions.parallelism.key = CachedSettings.Render.ThreadsCount; + _groupOptions.parallelism.channel = _cachedSettings.Render.ThreadsCount; + _groupOptions.parallelism.key = _cachedSettings.Render.ThreadsCount; break; default: break; @@ -229,7 +231,7 @@ public unsafe XSynthEngine(CSCore.WaveFormat waveFormat, Settings settings) : ba _sfArray = Marshal.AllocHGlobal(tmp.Length * sizeof(XSynth_Soundfont)); MarshalExt.CopyToManaged(tmp, _sfArray, 0, tmp.Length); - Initialized = true; + _init = true; Debug.PrintToConsole(Debug.LogType.Message, $"XSynth set up for {_streamParams.audio_channels}ch output at {_streamParams.sample_rate}Hz "); Debug.PrintToConsole(Debug.LogType.Message, $"FadeOutKilling = {_groupOptions.fade_out_killing}"); @@ -243,14 +245,14 @@ protected override void Dispose(bool disposing) if (_disposed) return; - if (Initialized) + if (_init) { foreach (var group in _channelGroups) ChannelGroup_Drop(group); FreeSoundFontsArray(); - Initialized = false; + _init = false; } _disposed = true; @@ -258,7 +260,7 @@ protected override void Dispose(bool disposing) private XSynth_Soundfont[]? InitializeSoundFonts() { - foreach (SoundFont sf in CachedSettings.SoundFontsList) + foreach (SoundFont sf in _cachedSettings.SoundFontsList) { if (!sf.Enabled) { @@ -272,13 +274,13 @@ protected override void Dispose(bool disposing) _soundfontOptions.stream_params = _streamParams; _soundfontOptions.bank = sf.SourceBank; _soundfontOptions.preset = sf.SourcePreset; - if (CachedSettings.XSynth.LinearEnvelope) { + if (_cachedSettings.XSynth.LinearEnvelope) { // Linear in amplitude -> Exponential in dB (XSynth uses dB units) _soundfontOptions.vol_envelope_options.decay_curve = EnvelopeCurve.Exponential; _soundfontOptions.vol_envelope_options.release_curve = EnvelopeCurve.Exponential; } - _soundfontOptions.use_effects = CachedSettings.XSynth.UseEffects; - _soundfontOptions.interpolator = CachedSettings.Synth.Interpolation switch { + _soundfontOptions.use_effects = _cachedSettings.XSynth.UseEffects; + _soundfontOptions.interpolator = _cachedSettings.Synth.Interpolation switch { GlobalSynthSettings.InterpolationType.None => Interpolation.Nearest, _ => Interpolation.Linear, }; @@ -327,7 +329,7 @@ public nint GetSoundFontsArray(out ulong count) public GroupOptions GetGroupOptions() => _groupOptions; } - public class XSynthRenderer : MIDIRenderer + public class XSynthRenderer : AudioRenderer { public XSynth_ChannelGroup? handle { get; private set; } = null; private ulong sfCount = 0; @@ -336,7 +338,7 @@ public class XSynthRenderer : MIDIRenderer private GroupOptions groupOptions; private double dbVolume = 1.0; - public XSynthRenderer(XSynthEngine xsynth) : base(xsynth.WaveFormat, xsynth.CachedSettings.Synth.Volume, false) + public XSynthRenderer(XSynthEngine xsynth) : base(xsynth, false) { reference = xsynth; @@ -356,7 +358,7 @@ public XSynthRenderer(XSynthEngine xsynth) : base(xsynth.WaveFormat, xsynth.Cach handle = ChannelGroup_Create(groupOptions); reference.AddChannel((XSynth_ChannelGroup)handle); - ChannelGroup_SendConfigEventAll((XSynth_ChannelGroup)handle, ConfigEvent.SetLayers, (uint)reference.CachedSettings.XSynth.MaxLayers); + ChannelGroup_SendConfigEventAll((XSynth_ChannelGroup)handle, ConfigEvent.SetLayers, (uint)_cachedSettings.XSynth.MaxLayers); ChannelGroup_SetSoundfonts((XSynth_ChannelGroup)handle, sfArray, sfCount); var tmp = ChannelGroup_GetStreamParams((XSynth_ChannelGroup)handle); @@ -383,22 +385,22 @@ public override unsafe int Read(float[] buffer, int offset, long delta, int coun if (handle == null) return 0; - lock (Lock) + lock (_lock) { fixed (float* buff = buffer) { var offsetBuff = buff + offset; ChannelGroup_ReadSamples((XSynth_ChannelGroup)handle, (nint)offsetBuff, (ulong)count); - if (Volume < 1.0) + if (_cachedSettings.Synth.Volume < 1.0) { for (int i = 0; i < count; i++) - offsetBuff[i] = offsetBuff[i] * (float)Volume; + offsetBuff[i] = offsetBuff[i] * (float)_cachedSettings.Synth.Volume; } } } - streamLength += count; + _streamLength += count; return count; } @@ -433,11 +435,6 @@ public override void SendEvent(byte[] data) switch ((MIDIEventType)(status & 0xF0)) { case MIDIEventType.NoteOn: - if (reference.CachedSettings.Event.FilterVelocity && param2 >= reference.CachedSettings.Event.VelocityLow && param2 <= reference.CachedSettings.Event.VelocityHigh) - return; - if (reference.CachedSettings.Event.FilterKey && (param1 < reference.CachedSettings.Event.KeyLow || param1 > reference.CachedSettings.Event.KeyHigh)) - return; - if (param1 == 0) { eventType = AudioEvent.NoteOff; @@ -447,9 +444,6 @@ public override void SendEvent(byte[] data) break; case MIDIEventType.NoteOff: - if (reference.CachedSettings.Event.FilterKey && (param1 < reference.CachedSettings.Event.KeyLow || param1 > reference.CachedSettings.Event.KeyHigh)) - return; - eventType = AudioEvent.NoteOff; eventParams = param1; break; diff --git a/OmniConverter/Extensions/MIDI/MIDIConverter.cs b/OmniConverter/Extensions/MIDI/MIDIConverter.cs index c3b2ab5..f3c899e 100644 --- a/OmniConverter/Extensions/MIDI/MIDIConverter.cs +++ b/OmniConverter/Extensions/MIDI/MIDIConverter.cs @@ -265,7 +265,7 @@ private void ConversionFunc() if (_audioRenderer == null) throw new Exception("Invalid audio renderer!"); - if (_audioRenderer.Initialized) + if (_audioRenderer.IsInitialized()) { // Cache variables _autoDev = _audioRenderer is BASSEngine; @@ -371,7 +371,7 @@ private void PerMIDIConversion() { using (var msm = new MultiStreamMerger(_cachedSettings.WaveFormat)) { - using (var eventsProcesser = new EventsProcesser(_cachedSettings, _audioRenderer, evs, midi)) + using (var eventsProcesser = new EventsProcesser(_audioRenderer, evs, midi)) { AutoFillInfo(ConvStatus.SingleConv); @@ -588,7 +588,7 @@ private void PerTrackConversion() } else sampleWriter = msm.GetWriter(); - using (var eventsProcesser = new EventsProcesser(_cachedSettings, _audioRenderer, midiTrack, midi, track)) + using (var eventsProcesser = new EventsProcesser(_audioRenderer, midiTrack, midi, track)) { Dispatcher.UIThread.Post(() => trackPanel = new TaskStatus($"Track {track}", _panelRef, eventsProcesser)); @@ -797,8 +797,9 @@ private void PerTrackConversion() public class EventsProcesser : OmniTask { - MIDIRenderer? _midiRenderer = null; AudioEngine _audioRenderer; + AudioRenderer? _midiRenderer = null; + IEnumerable? _events = new List(); MidiFile _file; Settings _cachedSettings; @@ -829,7 +830,7 @@ public class EventsProcesser : OmniTask public bool IsRTS => rtsMode; public double Framerate => 1 / curFrametime; - public EventsProcesser(Settings cachedSettings, AudioEngine audioRenderer, IEnumerable events, MIDI? midi, int track = -1) + public EventsProcesser(AudioEngine audioRenderer, IEnumerable events, MIDI? midi, int track = -1) { if (midi == null) throw new NullReferenceException("MIDI is null"); @@ -841,7 +842,7 @@ public EventsProcesser(Settings cachedSettings, AudioEngine audioRenderer, IEnum _audioRenderer = audioRenderer; _events = events; _eventsCount = track < 0 ? midi.TotalEventCount : midi.EventCounts[track]; - _cachedSettings = cachedSettings; + _cachedSettings = _audioRenderer.GetCachedSettings(); _length = midi.Length.TotalSeconds; } @@ -947,19 +948,32 @@ public void Process(ISampleWriter output, WaveFormat waveFormat, CancellationTok switch (e) { case ControlChangeEvent ev: - if (_audioRenderer.CachedSettings.Event.OverrideEffects && (ev.Controller == 0x5B || ev.Controller == 0x5D)) + if (_cachedSettings.Event.OverrideEffects && (ev.Controller == 0x5B || ev.Controller == 0x5D)) break; goto default; case ProgramChangeEvent: - if (!_audioRenderer.CachedSettings.Event.IgnoreProgramChanges) + if (!_cachedSettings.Event.IgnoreProgramChanges) goto default; break; - case NoteOnEvent: + case NoteOnEvent non: playedNotes++; + + if (_cachedSettings.Event.FilterVelocity && eb[2] >= _cachedSettings.Event.VelocityLow && eb[2] <= _cachedSettings.Event.VelocityHigh) + break; + + if (_cachedSettings.Event.FilterKey && (eb[1] < _cachedSettings.Event.KeyLow || eb[1] > _cachedSettings.Event.KeyHigh)) + break; + + goto default; + + case NoteOffEvent noff: + if (_cachedSettings.Event.FilterKey && (eb[1] < _cachedSettings.Event.KeyLow || eb[1] > _cachedSettings.Event.KeyHigh)) + return; + goto default; case MIDIPortEvent: diff --git a/OmniConverter/Extensions/Settings.cs b/OmniConverter/Extensions/Settings.cs index 917908a..72271ef 100644 --- a/OmniConverter/Extensions/Settings.cs +++ b/OmniConverter/Extensions/Settings.cs @@ -20,10 +20,10 @@ public enum InterpolationType } [JsonProperty] - public int MaxVoices = 2048; + public double Volume = 1.0; [JsonProperty] - public double Volume = 1.0; + public int MaxVoices = 2048; [JsonProperty] public int SampleRate = 48000; @@ -34,6 +34,9 @@ public enum InterpolationType [JsonProperty] public bool KilledNoteFading = false; + [JsonProperty] + public bool DisableEffects = true; + [JsonProperty] public bool AudioLimiter = false; @@ -55,9 +58,6 @@ public object Clone() [JsonObject] public class BASSSettings : ICloneable { - [JsonProperty] - public bool DisableEffects = true; - [JsonProperty] public bool NoteOff1 = false; @@ -262,15 +262,15 @@ public class Settings : ICloneable switch (Renderer) { case EngineID.XSynth: - _cachedEngine = new XSynthEngine(_waveFormat, this); + _cachedEngine = new XSynthEngine(this); break; case EngineID.FluidSynth: - _cachedEngine = new FluidSynthEngine(_waveFormat, this); + _cachedEngine = new FluidSynthEngine(this); break; case EngineID.BASS: - _cachedEngine = new BASSEngine(_waveFormat, this); + _cachedEngine = new BASSEngine(this); break; default: @@ -280,7 +280,7 @@ public class Settings : ICloneable return _cachedEngine; } - public MIDIRenderer? GetRenderer() + public AudioRenderer? GetRenderer() { switch (_cachedEngine) { diff --git a/OmniConverter/Forms/SettingsWindow.axaml.cs b/OmniConverter/Forms/SettingsWindow.axaml.cs index fcf357b..215f91c 100644 --- a/OmniConverter/Forms/SettingsWindow.axaml.cs +++ b/OmniConverter/Forms/SettingsWindow.axaml.cs @@ -64,7 +64,7 @@ private void CheckSettings(object? sender, RoutedEventArgs e) BASS_MaxVoices.Value = Program.Settings.Synth.MaxVoices; XSynth_MaxLayers.Value = Program.Settings.XSynth.MaxLayers; - BASS_DisableFX.IsChecked = Program.Settings.BASS.DisableEffects; + BASS_DisableFX.IsChecked = Program.Settings.Synth.DisableEffects; BASS_NoteOff1.IsChecked = Program.Settings.BASS.NoteOff1; XSynth_UseEffects.IsChecked = Program.Settings.XSynth.UseEffects; XSynth_LinearEnv.IsChecked = Program.Settings.XSynth.LinearEnvelope; @@ -339,7 +339,7 @@ private void ApplySettings(object? sender, RoutedEventArgs e) Program.Settings.Encoder.AudioBitrate = (int)AudioBitrate.Value; if (BASS_DisableFX.IsChecked != null) - Program.Settings.BASS.DisableEffects = (bool)BASS_DisableFX.IsChecked; + Program.Settings.Synth.DisableEffects = (bool)BASS_DisableFX.IsChecked; if (BASS_NoteOff1.IsChecked != null) Program.Settings.BASS.NoteOff1 = (bool)BASS_NoteOff1.IsChecked;