From b8b8c859098ee80fe7089c3f5ecb1dc32e87bac2 Mon Sep 17 00:00:00 2001 From: Cam Sinclair Date: Sat, 16 Nov 2024 22:31:32 +1000 Subject: [PATCH] Target SerdesNet 3.0.1, use file-scoped namespaces --- ADLMidi.NET.sln | 2 +- TestApp/Program.cs | 355 ++++---- TestApp/TestApp.csproj | 4 +- src/ADLMidi.NET.csproj | 23 +- src/AdlMidi.cs | 39 +- src/AdlMidiImports.cs | 1661 ++++++++++++++++++------------------ src/AudioFormat.cs | 23 +- src/Bank.cs | 81 +- src/BankAccessFlags.cs | 19 +- src/BankId.cs | 23 +- src/Emulator.cs | 27 +- src/GlobalBankFlags.cs | 13 +- src/GlobalTimbreLibrary.cs | 125 ++- src/Instrument.cs | 47 +- src/InstrumentFlags.cs | 17 +- src/MarkerEntry.cs | 23 +- src/MidiPlayer.cs | 244 +++--- src/Modulation.cs | 33 +- src/Operator.cs | 69 +- src/OperatorFlags.cs | 49 +- src/RhythmMode.cs | 27 +- src/SampleType.cs | 37 +- src/TimbreData.cs | 47 +- src/TrackOptions.cs | 21 +- src/VolumeModel.cs | 29 +- src/Waveform.cs | 23 +- src/WoplBank.cs | 33 +- src/WoplFile.cs | 169 ++-- src/WoplInstrument.cs | 121 ++- 29 files changed, 1680 insertions(+), 1704 deletions(-) diff --git a/ADLMidi.NET.sln b/ADLMidi.NET.sln index 59467ee..c15a917 100644 --- a/ADLMidi.NET.sln +++ b/ADLMidi.NET.sln @@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ADLMidi.NET", "src\ADLMidi. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp", "TestApp\TestApp.csproj", "{C39D3663-C688-489F-A46C-06B4BFF53673}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SerdesNet", "..\SerdesNet\src\SerdesNet.csproj", "{DC43FE5A-8DBA-4F72-9AAB-34DE1D512DB0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SerdesNet", "..\SerdesNet\src\SerdesNet\SerdesNet.csproj", "{DC43FE5A-8DBA-4F72-9AAB-34DE1D512DB0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/TestApp/Program.cs b/TestApp/Program.cs index bd833ac..38db90f 100644 --- a/TestApp/Program.cs +++ b/TestApp/Program.cs @@ -5,187 +5,187 @@ using ADLMidi.NET; using SerdesNet; -namespace TestApp +namespace TestApp; + +class Program { - class Program - { - const int SampleRate = 44100; - const string newWoplPath = @"C:\Depot\bb\ualbion\albion\DRIVERS\ALBISND_NEW.wopl"; - static readonly StringBuilder NoteWriter = new(); - static double Time = 0; + const int SampleRate = 44100; + const string NewWoplPath = @"C:\Depot\bb\ualbion\albion\DRIVERS\ALBISND_NEW.wopl"; + static readonly StringBuilder NoteWriter = new(); + static double Time = 0; - static void Main() + static void Main() + { + // WoplFile realWopl = ReadWopl(@"C:\Depot\bb\ualbion\albion\DRIVERS\ALBISND.wopl"); + // WriteWopl(realWopl, @"C:\Depot\bb\ualbion\albion\DRIVERS\ALBISND_ROUNDTRIP.wopl"); + + GlobalTimbreLibrary oplFile = ReadOpl(@"C:\Depot\bb\ualbion\albion\DRIVERS\ALBISND.OPL"); + WoplFile wopl = OplToWopl(oplFile); + WriteWopl(wopl, NewWoplPath); + + byte[] bankData = File.ReadAllBytes(NewWoplPath); + for (int i = 0; i <= 45; i++) { - // WoplFile realWopl = ReadWopl(@"C:\Depot\bb\ualbion\albion\DRIVERS\ALBISND.wopl"); - // WriteWopl(realWopl, @"C:\Depot\bb\ualbion\albion\DRIVERS\ALBISND_ROUNDTRIP.wopl"); - - GlobalTimbreLibrary oplFile = ReadOpl(@"C:\Depot\bb\ualbion\albion\DRIVERS\ALBISND.OPL"); - WoplFile wopl = OplToWopl(oplFile); - WriteWopl(wopl, newWoplPath); - - byte[] bankData = File.ReadAllBytes(newWoplPath); - for (int i = 0; i <= 45; i++) - { - Console.WriteLine($"Dumping {i}"); - ExportAlbionSong(i, bankData); - ExportSongEvents(i, bankData); - } - - File.WriteAllText(@"C:\Depot\bb\ualbion\re\SongsPlayed.txt", NoteWriter.ToString()); + Console.WriteLine($"Dumping {i}"); + ExportAlbionSong(i, bankData); + ExportSongEvents(i, bankData); } - static void ExportAlbionSong(int songId, byte[] bankData) + File.WriteAllText(@"C:\Depot\bb\ualbion\re\SongsPlayed.txt", NoteWriter.ToString()); + } + + static void ExportAlbionSong(int songId, byte[] bankData) + { + string path = $@"C:\Depot\bb\ualbion\Data\Exported\SONGS{songId/100}.XLD\{songId%100:D2}.xmi"; + if (!File.Exists(path)) + return; + + using var outputFile = new WavFile( + $@"C:\Depot\bb\ualbion\re\Songs{songId/100}_{songId%100:D2}.wav", + SampleRate, 2, 2); + + using var player = AdlMidi.Init(); + + NoteWriter.AppendLine($"Song {songId}"); + player.SetNoteHook(NoteHook, IntPtr.Zero); + player.OpenBankData(bankData); + player.OpenFile(path); + player.SetLoopEnabled(false); + short[] bufferArray = new short[4096]; + long totalSamples = 0; + for(;;) { - string path = $@"C:\Depot\bb\ualbion\Data\Exported\SONGS{songId/100}.XLD\{songId%100:D2}.xmi"; - if (!File.Exists(path)) - return; - - using var outputFile = new WavFile( - $@"C:\Depot\bb\ualbion\re\Songs{songId/100}_{songId%100:D2}.wav", - SampleRate, 2, 2); - - using var player = AdlMidi.Init(); - - NoteWriter.AppendLine($"Song {songId}"); - player.SetNoteHook(NoteHook, IntPtr.Zero); - player.OpenBankData(bankData); - player.OpenFile(path); - player.SetLoopEnabled(false); - short[] bufferArray = new short[4096]; - long totalSamples = 0; - for(;;) - { - Time = (double)totalSamples / (2 * SampleRate); - int samplesWritten = player.Play(bufferArray); - totalSamples += samplesWritten; - - if (samplesWritten <= 0) - break; - - var byteSpan = MemoryMarshal.Cast(new ReadOnlySpan(bufferArray, 0, samplesWritten)); - outputFile.Write(byteSpan); - } - NoteWriter.AppendLine(); + Time = (double)totalSamples / (2 * SampleRate); + int samplesWritten = player.Play(bufferArray); + totalSamples += samplesWritten; + + if (samplesWritten <= 0) + break; + + var byteSpan = MemoryMarshal.Cast(new ReadOnlySpan(bufferArray, 0, samplesWritten)); + outputFile.Write(byteSpan); } + NoteWriter.AppendLine(); + } + + public static void ExportSongEvents(int songId, byte[] bankData) + { + string path = $@"C:\Depot\bb\ualbion\Data\Exported\SONGS{songId/100}.XLD\{songId%100:D2}.xmi"; + if (!File.Exists(path)) + return; + + using var player = AdlMidi.Init(); + + NoteWriter.AppendLine($"Song {songId}"); + player.OpenBankData(bankData); + player.SetNoteHook(NoteHook, IntPtr.Zero); + player.OpenFile(path); + player.SetLoopEnabled(false); + double nextTime = 0; + Time = 0; + const double minTick = 1.0; + while (player.AtEnd() == 0) + { + Time += nextTime; + nextTime = player.TickEvents(nextTime, minTick); + } + + NoteWriter.AppendLine(); + } + + static void NoteHook(IntPtr userdata, int adlchannel, int note, int ins, int pressure, double bend) + { + NoteWriter.AppendLine($" {Time}: Chan{adlchannel} Note{note} Instrument{ins} Pressure{pressure} Bend{bend}"); + } + + static WoplFile OplToWopl(GlobalTimbreLibrary oplFile) + { + var wopl = new WoplFile + { + Version = 3, + GlobalFlags = GlobalBankFlags.DeepTremolo | GlobalBankFlags.DeepVibrato, + VolumeModel = VolumeModel.Auto + }; + + wopl.Melodic.Add(new WoplBank { Id = 0, Name = "" }); + wopl.Percussion.Add(new WoplBank { Id = 0, Name = "" }); - public static void ExportSongEvents(int songId, byte[] bankData) + for(int i = 0; i < oplFile.Data.Count; i++) { - string path = $@"C:\Depot\bb\ualbion\Data\Exported\SONGS{songId/100}.XLD\{songId%100:D2}.xmi"; - if (!File.Exists(path)) - return; - - using var player = AdlMidi.Init(); - - NoteWriter.AppendLine($"Song {songId}"); - player.OpenBankData(bankData); - player.SetNoteHook(NoteHook, IntPtr.Zero); - player.OpenFile(path); - player.SetLoopEnabled(false); - double nextTime = 0; - Time = 0; - const double minTick = 1.0; - while (player.AtEnd() == 0) - { - Time += nextTime; - nextTime = player.TickEvents(nextTime, minTick); - } - - NoteWriter.AppendLine(); + var timbre = oplFile.Data[i]; + WoplInstrument x = + i < 128 + ? wopl.Melodic[0].Instruments[i] ?? new WoplInstrument() + : wopl.Percussion[0].Instruments[i - 128 + 35] ?? new WoplInstrument(); + + x.Name = ""; + x.NoteOffset1 = timbre.MidiPatchNumber; + x.NoteOffset2 = timbre.MidiBankNumber; + x.InstrumentMode = InstrumentMode.TwoOperator; + x.FbConn1C0 = timbre.FeedbackConnection; + x.Operator0 = timbre.Carrier; + x.Operator1 = timbre.Modulation; + x.Operator2 = Operator.Blank; + x.Operator3 = Operator.Blank; + + if (i < 128) + wopl.Melodic[0].Instruments[i] = x; + else + wopl.Percussion[0].Instruments[i - 128 + 35] = x; } - static void NoteHook(IntPtr userdata, int adlchannel, int note, int ins, int pressure, double bend) + return wopl; + } + + public sealed class WavFile : IDisposable + { + readonly FileStream _stream; + readonly BinaryWriter _bw; + readonly long _riffSizeOffset; + readonly long _dataSizeOffset; + uint _dataSize; + + public WavFile(string filename, uint sampleRate, ushort numChannels, ushort bytesPerSample) { - NoteWriter.AppendLine($" {Time}: Chan{adlchannel} Note{note} Instrument{ins} Pressure{pressure} Bend{bend}"); + _stream = File.Open(filename, FileMode.Create); + _bw = new BinaryWriter(_stream); + _bw.Write(Encoding.ASCII.GetBytes("RIFF")); // Container format chunk + _riffSizeOffset = _stream.Position; + _bw.Write(0); // Dummy write to start with, will be overwritten at the end. + + _bw.Write(Encoding.ASCII.GetBytes("WAVEfmt ")); // Subchunk1 (format metadata) + _bw.Write(16); + _bw.Write((ushort)1); // Format = Linear Quantisation + _bw.Write(numChannels); // NumChannels + _bw.Write(sampleRate); // SampleRate + _bw.Write(sampleRate * numChannels * bytesPerSample); // ByteRate + _bw.Write((ushort)(numChannels * bytesPerSample)); // BlockAlign + _bw.Write((ushort)(bytesPerSample * 8)); // BitsPerSample + + _bw.Write(Encoding.ASCII.GetBytes("data")); // Subchunk2 (raw sample data) + _dataSizeOffset = _stream.Position; + _bw.Write(0); // Dummy write, will be overwritten at the end } - static WoplFile OplToWopl(GlobalTimbreLibrary oplFile) + public void Write(ReadOnlySpan buffer) { - var wopl = new WoplFile - { - Version = 3, - GlobalFlags = GlobalBankFlags.DeepTremolo | GlobalBankFlags.DeepVibrato, - VolumeModel = VolumeModel.Auto - }; - - wopl.Melodic.Add(new WoplBank { Id = 0, Name = "" }); - wopl.Percussion.Add(new WoplBank { Id = 0, Name = "" }); - - for(int i = 0; i < oplFile.Data.Count; i++) - { - var timbre = oplFile.Data[i]; - WoplInstrument x = - i < 128 - ? wopl.Melodic[0].Instruments[i] ?? new WoplInstrument() - : wopl.Percussion[0].Instruments[i - 128 + 35] ?? new WoplInstrument(); - - x.Name = ""; - x.NoteOffset1 = timbre.MidiPatchNumber; - x.NoteOffset2 = timbre.MidiBankNumber; - x.InstrumentMode = InstrumentMode.TwoOperator; - x.FbConn1C0 = timbre.FeedbackConnection; - x.Operator0 = timbre.Carrier; - x.Operator1 = timbre.Modulation; - x.Operator2 = Operator.Blank; - x.Operator3 = Operator.Blank; - - if (i < 128) - wopl.Melodic[0].Instruments[i] = x; - else - wopl.Percussion[0].Instruments[i - 128 + 35] = x; - } - - return wopl; + _bw.Write(buffer); + _dataSize += (uint)buffer.Length; } - public sealed class WavFile : IDisposable + public void Dispose() { - readonly FileStream _stream; - readonly BinaryWriter _bw; - readonly long _riffSizeOffset; - readonly long _dataSizeOffset; - uint _dataSize; - - public WavFile(string filename, uint sampleRate, ushort numChannels, ushort bytesPerSample) - { - _stream = File.Open(filename, FileMode.Create); - _bw = new BinaryWriter(_stream); - _bw.Write(Encoding.ASCII.GetBytes("RIFF")); // Container format chunk - _riffSizeOffset = _stream.Position; - _bw.Write(0); // Dummy write to start with, will be overwritten at the end. - - _bw.Write(Encoding.ASCII.GetBytes("WAVEfmt ")); // Subchunk1 (format metadata) - _bw.Write(16); - _bw.Write((ushort)1); // Format = Linear Quantisation - _bw.Write(numChannels); // NumChannels - _bw.Write(sampleRate); // SampleRate - _bw.Write(sampleRate * numChannels * bytesPerSample); // ByteRate - _bw.Write((ushort)(numChannels * bytesPerSample)); // BlockAlign - _bw.Write((ushort)(bytesPerSample * 8)); // BitsPerSample - - _bw.Write(Encoding.ASCII.GetBytes("data")); // Subchunk2 (raw sample data) - _dataSizeOffset = _stream.Position; - _bw.Write(0); // Dummy write, will be overwritten at the end - } - - public void Write(ReadOnlySpan buffer) - { - _bw.Write(buffer); - _dataSize += (uint)buffer.Length; - } - - public void Dispose() - { - var totalLength = _stream.Position; // Write actual length to container format chunk - _stream.Position = _riffSizeOffset; - _bw.Write((uint)(totalLength - 8)); - - _stream.Position = _dataSizeOffset; - _bw.Write(_dataSize); - - _bw.Dispose(); - _stream.Dispose(); - } + var totalLength = _stream.Position; // Write actual length to container format chunk + _stream.Position = _riffSizeOffset; + _bw.Write((uint)(totalLength - 8)); + + _stream.Position = _dataSizeOffset; + _bw.Write(_dataSize); + + _bw.Dispose(); + _stream.Dispose(); } + } /* static WoplFile ReadWopl(string filename) { @@ -195,21 +195,20 @@ static WoplFile ReadWopl(string filename) } */ - static void WriteWopl(WoplFile wopl, string filename) - { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - WoplFile.Serdes(wopl, new GenericBinaryWriter(bw, Encoding.ASCII.GetBytes, Console.WriteLine)); - byte[] bytes = ms.ToArray(); - File.WriteAllBytes(filename, bytes); - } + static void WriteWopl(WoplFile wopl, string filename) + { + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + WoplFile.Serdes(wopl, new WriterSerdes(bw, Encoding.ASCII.GetBytes, Console.WriteLine)); + byte[] bytes = ms.ToArray(); + File.WriteAllBytes(filename, bytes); + } - static GlobalTimbreLibrary ReadOpl(string filename) - { - using var stream = File.OpenRead(filename); - using var br = new BinaryReader(stream); - return GlobalTimbreLibrary.Serdes(null, - new GenericBinaryReader(br, br.BaseStream.Length, Encoding.ASCII.GetString, Console.WriteLine)); - } + static GlobalTimbreLibrary ReadOpl(string filename) + { + using var stream = File.OpenRead(filename); + using var br = new BinaryReader(stream); + return GlobalTimbreLibrary.Serdes(null, + new ReaderSerdes(br, br.BaseStream.Length, Encoding.ASCII.GetString, Console.WriteLine)); } -} +} \ No newline at end of file diff --git a/TestApp/TestApp.csproj b/TestApp/TestApp.csproj index e683ac8..a0d2e06 100644 --- a/TestApp/TestApp.csproj +++ b/TestApp/TestApp.csproj @@ -11,9 +11,9 @@ - + - + diff --git a/src/ADLMidi.NET.csproj b/src/ADLMidi.NET.csproj index 95e54d3..f94cf22 100644 --- a/src/ADLMidi.NET.csproj +++ b/src/ADLMidi.NET.csproj @@ -2,19 +2,26 @@ netstandard2.0 + 10 true + Cam Sinclair A .NET wrapper for the libADLMIDI library, a free Software MIDI synthesizer library with OPL3 emulation 2020 Cam Sinclair + + true ADLMidi.NET LGPL-2.1-or-later MIDI OPL3 ADLMIDI - https://github.com/CSinkers/AdlMidi.NET - latest - Git - https://github.com/CSinkers/AdlMidi.NET - true - 1.0.18 + https://github.com/csinkers/AdlMidi.NET + + git + https://github.com/csinkers/AdlMidi.NET + + True + true + Embedded + 1.0.19 @@ -22,10 +29,10 @@ - + - + diff --git a/src/AdlMidi.cs b/src/AdlMidi.cs index 36529e0..45140b6 100644 --- a/src/AdlMidi.cs +++ b/src/AdlMidi.cs @@ -1,28 +1,27 @@ using System; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +public static class AdlMidi { - public static class AdlMidi - { - public const int DefaultChipSampleRate = 49716; - public static int GetBankCount() => AdlMidiImports.adl_getBanksCount(); - public static string[] GetBankNames() => AdlMidiImports.adl_getBankNames(); - public static string LinkedLibraryVersion() => AdlMidiImports.adl_linkedLibraryVersion(); + public const int DefaultChipSampleRate = 49716; + public static int GetBankCount() => AdlMidiImports.adl_getBanksCount(); + public static string[] GetBankNames() => AdlMidiImports.adl_getBankNames(); + public static string LinkedLibraryVersion() => AdlMidiImports.adl_linkedLibraryVersion(); - public static Version LinkedVersion() - { - var version = AdlMidiImports.adl_linkedVersion(); - return new Version(version.Major, version.Minor, version.Patch); - } + public static Version LinkedVersion() + { + var version = AdlMidiImports.adl_linkedVersion(); + return new Version(version.Major, version.Minor, version.Patch); + } - public static string ErrorString() => AdlMidiImports.adl_errorString(); - public static MidiPlayer Init(long sampleRate = DefaultChipSampleRate) - { - var midiPlayer = AdlMidiImports.adl_init(sampleRate); - if (midiPlayer == IntPtr.Zero) - throw new InvalidOperationException(ErrorString()); + public static string ErrorString() => AdlMidiImports.adl_errorString(); + public static MidiPlayer Init(long sampleRate = DefaultChipSampleRate) + { + var midiPlayer = AdlMidiImports.adl_init(sampleRate); + if (midiPlayer == IntPtr.Zero) + throw new InvalidOperationException(ErrorString()); - return new MidiPlayer(midiPlayer); - } + return new MidiPlayer(midiPlayer); } } \ No newline at end of file diff --git a/src/AdlMidiImports.cs b/src/AdlMidiImports.cs index 6a37de0..e4dd380 100644 --- a/src/AdlMidiImports.cs +++ b/src/AdlMidiImports.cs @@ -25,911 +25,909 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -#pragma warning disable CS0626 // Method, operator, or accessor is marked external and has no attributes on it -#pragma warning disable IDE1006 // Naming Styles -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// Raw event callback +/// Pointer to user data (usually, context of something) +/// MIDI event type +/// MIDI event subtype (special events only) +/// MIDI channel +/// Raw event data +/// Length of event data +/// +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public delegate void RawEventHook(IntPtr userData, byte type, byte subType, byte channel, IntPtr data, UIntPtr length); + +/// +/// Note on/off callback +/// Pointer to user data (usually, context of something) +/// Chip channel where note was played +/// Note number [between 0 and 127] +/// Velocity level, or -1 when it's note off event +/// Pitch bend offset value +/// +public delegate void NoteHook(IntPtr userData, int adlChannel, int note, int ins, int pressure, double bend); + +static class AdlMidiImports { + const string LibraryName = "libadlmidi"; + + public static readonly Version AdlMidiVersion = new(1, 4, 1); + /// - /// Raw event callback - /// Pointer to user data (usually, context of something) - /// MIDI event type - /// MIDI event sub-type (special events only) - /// MIDI channel - /// Raw event data - /// Length of event data + /// Sets number of emulated chips (from 1 to 100). Emulation of multiple chips extends polyphony limits + /// Instance of the library + /// Count of virtual chips to emulate + /// 0 on success, <0 when any error has occurred /// - [SuppressMessage("ReSharper", "UnusedMember.Global")] - public delegate void RawEventHook(IntPtr userData, byte type, byte subType, byte channel, IntPtr data, UIntPtr length); + [DllImport(LibraryName)] + public static extern int adl_setNumChips(IntPtr device, int numChips); /// - /// Note on/off callback - /// Pointer to user data (usually, context of something) - /// Chip channel where note was played - /// Note number [between 0 and 127] - /// Velocity level, or -1 when it's note off event - /// Pitch bend offset value + /// Get current number of emulated chips + /// Instance of the library + /// Count of working chip emulators /// - public delegate void NoteHook(IntPtr userData, int adlChannel, int note, int ins, int pressure, double bend); - - static class AdlMidiImports - { - const string LibraryName = "libadlmidi"; - - public static readonly Version AdlMidiVersion = new(1, 4, 1); - - /// - /// Sets number of emulated chips (from 1 to 100). Emulation of multiple chips extends polyphony limits - /// Instance of the library - /// Count of virtual chips to emulate - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_setNumChips(IntPtr device, int numChips); - - /// - /// Get current number of emulated chips - /// Instance of the library - /// Count of working chip emulators - /// - [DllImport(LibraryName)] - public static extern int adl_getNumChips(IntPtr device); + [DllImport(LibraryName)] + public static extern int adl_getNumChips(IntPtr device); - /// - /// Get obtained number of emulated chips - /// Instance of the library - /// Count of working chip emulators - /// - [DllImport(LibraryName)] - public static extern int adl_getNumChipsObtained(IntPtr device); + /// + /// Get obtained number of emulated chips + /// Instance of the library + /// Count of working chip emulators + /// + [DllImport(LibraryName)] + public static extern int adl_getNumChipsObtained(IntPtr device); - /// - /// Sets a number of the patches bank from 0 to N banks. - /// - /// Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. - /// - /// Instance of the library - /// Number of embedded bank - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_setBank(IntPtr device, int bank); + /// + /// Sets a number of the patches bank from 0 to N banks. + /// + /// Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. + /// + /// Instance of the library + /// Number of embedded bank + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_setBank(IntPtr device, int bank); - /// - /// Returns total number of available banks - /// Total number of available embedded banks - /// - [DllImport(LibraryName)] - public static extern int adl_getBanksCount(); + /// + /// Returns total number of available banks + /// Total number of available embedded banks + /// + [DllImport(LibraryName)] + public static extern int adl_getBanksCount(); - /// - /// Returns pointer to array of names of every bank - /// Array of strings containing the name of every embedded bank - /// - [DllImport(LibraryName)] - public static extern string[] adl_getBankNames(); + /// + /// Returns pointer to array of names of every bank + /// Array of strings containing the name of every embedded bank + /// + [DllImport(LibraryName)] + public static extern string[] adl_getBankNames(); - /// - /// Reference to dynamic bank - /// - [StructLayout(LayoutKind.Sequential)] - public struct Bank - { - public IntPtr Pointer0; - public IntPtr Pointer1; - public IntPtr Pointer2; - } + /// + /// Reference to dynamic bank + /// + [StructLayout(LayoutKind.Sequential)] + public struct Bank + { + public IntPtr Pointer0; + public IntPtr Pointer1; + public IntPtr Pointer2; + } - #region Setup + #region Setup - /// - /// Pre-allocates a minimum number of bank slots. Returns the actual capacity - /// Instance of the library - /// Count of bank slots to pre-allocate. - /// actual capacity of reserved bank slots. - /// - [DllImport(LibraryName)] - public static extern int adl_reserveBanks(IntPtr device, uint banks); - /// - /// Gets the bank designated by the identifier, optionally creating if it does not exist - /// Instance of the library - /// Identifier of dynamic bank - /// Flags for dynamic bank access (BankAccessFlags) - /// Reference to dynamic bank - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_getBank(IntPtr device, ref BankId id, BankAccessFlags flags, out Bank bank); - /// - /// Gets the identifier of a bank - /// Instance of the library - /// Reference to dynamic bank. - /// Identifier of dynamic bank - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_getBankId(IntPtr device, ref Bank bank, out BankId id); - /// - /// Removes a bank - /// Instance of the library - /// Reference to dynamic bank - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_removeBank(IntPtr device, ref Bank bank); - /// - /// Gets the first bank - /// Instance of the library - /// Reference to dynamic bank - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_getFirstBank(IntPtr device, out Bank bank); - /// - /// Iterates to the next bank - /// Instance of the library - /// Reference to dynamic bank - /// 0 on success, <0 when any error has occurred or end has been reached. - /// - [DllImport(LibraryName)] - public static extern int adl_getNextBank(IntPtr device, out Bank bank); - /// - /// Gets the nth instrument in the bank [0..127] - /// Instance of the library - /// Reference to dynamic bank - /// Index of the instrument - /// Instrument entry - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_getInstrument(IntPtr device, ref Bank bank, uint index, out Instrument ins); - /// - /// Sets the nth instrument in the bank [0..127] - /// Instance of the library - /// Reference to dynamic bank - /// Index of the instrument - /// Instrument structure pointer - /// 0 on success, <0 when any error has occurred - /// - /// This function allows to override an instrument on the fly - /// - [DllImport(LibraryName)] - public static extern int adl_setInstrument(IntPtr device, ref Bank bank, uint index, ref Instrument ins); - /// - /// Loads the melodic or percussive part of the nth embedded bank - /// Instance of the library - /// Reference to dynamic bank - /// Number of embedded bank to load into the current bank array - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_loadEmbeddedBank(IntPtr device, ref Bank bank, int num); + /// + /// Pre-allocates a minimum number of bank slots. Returns the actual capacity + /// Instance of the library + /// Count of bank slots to pre-allocate. + /// actual capacity of reserved bank slots. + /// + [DllImport(LibraryName)] + public static extern int adl_reserveBanks(IntPtr device, uint banks); + /// + /// Gets the bank designated by the identifier, optionally creating if it does not exist + /// Instance of the library + /// Identifier of dynamic bank + /// Flags for dynamic bank access (BankAccessFlags) + /// Reference to dynamic bank + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_getBank(IntPtr device, ref BankId id, BankAccessFlags flags, out Bank bank); + /// + /// Gets the identifier of a bank + /// Instance of the library + /// Reference to dynamic bank. + /// Identifier of dynamic bank + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_getBankId(IntPtr device, ref Bank bank, out BankId id); + /// + /// Removes a bank + /// Instance of the library + /// Reference to dynamic bank + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_removeBank(IntPtr device, ref Bank bank); + /// + /// Gets the first bank + /// Instance of the library + /// Reference to dynamic bank + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_getFirstBank(IntPtr device, out Bank bank); + /// + /// Iterates to the next bank + /// Instance of the library + /// Reference to dynamic bank + /// 0 on success, <0 when any error has occurred or end has been reached. + /// + [DllImport(LibraryName)] + public static extern int adl_getNextBank(IntPtr device, out Bank bank); + /// + /// Gets the nth instrument in the bank [0..127] + /// Instance of the library + /// Reference to dynamic bank + /// Index of the instrument + /// Instrument entry + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_getInstrument(IntPtr device, ref Bank bank, uint index, out Instrument ins); + /// + /// Sets the nth instrument in the bank [0..127] + /// Instance of the library + /// Reference to dynamic bank + /// Index of the instrument + /// Instrument structure pointer + /// 0 on success, <0 when any error has occurred + /// + /// This function allows to override an instrument on the fly + /// + [DllImport(LibraryName)] + public static extern int adl_setInstrument(IntPtr device, ref Bank bank, uint index, ref Instrument ins); + /// + /// Loads the melodic or percussive part of the nth embedded bank + /// Instance of the library + /// Reference to dynamic bank + /// Number of embedded bank to load into the current bank array + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_loadEmbeddedBank(IntPtr device, ref Bank bank, int num); - /// - /// Sets number of 4-operator channels between all chips - /// - /// By default, it is automatically re-calculating every bank change. - /// If you want to specify custom number of four operator channels, - /// please call this function after bank change (adl_setBank() or adl_openBank()), - /// otherwise, value will be overwritten by auto-calculated. - /// If the count is specified as -1, an auto-calculated amount is used instead. - /// - /// Instance of the library - /// Count of four-op channels to allocate between all emulating chips - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_setNumFourOpsChn(IntPtr device, int ops4); + /// + /// Sets number of 4-operator channels between all chips + /// + /// By default, it is automatically re-calculating every bank change. + /// If you want to specify custom number of four operator channels, + /// please call this function after bank change (adl_setBank() or adl_openBank()), + /// otherwise, value will be overwritten by auto-calculated. + /// If the count is specified as -1, an auto-calculated amount is used instead. + /// + /// Instance of the library + /// Count of four-op channels to allocate between all emulating chips + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_setNumFourOpsChn(IntPtr device, int ops4); - /// - /// Get current total count of 4-operator channels between all chips - /// Instance of the library - /// 0 on success, <-1 when any error has occurred, but, -1 - "auto" - /// - [DllImport(LibraryName)] - public static extern int adl_getNumFourOpsChn(IntPtr device); + /// + /// Get current total count of 4-operator channels between all chips + /// Instance of the library + /// 0 on success, <-1 when any error has occurred, but, -1 - "auto" + /// + [DllImport(LibraryName)] + public static extern int adl_getNumFourOpsChn(IntPtr device); - /// - /// Get obtained total count of 4-operator channels between all chips - /// Instance of the library - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_getNumFourOpsChnObtained(IntPtr device); + /// + /// Get obtained total count of 4-operator channels between all chips + /// Instance of the library + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_getNumFourOpsChnObtained(IntPtr device); - /// - /// Override Enable(1) or Disable(0) deep vibrato state. -1 - use bank default vibrato state - /// Instance of the library - /// 0 - disabled, 1 - enabled - /// - [DllImport(LibraryName)] - public static extern void adl_setHVibrato(IntPtr device, int vibratoMode); + /// + /// Override Enable(1) or Disable(0) deep vibrato state. -1 - use bank default vibrato state + /// Instance of the library + /// 0 - disabled, 1 - enabled + /// + [DllImport(LibraryName)] + public static extern void adl_setHVibrato(IntPtr device, int vibratoMode); - /// - /// Get the deep vibrato state. - /// Instance of the library - /// deep vibrato state on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_getHVibrato(IntPtr device); + /// + /// Get the deep vibrato state. + /// Instance of the library + /// deep vibrato state on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_getHVibrato(IntPtr device); - /// - /// Override Enable(1) or Disable(0) deep tremolo state. -1 - use bank default tremolo state - /// Instance of the library - /// 0 - disabled, 1 - enabled - /// - [DllImport(LibraryName)] - public static extern void adl_setHTremolo(IntPtr device, int tremoloMode); + /// + /// Override Enable(1) or Disable(0) deep tremolo state. -1 - use bank default tremolo state + /// Instance of the library + /// 0 - disabled, 1 - enabled + /// + [DllImport(LibraryName)] + public static extern void adl_setHTremolo(IntPtr device, int tremoloMode); - /// - /// Get the deep tremolo state. - /// Instance of the library - /// deep tremolo state on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_getHTremolo(IntPtr device); + /// + /// Get the deep tremolo state. + /// Instance of the library + /// deep tremolo state on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_getHTremolo(IntPtr device); - /// - /// Override Enable(1) or Disable(0) scaling of modulator volumes. -1 - use bank default scaling of modulator volumes - /// Instance of the library - /// 0 - disabled, 1 - enabled - /// - [DllImport(LibraryName)] - public static extern void adl_setScaleModulators(IntPtr device, int modulatorVolumeScaling); + /// + /// Override Enable(1) or Disable(0) scaling of modulator volumes. -1 - use bank default scaling of modulator volumes + /// Instance of the library + /// 0 - disabled, 1 - enabled + /// + [DllImport(LibraryName)] + public static extern void adl_setScaleModulators(IntPtr device, int modulatorVolumeScaling); - /// - /// Enable(1) or Disable(0) full-range brightness (MIDI CC74 used in XG music to filter result sounding) scaling - /// - /// By default, brightness affects sound between 0 and 64. - /// When this option is enabled, the brightness will use full range from 0 up to 127. - /// - /// Instance of the library - /// 0 - disabled, 1 - enabled - /// - [DllImport(LibraryName)] - public static extern void adl_setFullRangeBrightness(IntPtr device, int fullRangeBrightness); + /// + /// Enable(1) or Disable(0) full-range brightness (MIDI CC74 used in XG music to filter result sounding) scaling + /// + /// By default, brightness affects sound between 0 and 64. + /// When this option is enabled, the brightness will use full range from 0 up to 127. + /// + /// Instance of the library + /// 0 - disabled, 1 - enabled + /// + [DllImport(LibraryName)] + public static extern void adl_setFullRangeBrightness(IntPtr device, int fullRangeBrightness); - /// - /// Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part) - /// Instance of the library - /// 0 - disabled, 1 - enabled - /// - [DllImport(LibraryName)] - public static extern void adl_setLoopEnabled(IntPtr device, bool loopEnabled); + /// + /// Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part) + /// Instance of the library + /// 0 - disabled, 1 - enabled + /// + [DllImport(LibraryName)] + public static extern void adl_setLoopEnabled(IntPtr device, bool loopEnabled); - /// - /// Enable or disable soft panning with chip emulators - /// Instance of the library - /// 0 - disabled, 1 - enabled - /// - [DllImport(LibraryName)] - public static extern void adl_setSoftPanEnabled(IntPtr device, bool softPanEnabled); + /// + /// Enable or disable soft panning with chip emulators + /// Instance of the library + /// 0 - disabled, 1 - enabled + /// + [DllImport(LibraryName)] + public static extern void adl_setSoftPanEnabled(IntPtr device, bool softPanEnabled); - /// - /// Set different volume range model - /// Instance of the library - /// Volume model type (#VolumeModel) - /// - [DllImport(LibraryName)] - public static extern void adl_setVolumeRangeModel(IntPtr device, VolumeModel volumeModel); + /// + /// Set different volume range model + /// Instance of the library + /// Volume model type (#VolumeModel) + /// + [DllImport(LibraryName)] + public static extern void adl_setVolumeRangeModel(IntPtr device, VolumeModel volumeModel); - /// - /// Get the volume range model - /// Instance of the library - /// volume model on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern VolumeModel adl_getVolumeRangeModel(IntPtr device); + /// + /// Get the volume range model + /// Instance of the library + /// volume model on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern VolumeModel adl_getVolumeRangeModel(IntPtr device); - /// - /// Load WOPL bank file from File System - /// - /// Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. - /// - /// Instance of the library - /// Absolute or relative path to the WOPL bank file. UTF8 encoding is required, even on Windows. - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_openBankFile(IntPtr device, string filePath); + /// + /// Load WOPL bank file from File System + /// + /// Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. + /// + /// Instance of the library + /// Absolute or relative path to the WOPL bank file. UTF8 encoding is required, even on Windows. + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_openBankFile(IntPtr device, string filePath); - /// - /// Load WOPL bank file from memory data - /// - /// Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. - /// - /// Instance of the library - /// Pointer to memory block where is raw data of WOPL bank file is stored - /// Size of given memory block - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern unsafe int adl_openBankData(IntPtr device, byte* mem, uint size); + /// + /// Load WOPL bank file from memory data + /// + /// Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. + /// + /// Instance of the library + /// Pointer to memory block where is raw data of WOPL bank file is stored + /// Size of given memory block + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern unsafe int adl_openBankData(IntPtr device, byte* mem, uint size); - /// - /// Returns chip emulator name string - /// Instance of the library - /// Understandable name of current OPL3 emulator - /// - [DllImport(LibraryName)] - public static extern string adl_chipEmulatorName(IntPtr device); + /// + /// Returns chip emulator name string + /// Instance of the library + /// Understandable name of current OPL3 emulator + /// + [DllImport(LibraryName)] + public static extern string adl_chipEmulatorName(IntPtr device); - /// - /// Switch the emulation core - /// Instance of the library - /// Type of emulator (#Emulator) - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_switchEmulator(IntPtr device, Emulator emulator); + /// + /// Switch the emulation core + /// Instance of the library + /// Type of emulator (#Emulator) + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_switchEmulator(IntPtr device, Emulator emulator); - /// - /// Library version context - /// - [StructLayout(LayoutKind.Sequential)] - public struct AdlVersion - { - public ushort Major; - public ushort Minor; - public ushort Patch; - } + /// + /// Library version context + /// + [StructLayout(LayoutKind.Sequential)] + public struct AdlVersion + { + public ushort Major; + public ushort Minor; + public ushort Patch; + } - /// - /// Run emulator with PCM rate to reduce CPU usage on slow devices. - /// - /// May decrease sounding accuracy on some chip emulators. - /// - /// Instance of the library - /// 0 - disabled, 1 - enabled - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_setRunAtPcmRate(IntPtr device, bool enabled); + /// + /// Run emulator with PCM rate to reduce CPU usage on slow devices. + /// + /// May decrease sounding accuracy on some chip emulators. + /// + /// Instance of the library + /// 0 - disabled, 1 - enabled + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_setRunAtPcmRate(IntPtr device, bool enabled); - /// - /// Set 4-bit device identifier. Used by the SysEx processor. - /// Instance of the library - /// 4-bit device identifier - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_setDeviceIdentifier(IntPtr device, uint id); + /// + /// Set 4-bit device identifier. Used by the SysEx processor. + /// Instance of the library + /// 4-bit device identifier + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_setDeviceIdentifier(IntPtr device, uint id); - /// - /// @section Information - /// + /// + /// @section Information + /// - /// - /// Returns string which contains a version number - /// String which contains a version of the library - /// - [DllImport(LibraryName)] - public static extern string adl_linkedLibraryVersion(); + /// + /// Returns string which contains a version number + /// String which contains a version of the library + /// + [DllImport(LibraryName)] + public static extern string adl_linkedLibraryVersion(); - /// - /// Returns structure which contains a version number of library - /// Library version context structure which contains version number of the library - /// - [DllImport(LibraryName)] - public static extern AdlVersion adl_linkedVersion(); + /// + /// Returns structure which contains a version number of library + /// Library version context structure which contains version number of the library + /// + [DllImport(LibraryName)] + public static extern AdlVersion adl_linkedVersion(); - #endregion + #endregion - #region Error Info + #region Error Info - /// - /// Returns string which contains last error message of initialization - /// - /// Don't use this function to get info on any function except of `adl_init`! - /// Use `adl_errorInfo()` to get error information while workflow - /// - /// String with error message related to library initialization - /// - [DllImport(LibraryName)] - public static extern string adl_errorString(); + /// + /// Returns string which contains last error message of initialization + /// + /// Don't use this function to get info on any function except of `adl_init`! + /// Use `adl_errorInfo()` to get error information while workflow + /// + /// String with error message related to library initialization + /// + [DllImport(LibraryName)] + public static extern string adl_errorString(); - /// - /// Returns string which contains last error message on specific device - /// Instance of the library - /// String with error message related to last function call returned non-zero value. - /// - [DllImport(LibraryName)] - public static extern string adl_errorInfo(IntPtr device); + /// + /// Returns string which contains last error message on specific device + /// Instance of the library + /// String with error message related to last function call returned non-zero value. + /// + [DllImport(LibraryName)] + public static extern string adl_errorInfo(IntPtr device); - #endregion + #endregion - #region Initialization + #region Initialization - /// - /// Initialize ADLMIDI Player device - /// - /// Tip 1: You can initialize multiple instances and run them in parallel - /// Tip 2: Library is NOT thread-safe, therefore don't use same instance in different threads or use mutexes - /// Tip 3: Changing of sample rate on the fly is not supported. Re-create the instance again. - /// Top 4: To generate output in OPL chip native sample rate, please initialize it with sample rate value as `ChipSampleRate` - /// - /// Output sample rate - /// Instance of the library. If NULL was returned, check the `adl_errorString` message for more info. - /// - [DllImport(LibraryName)] - public static extern IntPtr adl_init(long sampleRate); + /// + /// Initialize ADLMIDI Player device + /// + /// Tip 1: You can initialize multiple instances and run them in parallel + /// Tip 2: Library is NOT thread-safe, therefore don't use same instance in different threads or use mutexes + /// Tip 3: Changing of sample rate on the fly is not supported. Re-create the instance again. + /// Top 4: To generate output in OPL chip native sample rate, please initialize it with sample rate value as `ChipSampleRate` + /// + /// Output sample rate + /// Instance of the library. If NULL was returned, check the `adl_errorString` message for more info. + /// + [DllImport(LibraryName)] + public static extern IntPtr adl_init(long sampleRate); - /// - /// Close and delete ADLMIDI device - /// Instance of the library - /// - [DllImport(LibraryName)] - public static extern void adl_close(IntPtr device); + /// + /// Close and delete ADLMIDI device + /// Instance of the library + /// + [DllImport(LibraryName)] + public static extern void adl_close(IntPtr device); - #endregion + #endregion - #region MIDI Sequencer + #region MIDI Sequencer - /// - /// Load MIDI (or any other supported format) file from File System - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// Absolute or relative path to the music file. UTF8 encoding is required, even on Windows. - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_openFile(IntPtr device, string filePath); + /// + /// Load MIDI (or any other supported format) file from File System + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// Absolute or relative path to the music file. UTF8 encoding is required, even on Windows. + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_openFile(IntPtr device, string filePath); - /// - /// Load MIDI (or any other supported format) file from memory data - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// Pointer to memory block where is raw data of music file is stored - /// Size of given memory block - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern unsafe int adl_openData(IntPtr device, byte* mem, uint size); + /// + /// Load MIDI (or any other supported format) file from memory data + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// Pointer to memory block where is raw data of music file is stored + /// Size of given memory block + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern unsafe int adl_openData(IntPtr device, byte* mem, uint size); - /// - /// Resets MIDI player (per-channel setup) into initial state - /// Instance of the library - /// - [DllImport(LibraryName)] - public static extern void adl_reset(IntPtr device); + /// + /// Resets MIDI player (per-channel setup) into initial state + /// Instance of the library + /// + [DllImport(LibraryName)] + public static extern void adl_reset(IntPtr device); - /// - /// Get total time length of current song - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// Total song length in seconds - /// - [DllImport(LibraryName)] - public static extern double adl_totalTimeLength(IntPtr device); + /// + /// Get total time length of current song + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// Total song length in seconds + /// + [DllImport(LibraryName)] + public static extern double adl_totalTimeLength(IntPtr device); - /// - /// Get loop start time if presented. - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// Time position in seconds of loop start point, or -1 when file has no loop points - /// - [DllImport(LibraryName)] - public static extern double adl_loopStartTime(IntPtr device); + /// + /// Get loop start time if presented. + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// Time position in seconds of loop start point, or -1 when file has no loop points + /// + [DllImport(LibraryName)] + public static extern double adl_loopStartTime(IntPtr device); - /// - /// Get loop end time if present. - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// Time position in seconds of loop end point, or -1 when file has no loop points - /// - [DllImport(LibraryName)] - public static extern double adl_loopEndTime(IntPtr device); + /// + /// Get loop end time if present. + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// Time position in seconds of loop end point, or -1 when file has no loop points + /// + [DllImport(LibraryName)] + public static extern double adl_loopEndTime(IntPtr device); - /// - /// Get current time position in seconds - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// Current time position in seconds - /// - [DllImport(LibraryName)] - public static extern double adl_positionTell(IntPtr device); + /// + /// Get current time position in seconds + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// Current time position in seconds + /// + [DllImport(LibraryName)] + public static extern double adl_positionTell(IntPtr device); - /// - /// Jump to absolute time position in seconds - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// Destination time position in seconds to seek - /// - [DllImport(LibraryName)] - public static extern void adl_positionSeek(IntPtr device, double seconds); + /// + /// Jump to absolute time position in seconds + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// Destination time position in seconds to seek + /// + [DllImport(LibraryName)] + public static extern void adl_positionSeek(IntPtr device, double seconds); - /// - /// Reset MIDI track position to begin - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// - [DllImport(LibraryName)] - public static extern void adl_positionRewind(IntPtr device); + /// + /// Reset MIDI track position to begin + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// + [DllImport(LibraryName)] + public static extern void adl_positionRewind(IntPtr device); - /// - /// Set tempo multiplier - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// Tempo multiplier value: 1.0 - original tempo, >1 - play faster, <1 - play slower - /// - [DllImport(LibraryName)] - public static extern void adl_setTempo(IntPtr device, double tempo); + /// + /// Set tempo multiplier + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// Tempo multiplier value: 1.0 - original tempo, >1 - play faster, <1 - play slower + /// + [DllImport(LibraryName)] + public static extern void adl_setTempo(IntPtr device, double tempo); - /// - /// Returns 1 if music position has reached end - /// Instance of the library - /// 1 when end of sing has been reached, otherwise, 0 will be returned. <0 is returned on any error - /// - [DllImport(LibraryName)] - public static extern int adl_atEnd(IntPtr device); + /// + /// Returns 1 if music position has reached end + /// Instance of the library + /// 1 when end of sing has been reached, otherwise, 0 will be returned. <0 is returned on any error + /// + [DllImport(LibraryName)] + public static extern int adl_atEnd(IntPtr device); - /// - /// Returns the number of tracks of the current sequence - /// Instance of the library - /// Count of tracks in the current sequence - /// - [DllImport(LibraryName)] - public static extern UIntPtr adl_trackCount(IntPtr device); + /// + /// Returns the number of tracks of the current sequence + /// Instance of the library + /// Count of tracks in the current sequence + /// + [DllImport(LibraryName)] + public static extern UIntPtr adl_trackCount(IntPtr device); - /// - /// Sets options on a track of the current sequence - /// Instance of the library - /// Identifier of the designated track. - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_setTrackOptions(IntPtr device, UIntPtr trackNumber, TrackOptions trackOptions); + /// + /// Sets options on a track of the current sequence + /// Instance of the library + /// Identifier of the designated track. + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_setTrackOptions(IntPtr device, UIntPtr trackNumber, TrackOptions trackOptions); - /// - /// Handler of callback trigger events - /// Pointer to user data (usually, context of something) - /// Value of the event which triggered this callback. - /// Identifier of the track which triggered this callback. - /// - public delegate void TriggerHandler(IntPtr userData, uint trigger, UIntPtr track); + /// + /// Handler of callback trigger events + /// Pointer to user data (usually, context of something) + /// Value of the event which triggered this callback. + /// Identifier of the track which triggered this callback. + /// + public delegate void TriggerHandler(IntPtr userData, uint trigger, UIntPtr track); - /// - /// Defines a handler for callback trigger events - /// Instance of the library - /// Handler to invoke from the sequencer when triggered, or NULL. - /// Instance of the library - /// 0 on success, <0 when any error has occurred - /// - [DllImport(LibraryName)] - public static extern int adl_setTriggerHandler(IntPtr device, TriggerHandler handler, IntPtr userData); + /// + /// Defines a handler for callback trigger events + /// Instance of the library + /// Handler to invoke from the sequencer when triggered, or NULL. + /// Instance of the library + /// 0 on success, <0 when any error has occurred + /// + [DllImport(LibraryName)] + public static extern int adl_setTriggerHandler(IntPtr device, TriggerHandler handler, IntPtr userData); - #endregion + #endregion - #region Meta-Tags + #region Meta-Tags - /// - /// Returns string which contains a music title - /// Instance of the library - /// A string that contains music title - /// - [DllImport(LibraryName)] - public static extern string adl_metaMusicTitle(IntPtr device); + /// + /// Returns string which contains a music title + /// Instance of the library + /// A string that contains music title + /// + [DllImport(LibraryName)] + public static extern string adl_metaMusicTitle(IntPtr device); - /// - /// Returns string which contains a copyright string* - /// Instance of the library - /// A string that contains copyright notice, otherwise NULL - /// - [DllImport(LibraryName)] - public static extern string adl_metaMusicCopyright(IntPtr device); + /// + /// Returns string which contains a copyright string* + /// Instance of the library + /// A string that contains copyright notice, otherwise NULL + /// + [DllImport(LibraryName)] + public static extern string adl_metaMusicCopyright(IntPtr device); - /// - /// Returns count of available track titles - /// - /// NOTE: There are CAN'T be associated with channel in any of event or note hooks - /// - /// Instance of the library - /// Count of available MIDI tracks, otherwise NULL - /// - [DllImport(LibraryName)] - public static extern UIntPtr adl_metaTrackTitleCount(IntPtr device); + /// + /// Returns count of available track titles + /// + /// NOTE: There are CAN'T be associated with channel in any of event or note hooks + /// + /// Instance of the library + /// Count of available MIDI tracks, otherwise NULL + /// + [DllImport(LibraryName)] + public static extern UIntPtr adl_metaTrackTitleCount(IntPtr device); - /// - /// Get track title by index - /// Instance of the library - /// Index of the track to retrieve the title - /// A string that contains track title, otherwise NULL. - /// - [DllImport(LibraryName)] - public static extern string adl_metaTrackTitle(IntPtr device, UIntPtr index); + /// + /// Get track title by index + /// Instance of the library + /// Index of the track to retrieve the title + /// A string that contains track title, otherwise NULL. + /// + [DllImport(LibraryName)] + public static extern string adl_metaTrackTitle(IntPtr device, UIntPtr index); - /// - /// Returns count of available markers - /// Instance of the library - /// Count of available MIDI markers - /// - [DllImport(LibraryName)] - public static extern UIntPtr adl_metaMarkerCount(IntPtr device); + /// + /// Returns count of available markers + /// Instance of the library + /// Count of available MIDI markers + /// + [DllImport(LibraryName)] + public static extern UIntPtr adl_metaMarkerCount(IntPtr device); - /// - /// Returns the marker entry - /// Instance of the library - /// Index of the marker to retrieve it. - /// MIDI Marker description structure. - /// - [DllImport(LibraryName)] - public static extern MarkerEntry adl_metaMarker(IntPtr device, UIntPtr index); + /// + /// Returns the marker entry + /// Instance of the library + /// Index of the marker to retrieve it. + /// MIDI Marker description structure. + /// + [DllImport(LibraryName)] + public static extern MarkerEntry adl_metaMarker(IntPtr device, UIntPtr index); - #endregion + #endregion - #region Audio output Generation + #region Audio output Generation - /// - /// Generate PCM signed 16-bit stereo audio output and iterate MIDI timers - /// - /// Use this function when you are playing a MIDI file loaded by `adl_openFile` or `adl_openData` - /// when using the built-in MIDI sequencer. - /// - /// Don't use count of frames, instead use the count of samples. One frame is two samples. - /// So, for example, if you want to take 10 frames, you must request 20 samples! - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// Count of samples (not frames!) - /// Pointer to output with 16-bit stereo PCM output - /// Count of given samples, otherwise, 0 or when catching an error while playing - /// - [DllImport(LibraryName)] - public static extern unsafe int adl_play(IntPtr device, int sampleCount, short* sampleBuffer); + /// + /// Generate PCM signed 16-bit stereo audio output and iterate MIDI timers + /// + /// Use this function when you are playing a MIDI file loaded by `adl_openFile` or `adl_openData` + /// when using the built-in MIDI sequencer. + /// + /// Don't use count of frames, instead use the count of samples. One frame is two samples. + /// So, for example, if you want to take 10 frames, you must request 20 samples! + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// Count of samples (not frames!) + /// Pointer to output with 16-bit stereo PCM output + /// Count of given samples, otherwise, 0 or when catching an error while playing + /// + [DllImport(LibraryName)] + public static extern unsafe int adl_play(IntPtr device, int sampleCount, short* sampleBuffer); - /// - /// Generate PCM stereo audio output in sample format declared by given context and iterate MIDI timers - /// - /// Use this function when you are playing MIDI file loaded by `adl_openFile` or `adl_openData` - /// when using the built-in MIDI sequencer. - /// - /// Don't use count of frames, instead use the count of samples. One frame is two samples. - /// So, for example, if you want to take 10 frames, you must request 20 samples! - /// - /// Available when library is built with built-in MIDI Sequencer support. - /// - /// Instance of the library - /// Count of samples (not frames!) - /// Left channel buffer output (must be cast to byte array) - /// Right channel buffer output (must be cast to byte array) - /// Destination PCM format context - /// Count of given samples, otherwise, 0 or when catching an error while playing - /// - [DllImport(LibraryName)] - public static extern int adl_playFormat(IntPtr device, int sampleCount, IntPtr left, IntPtr right, ref AudioFormat format); + /// + /// Generate PCM stereo audio output in sample format declared by given context and iterate MIDI timers + /// + /// Use this function when you are playing MIDI file loaded by `adl_openFile` or `adl_openData` + /// when using the built-in MIDI sequencer. + /// + /// Don't use count of frames, instead use the count of samples. One frame is two samples. + /// So, for example, if you want to take 10 frames, you must request 20 samples! + /// + /// Available when library is built with built-in MIDI Sequencer support. + /// + /// Instance of the library + /// Count of samples (not frames!) + /// Left channel buffer output (must be cast to byte array) + /// Right channel buffer output (must be cast to byte array) + /// Destination PCM format context + /// Count of given samples, otherwise, 0 or when catching an error while playing + /// + [DllImport(LibraryName)] + public static extern int adl_playFormat(IntPtr device, int sampleCount, IntPtr left, IntPtr right, ref AudioFormat format); - /// - /// Generate PCM signed 16-bit stereo audio output without iteration of MIDI timers - /// - /// Use this function when you are using library as Real-Time MIDI synthesizer or with - /// an external MIDI sequencer. You must request the amount of samples which is equal - /// to the delta between of MIDI event rows. One MIDI row is a group of MIDI events - /// are having zero delta/delay between each other. When you are receiving events in - /// real time, request the minimum possible delay value. - /// - /// Don't use count of frames, use instead count of samples. One frame is two samples. - /// So, for example, if you want to take 10 frames, you must request amount of 20 samples! - /// - /// Instance of the library - /// @param sampleCount - /// Pointer to output with 16-bit stereo PCM output - /// Count of given samples, otherwise, 0 or when catching an error while playing - /// - [DllImport(LibraryName)] - public static extern unsafe int adl_generate(IntPtr device, int sampleCount, short* sampleBuffer); // sampleBuffer = short[] + /// + /// Generate PCM signed 16-bit stereo audio output without iteration of MIDI timers + /// + /// Use this function when you are using library as Real-Time MIDI synthesizer or with + /// an external MIDI sequencer. You must request the amount of samples which is equal + /// to the delta between of MIDI event rows. One MIDI row is a group of MIDI events + /// are having zero delta/delay between each other. When you are receiving events in + /// real time, request the minimum possible delay value. + /// + /// Don't use count of frames, use instead count of samples. One frame is two samples. + /// So, for example, if you want to take 10 frames, you must request amount of 20 samples! + /// + /// Instance of the library + /// @param sampleCount + /// Pointer to output with 16-bit stereo PCM output + /// Count of given samples, otherwise, 0 or when catching an error while playing + /// + [DllImport(LibraryName)] + public static extern unsafe int adl_generate(IntPtr device, int sampleCount, short* sampleBuffer); // sampleBuffer = short[] - /// - /// Generate PCM stereo audio output in sample format declared by given context without iteration of MIDI timers - /// - /// Use this function when you are using library as Real-Time MIDI synthesizer or with - /// an external MIDI sequencer. You must request the amount of samples which is equal - /// to the delta between of MIDI event rows. One MIDI row is a group of MIDI events - /// are having zero delta/delay between each other. When you are receiving events in - /// real time, request the minimum possible delay value. - /// - /// Don't use count of frames, use instead count of samples. One frame is two samples. - /// So, for example, if you want to take 10 frames, you must request amount of 20 samples! - /// - /// Instance of the library - /// @param sampleCount - /// Left channel buffer output (must be cast to byte array) - /// Right channel buffer output (must be cast to byte array) - /// Destination PCM format context - /// Count of given samples, otherwise, 0 or when catching an error while playing - /// - [DllImport(LibraryName)] - public static extern int adl_generateFormat(IntPtr device, int sampleCount, IntPtr left, IntPtr right, ref AudioFormat format); + /// + /// Generate PCM stereo audio output in sample format declared by given context without iteration of MIDI timers + /// + /// Use this function when you are using library as Real-Time MIDI synthesizer or with + /// an external MIDI sequencer. You must request the amount of samples which is equal + /// to the delta between of MIDI event rows. One MIDI row is a group of MIDI events + /// are having zero delta/delay between each other. When you are receiving events in + /// real time, request the minimum possible delay value. + /// + /// Don't use count of frames, use instead count of samples. One frame is two samples. + /// So, for example, if you want to take 10 frames, you must request amount of 20 samples! + /// + /// Instance of the library + /// @param sampleCount + /// Left channel buffer output (must be cast to byte array) + /// Right channel buffer output (must be cast to byte array) + /// Destination PCM format context + /// Count of given samples, otherwise, 0 or when catching an error while playing + /// + [DllImport(LibraryName)] + public static extern int adl_generateFormat(IntPtr device, int sampleCount, IntPtr left, IntPtr right, ref AudioFormat format); - /// - /// Periodic tick handler. - /// - /// Notice: The function is provided to use it with Hardware OPL3 mode or for the purpose of iterating - /// MIDI playback without sound generation. - /// - /// DON'T USE IT TOGETHER WITH adl_play() and adl_playFormat() calls - /// as there are all using this function internally!!! - /// - /// Instance of the library - /// Previous delay. For the first moment, pass `0.0` - /// Minimum size of one MIDI tick in seconds. - /// desired number of seconds until next call. Pass this value into `seconds` field in next time - /// - [DllImport(LibraryName)] - public static extern double adl_tickEvents(IntPtr device, double seconds, double granularity); + /// + /// Periodic tick handler. + /// + /// Notice: The function is provided to use it with Hardware OPL3 mode or for the purpose of iterating + /// MIDI playback without sound generation. + /// + /// DON'T USE IT TOGETHER WITH adl_play() and adl_playFormat() calls + /// as there are all using this function internally!!! + /// + /// Instance of the library + /// Previous delay. For the first moment, pass `0.0` + /// Minimum size of one MIDI tick in seconds. + /// desired number of seconds until next call. Pass this value into `seconds` field in next time + /// + [DllImport(LibraryName)] + public static extern double adl_tickEvents(IntPtr device, double seconds, double granularity); - #endregion + #endregion - #region Real-Time MIDI + #region Real-Time MIDI - /// - /// Force Off all notes on all channels - /// Instance of the library - /// - [DllImport(LibraryName)] - public static extern void adl_panic(IntPtr device); + /// + /// Force Off all notes on all channels + /// Instance of the library + /// + [DllImport(LibraryName)] + public static extern void adl_panic(IntPtr device); - /// - /// Reset states of all controllers on all MIDI channels - /// Instance of the library - /// - [DllImport(LibraryName)] - public static extern void adl_rt_resetState(IntPtr device); + /// + /// Reset states of all controllers on all MIDI channels + /// Instance of the library + /// + [DllImport(LibraryName)] + public static extern void adl_rt_resetState(IntPtr device); - /// - /// Turn specific MIDI note ON - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// Note number to on [Between 0 and 127] - /// Velocity level [Between 0 and 127] - /// 1 when note was successfully started, 0 when note was rejected for any reason. - /// - [DllImport(LibraryName)] - public static extern int adl_rt_noteOn(IntPtr device, byte channel, byte note, byte velocity); + /// + /// Turn specific MIDI note ON + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// Note number to on [Between 0 and 127] + /// Velocity level [Between 0 and 127] + /// 1 when note was successfully started, 0 when note was rejected for any reason. + /// + [DllImport(LibraryName)] + public static extern int adl_rt_noteOn(IntPtr device, byte channel, byte note, byte velocity); - /// - /// Turn specific MIDI note OFF - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// Note number to off [Between 0 and 127] - /// - [DllImport(LibraryName)] - public static extern void adl_rt_noteOff(IntPtr device, byte channel, byte note); + /// + /// Turn specific MIDI note OFF + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// Note number to off [Between 0 and 127] + /// + [DllImport(LibraryName)] + public static extern void adl_rt_noteOff(IntPtr device, byte channel, byte note); - /// - /// Set note after-touch - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// Note number to affect by aftertouch event [Between 0 and 127] - /// After-Touch value [Between 0 and 127] - /// - [DllImport(LibraryName)] - public static extern void adl_rt_noteAfterTouch(IntPtr device, byte channel, byte note, byte atVal); + /// + /// Set note after-touch + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// Note number to affect by aftertouch event [Between 0 and 127] + /// After-Touch value [Between 0 and 127] + /// + [DllImport(LibraryName)] + public static extern void adl_rt_noteAfterTouch(IntPtr device, byte channel, byte note, byte atVal); - /// - /// Set channel after-touch - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// After-Touch level [Between 0 and 127] - /// - [DllImport(LibraryName)] - public static extern void adl_rt_channelAfterTouch(IntPtr device, byte channel, byte atVal); + /// + /// Set channel after-touch + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// After-Touch level [Between 0 and 127] + /// + [DllImport(LibraryName)] + public static extern void adl_rt_channelAfterTouch(IntPtr device, byte channel, byte atVal); - /// - /// Apply controller change - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// Type of the controller [Between 0 and 255] - /// Value of the controller event [Between 0 and 127] - /// - [DllImport(LibraryName)] - public static extern void adl_rt_controllerChange(IntPtr device, byte channel, byte type, byte value); + /// + /// Apply controller change + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// Type of the controller [Between 0 and 255] + /// Value of the controller event [Between 0 and 127] + /// + [DllImport(LibraryName)] + public static extern void adl_rt_controllerChange(IntPtr device, byte channel, byte type, byte value); - /// - /// Apply patch change - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// Patch number [Between 0 and 127] - /// - [DllImport(LibraryName)] - public static extern void adl_rt_patchChange(IntPtr device, byte channel, byte patch); + /// + /// Apply patch change + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// Patch number [Between 0 and 127] + /// + [DllImport(LibraryName)] + public static extern void adl_rt_patchChange(IntPtr device, byte channel, byte patch); - /// - /// Apply pitch bend change - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// 24-bit pitch bend value - /// - [DllImport(LibraryName)] - public static extern void adl_rt_pitchBend(IntPtr device, byte channel, ushort pitch); + /// + /// Apply pitch bend change + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// 24-bit pitch bend value + /// + [DllImport(LibraryName)] + public static extern void adl_rt_pitchBend(IntPtr device, byte channel, ushort pitch); - /// - /// Apply pitch bend change - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// MSB part of 24-bit pitch bend value - /// LSB part of 24-bit pitch bend value - /// - [DllImport(LibraryName)] - public static extern void adl_rt_pitchBendML(IntPtr device, byte channel, byte msb, byte lsb); + /// + /// Apply pitch bend change + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// MSB part of 24-bit pitch bend value + /// LSB part of 24-bit pitch bend value + /// + [DllImport(LibraryName)] + public static extern void adl_rt_pitchBendML(IntPtr device, byte channel, byte msb, byte lsb); - /// - /// Change LSB of the bank number (Alias to CC-32 event) - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// LSB value of the MIDI bank number - /// - [DllImport(LibraryName)] - public static extern void adl_rt_bankChangeLSB(IntPtr device, byte channel, byte lsb); + /// + /// Change LSB of the bank number (Alias to CC-32 event) + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// LSB value of the MIDI bank number + /// + [DllImport(LibraryName)] + public static extern void adl_rt_bankChangeLSB(IntPtr device, byte channel, byte lsb); - /// - /// Change MSB of the bank (Alias to CC-0 event) - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// MSB value of the MIDI bank number - /// - [DllImport(LibraryName)] - public static extern void adl_rt_bankChangeMSB(IntPtr device, byte channel, byte msb); + /// + /// Change MSB of the bank (Alias to CC-0 event) + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// MSB value of the MIDI bank number + /// + [DllImport(LibraryName)] + public static extern void adl_rt_bankChangeMSB(IntPtr device, byte channel, byte msb); - /// - /// Change bank by absolute signed value - /// Instance of the library - /// Target MIDI channel [Between 0 and 16] - /// Bank number as concatenated signed 16-bit value of MSB and LSB parts. - /// + /// + /// Change bank by absolute signed value + /// Instance of the library + /// Target MIDI channel [Between 0 and 16] + /// Bank number as concatenated signed 16-bit value of MSB and LSB parts. + /// - [DllImport(LibraryName)] - public static extern void adl_rt_bankChange(IntPtr device, byte channel, short bank); + [DllImport(LibraryName)] + public static extern void adl_rt_bankChange(IntPtr device, byte channel, short bank); - /// - /// Perform a system exclusive message - /// Instance of the library - /// Raw SysEx message buffer (must begin with 0xF0 and end with 0xF7) - /// Size of given SysEx message buffer - /// 1 when SysEx message was successfully processed, 0 when SysEx message was rejected for any reason - /// - [DllImport(LibraryName)] - public static extern unsafe int adl_rt_systemExclusive(IntPtr device, byte* message, UIntPtr size); + /// + /// Perform a system exclusive message + /// Instance of the library + /// Raw SysEx message buffer (must begin with 0xF0 and end with 0xF7) + /// Size of given SysEx message buffer + /// 1 when SysEx message was successfully processed, 0 when SysEx message was rejected for any reason + /// + [DllImport(LibraryName)] + public static extern unsafe int adl_rt_systemExclusive(IntPtr device, byte* message, UIntPtr size); - #endregion + #endregion - #region Hooks and debugging + #region Hooks and debugging - /// - /// Set raw MIDI event hook - /// Instance of the library - /// Pointer to the callback function which will be called on every MIDI event - /// Pointer to user data which will be passed through the callback. - /// - [DllImport(LibraryName)] - public static extern void adl_setRawEventHook(IntPtr device, RawEventHook rawEventHook, IntPtr userData); + /// + /// Set raw MIDI event hook + /// Instance of the library + /// Pointer to the callback function which will be called on every MIDI event + /// Pointer to user data which will be passed through the callback. + /// + [DllImport(LibraryName)] + public static extern void adl_setRawEventHook(IntPtr device, RawEventHook rawEventHook, IntPtr userData); - /// - /// Set note hook - /// Instance of the library - /// Pointer to the callback function which will be called on every noteOn MIDI event - /// Pointer to user data which will be passed through the callback. - /// - [DllImport(LibraryName)] - public static extern void adl_setNoteHook(IntPtr device, NoteHook noteHook, IntPtr userData); + /// + /// Set note hook + /// Instance of the library + /// Pointer to the callback function which will be called on every noteOn MIDI event + /// Pointer to user data which will be passed through the callback. + /// + [DllImport(LibraryName)] + public static extern void adl_setNoteHook(IntPtr device, NoteHook noteHook, IntPtr userData); #if false // Variadic delegate, ahh! Will worry about it if and when I need it. /// @@ -948,30 +946,27 @@ public struct AdlVersion [DllImport(LibraryName)] public static extern void adl_setDebugMessageHook(IntPtr device, DebugMessageHook debugMessageHook, IntPtr userData); #endif - /// - /// Get a textual description of the channel state. For display only. - /// Instance of the library - /// Destination char buffer for channel usage state. Every entry is assigned to the chip channel. - /// Destination char buffer for additional attributes like MIDI channel number that uses this chip channel. - /// Size of given buffers (both text and attr are must have same size!) - /// 0 on success, <0 when any error has occurred - /// - /// Every character in the `text` buffer means the type of usage: - /// ``` - /// `-` - channel is unused (free) - /// `+` - channel is used by two-operator voice - /// `#` - channel is used by four-operator voice - /// `@` - channel is used to play automatic arpeggio on chip channels overflow - /// `r` - rhythm-mode channel note - /// ``` - /// - /// The `attr` field receives the MIDI channel from which the chip channel is used. - /// To get the valid MIDI channel you will need to apply the & 0x0F mask to every value. - /// - [DllImport(LibraryName)] - public static extern int adl_describeChannels(IntPtr device, string text, string attr, UIntPtr size); - #endregion - } + /// + /// Get a textual description of the channel state. For display only. + /// Instance of the library + /// Destination char buffer for channel usage state. Every entry is assigned to the chip channel. + /// Destination char buffer for additional attributes like MIDI channel number that uses this chip channel. + /// Size of given buffers (both text and attr are must have same size!) + /// 0 on success, <0 when any error has occurred + /// + /// Every character in the `text` buffer means the type of usage: + /// ``` + /// `-` - channel is unused (free) + /// `+` - channel is used by two-operator voice + /// `#` - channel is used by four-operator voice + /// `@` - channel is used to play automatic arpeggio on chip channels overflow + /// `r` - rhythm-mode channel note + /// ``` + /// + /// The `attr` field receives the MIDI channel from which the chip channel is used. + /// To get the valid MIDI channel you will need to apply the & 0x0F mask to every value. + /// + [DllImport(LibraryName)] + public static extern int adl_describeChannels(IntPtr device, string text, string attr, UIntPtr size); + #endregion } -#pragma warning restore CS0626 // Method, operator, or accessor is marked external and has no attributes on it -#pragma warning restore IDE1006 // Naming Styles diff --git a/src/AudioFormat.cs b/src/AudioFormat.cs index f376bb8..58e13c0 100644 --- a/src/AudioFormat.cs +++ b/src/AudioFormat.cs @@ -1,15 +1,14 @@ using System.Runtime.InteropServices; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// Sound output format context +/// +[StructLayout(LayoutKind.Sequential)] +public struct AudioFormat { - /// - /// Sound output format context - /// - [StructLayout(LayoutKind.Sequential)] - public struct AudioFormat - { - public SampleType Type; // type of sample - public uint ContainerSize; // size in bytes of the storage type - public uint SampleOffset; // distance in bytes between consecutive samples - } -} + public SampleType Type; // type of sample + public uint ContainerSize; // size in bytes of the storage type + public uint SampleOffset; // distance in bytes between consecutive samples +} \ No newline at end of file diff --git a/src/Bank.cs b/src/Bank.cs index 7cc970f..0a9ba1c 100644 --- a/src/Bank.cs +++ b/src/Bank.cs @@ -1,47 +1,46 @@ using System; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +public class Bank { - public class Bank + readonly IntPtr _device; + AdlMidiImports.Bank _bank; + + internal Bank(IntPtr device, AdlMidiImports.Bank bank) + { + _device = device; + _bank = bank; + } + + public BankId GetBankId() + { + var result = AdlMidiImports.adl_getBankId(_device, ref _bank, out var id); + if(result < 0) + throw new InvalidOperationException(); + return id; + } + + public int RemoveBank() + { + return AdlMidiImports.adl_removeBank(_device, ref _bank); + } + + public Instrument GetInstrument(uint index) + { + var result = AdlMidiImports.adl_getInstrument(_device, ref _bank, index, out var instrument); + if(result < 0) + throw new InvalidOperationException(); + return instrument; + } + + public int SetInstrument(uint index, ref Instrument ins) + { + return AdlMidiImports.adl_setInstrument(_device, ref _bank, index, ref ins); + } + + public int LoadEmbeddedBank(int num) { - readonly IntPtr _device; - AdlMidiImports.Bank _bank; - - internal Bank(IntPtr device, AdlMidiImports.Bank bank) - { - _device = device; - _bank = bank; - } - - public BankId GetBankId() - { - var result = AdlMidiImports.adl_getBankId(_device, ref _bank, out var id); - if(result < 0) - throw new InvalidOperationException(); - return id; - } - - public int RemoveBank() - { - return AdlMidiImports.adl_removeBank(_device, ref _bank); - } - - public Instrument GetInstrument(uint index) - { - var result = AdlMidiImports.adl_getInstrument(_device, ref _bank, index, out var instrument); - if(result < 0) - throw new InvalidOperationException(); - return instrument; - } - - public int SetInstrument(uint index, ref Instrument ins) - { - return AdlMidiImports.adl_setInstrument(_device, ref _bank, index, ref ins); - } - - public int LoadEmbeddedBank(int num) - { - return AdlMidiImports.adl_loadEmbeddedBank(_device, ref _bank, num); - } + return AdlMidiImports.adl_loadEmbeddedBank(_device, ref _bank, num); } } \ No newline at end of file diff --git a/src/BankAccessFlags.cs b/src/BankAccessFlags.cs index e98ad93..0e16a06 100644 --- a/src/BankAccessFlags.cs +++ b/src/BankAccessFlags.cs @@ -1,11 +1,10 @@ -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// Flags for dynamic bank access +/// +public enum BankAccessFlags { - /// - /// Flags for dynamic bank access - /// - public enum BankAccessFlags - { - Create = 1, // create bank, allocating memory as needed - CreateRt = 1 | 2 // create bank, never allocating memory - } -} + Create = 1, // create bank, allocating memory as needed + CreateRt = 1 | 2 // create bank, never allocating memory +} \ No newline at end of file diff --git a/src/BankId.cs b/src/BankId.cs index ed44927..a09d5db 100644 --- a/src/BankId.cs +++ b/src/BankId.cs @@ -1,15 +1,14 @@ using System.Runtime.InteropServices; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// Identifier of dynamic bank +/// +[StructLayout(LayoutKind.Sequential)] +public struct BankId { - /// - /// Identifier of dynamic bank - /// - [StructLayout(LayoutKind.Sequential)] - public struct BankId - { - public byte Percussive; // 0 if bank is melodic set, or 1 if bank is a percussion set - public byte Msb; // Assign to MSB bank number - public byte Lsb; // Assign to LSB bank number - } -} + public byte Percussive; // 0 if bank is melodic set, or 1 if bank is a percussion set + public byte Msb; // Assign to MSB bank number + public byte Lsb; // Assign to LSB bank number +} \ No newline at end of file diff --git a/src/Emulator.cs b/src/Emulator.cs index 4671ef8..103b42b 100644 --- a/src/Emulator.cs +++ b/src/Emulator.cs @@ -1,15 +1,14 @@ -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// List of available OPL3 emulators +/// +public enum Emulator { - /// - /// List of available OPL3 emulators - /// - public enum Emulator - { - Nuked = 0, // Nuked OPL3 v. 1.8 - Nuked174, // Nuked OPL3 v. 1.7.4 - DosBox, // DosBox - Opal, // Opal - Java, // Java - End // Count instrument on the level - } -} + Nuked = 0, // Nuked OPL3 v. 1.8 + Nuked174, // Nuked OPL3 v. 1.7.4 + DosBox, // DosBox + Opal, // Opal + Java, // Java + End // Count instrument on the level +} \ No newline at end of file diff --git a/src/GlobalBankFlags.cs b/src/GlobalBankFlags.cs index 8215aaa..d06da33 100644 --- a/src/GlobalBankFlags.cs +++ b/src/GlobalBankFlags.cs @@ -1,11 +1,10 @@ using System; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +[Flags] +public enum GlobalBankFlags : byte { - [Flags] - public enum GlobalBankFlags : byte - { - DeepTremolo = 1, - DeepVibrato = 2, - } + DeepTremolo = 1, + DeepVibrato = 2, } \ No newline at end of file diff --git a/src/GlobalTimbreLibrary.cs b/src/GlobalTimbreLibrary.cs index ec654ee..e1e588a 100644 --- a/src/GlobalTimbreLibrary.cs +++ b/src/GlobalTimbreLibrary.cs @@ -2,87 +2,86 @@ using System.Collections.Generic; using SerdesNet; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +class TimbreHeader { - class TimbreHeader + public const int Size = 6; + public byte MidiPatchNumber { get; set; } + public byte MidiBankNumber { get; set; } + public uint InstrumentDataOffset { get; set; } + public bool IsSentinel => MidiPatchNumber == 0xff && MidiBankNumber == 0xff; + + public static TimbreHeader Serdes(TimbreHeader header, ISerdes s) { - public const int Size = 6; - public byte MidiPatchNumber { get; set; } - public byte MidiBankNumber { get; set; } - public uint InstrumentDataOffset { get; set; } - public bool IsSentinel => MidiPatchNumber == 0xff && MidiBankNumber == 0xff; + if (s == null) throw new ArgumentNullException(nameof(s)); + header ??= new TimbreHeader(); + header.MidiPatchNumber = s.UInt8(nameof(MidiPatchNumber), header.MidiPatchNumber); + header.MidiBankNumber = s.UInt8(nameof(MidiBankNumber), header.MidiBankNumber); - public static TimbreHeader Serdes(TimbreHeader header, ISerializer s) + if (header.IsSentinel) { - if (s == null) throw new ArgumentNullException(nameof(s)); - header ??= new TimbreHeader(); - header.MidiPatchNumber = s.UInt8(nameof(MidiPatchNumber), header.MidiPatchNumber); - header.MidiBankNumber = s.UInt8(nameof(MidiBankNumber), header.MidiBankNumber); - - if (header.IsSentinel) - { - header.InstrumentDataOffset = 0; - return header; - } - - header.InstrumentDataOffset = s.UInt32(nameof(InstrumentDataOffset), header.InstrumentDataOffset); + header.InstrumentDataOffset = 0; return header; } + + header.InstrumentDataOffset = s.UInt32(nameof(InstrumentDataOffset), header.InstrumentDataOffset); + return header; } +} - public class GlobalTimbreLibrary // Load and save .OPL / .AD files from AIL / Miles Sound System +public class GlobalTimbreLibrary // Load and save .OPL / .AD files from AIL / Miles Sound System +{ + public IList Data { get; } = new List(); + public static GlobalTimbreLibrary Serdes(GlobalTimbreLibrary library, ISerdes s) { - public IList Data { get; } = new List(); - public static GlobalTimbreLibrary Serdes(GlobalTimbreLibrary library, ISerializer s) - { - if (s == null) throw new ArgumentNullException(nameof(s)); - library ??= new GlobalTimbreLibrary(); - var start = s.Offset; + if (s == null) throw new ArgumentNullException(nameof(s)); + library ??= new GlobalTimbreLibrary(); + var start = s.Offset; - IList headers = new List(); - if (s.IsReading()) + IList headers = new List(); + if (s.IsReading()) + { + TimbreHeader header; + do { - TimbreHeader header; - do - { - header = TimbreHeader.Serdes(null, s); - headers.Add(header); - } while (!header.IsSentinel); - } - else + header = TimbreHeader.Serdes(null, s); + headers.Add(header); + } while (!header.IsSentinel); + } + else + { + uint offset = (uint)(start + TimbreHeader.Size * library.Data.Count + 2); + foreach (var data in library.Data) { - uint offset = (uint)(start + TimbreHeader.Size * library.Data.Count + 2); - foreach (var data in library.Data) + var header = new TimbreHeader { - var header = new TimbreHeader - { - MidiPatchNumber = data.MidiPatchNumber, - MidiBankNumber = data.MidiBankNumber, - InstrumentDataOffset = offset - }; - - TimbreHeader.Serdes(header, s); - headers.Add(header); - offset += data.Length; - } + MidiPatchNumber = data.MidiPatchNumber, + MidiBankNumber = data.MidiBankNumber, + InstrumentDataOffset = offset + }; - // Write sentinel - TimbreHeader.Serdes(new TimbreHeader - { - MidiPatchNumber = 0xff, - MidiBankNumber = 0xff, - }, s); + TimbreHeader.Serdes(header, s); + headers.Add(header); + offset += data.Length; } - s.List(nameof(library.Data), library.Data, headers.Count - 1, TimbreData.Serdes); - for (int i = 0; i < headers.Count - 1; i++) + // Write sentinel + TimbreHeader.Serdes(new TimbreHeader { - library.Data[i].MidiPatchNumber = headers[i].MidiPatchNumber; - library.Data[i].MidiBankNumber = headers[i].MidiBankNumber; - } + MidiPatchNumber = 0xff, + MidiBankNumber = 0xff, + }, s); + } - return library; + s.List(nameof(library.Data), library.Data, headers.Count - 1, TimbreData.Serdes); + for (int i = 0; i < headers.Count - 1; i++) + { + library.Data[i].MidiPatchNumber = headers[i].MidiPatchNumber; + library.Data[i].MidiBankNumber = headers[i].MidiBankNumber; } + + return library; } -} +} \ No newline at end of file diff --git a/src/Instrument.cs b/src/Instrument.cs index be0c762..b1d13b6 100644 --- a/src/Instrument.cs +++ b/src/Instrument.cs @@ -1,27 +1,26 @@ using System.Runtime.InteropServices; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// Instrument structure +/// +[StructLayout(LayoutKind.Sequential)] +public struct Instrument { - /// - /// Instrument structure - /// - [StructLayout(LayoutKind.Sequential)] - public struct Instrument - { - public int Version; // Version of the instrument object - public short NoteOffset1; // MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) - public short NoteOffset2; // MIDI note key (half-tone) offset for a second voice in pseudo-4-op mode - public sbyte MidiVelocityOffset; // MIDI note velocity offset (taken from Apogee TMB format) - public sbyte SecondVoiceDetune; // Second voice detune level (taken from DMX OP2) - public byte PercussionKeyNumber; // Percussion MIDI base tone number at which this drum will be played - public byte Flags; // Packed bitfield containing instrument and rhythm modes - public Modulation FbConn1C0; // Feedback & Connection register for first and second operators - public Modulation FbConn2C0; // Feedback & Connection register for third and fourth operators - public Operator Operator0; // Operators register data - public Operator Operator1; - public Operator Operator2; - public Operator Operator3; - public ushort DelayOnMs; // Millisecond delay of sounding while key is on - public ushort DelayOffMs; // Millisecond delay of sounding after key off - } -} + public int Version; // Version of the instrument object + public short NoteOffset1; // MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) + public short NoteOffset2; // MIDI note key (half-tone) offset for a second voice in pseudo-4-op mode + public sbyte MidiVelocityOffset; // MIDI note velocity offset (taken from Apogee TMB format) + public sbyte SecondVoiceDetune; // Second voice detune level (taken from DMX OP2) + public byte PercussionKeyNumber; // Percussion MIDI base tone number at which this drum will be played + public byte Flags; // Packed bitfield containing instrument and rhythm modes + public Modulation FbConn1C0; // Feedback & Connection register for first and second operators + public Modulation FbConn2C0; // Feedback & Connection register for third and fourth operators + public Operator Operator0; // Operators register data + public Operator Operator1; + public Operator Operator2; + public Operator Operator3; + public ushort DelayOnMs; // Millisecond delay of sounding while key is on + public ushort DelayOffMs; // Millisecond delay of sounding after key off +} \ No newline at end of file diff --git a/src/InstrumentFlags.cs b/src/InstrumentFlags.cs index 6372115..111bcf0 100644 --- a/src/InstrumentFlags.cs +++ b/src/InstrumentFlags.cs @@ -1,10 +1,9 @@ -namespace ADLMidi.NET +namespace ADLMidi.NET; + +public enum InstrumentMode { - public enum InstrumentMode - { - TwoOperator = 0, - FourOperator = 1, - PseudoFourOperator = 2, - Blank = 4 - } -} + TwoOperator = 0, + FourOperator = 1, + PseudoFourOperator = 2, + Blank = 4 +} \ No newline at end of file diff --git a/src/MarkerEntry.cs b/src/MarkerEntry.cs index 76d6646..3d300c1 100644 --- a/src/MarkerEntry.cs +++ b/src/MarkerEntry.cs @@ -1,15 +1,14 @@ using System.Runtime.InteropServices; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// MIDI Marker structure +/// +[StructLayout(LayoutKind.Sequential)] +public struct MarkerEntry { - /// - /// MIDI Marker structure - /// - [StructLayout(LayoutKind.Sequential)] - public struct MarkerEntry - { - public string Label; // MIDI Marker title - public double PosTime; // Absolute time position of the marker in seconds - public uint PosTicks; // Absolute time position of the marker in MIDI ticks - } -} + public string Label; // MIDI Marker title + public double PosTime; // Absolute time position of the marker in seconds + public uint PosTicks; // Absolute time position of the marker in MIDI ticks +} \ No newline at end of file diff --git a/src/MidiPlayer.cs b/src/MidiPlayer.cs index 19380f3..c428400 100644 --- a/src/MidiPlayer.cs +++ b/src/MidiPlayer.cs @@ -1,153 +1,153 @@ using System; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +public sealed class MidiPlayer : IDisposable { - public sealed class MidiPlayer : IDisposable - { - readonly IntPtr _device; + readonly IntPtr _device; - int Check(int result) - { - if (result >= 0) - return result; + int Check(int result) + { + if (result >= 0) + return result; - var error = AdlMidiImports.adl_errorInfo(_device); - throw new InvalidOperationException(error); - } + var error = AdlMidiImports.adl_errorInfo(_device); + throw new InvalidOperationException(error); + } - public MidiPlayer(IntPtr device) - { - _device = device; - } + public MidiPlayer(IntPtr device) + { + _device = device; + } - public void OpenFile(string filePath) => Check(AdlMidiImports.adl_openFile(_device, filePath)); - public unsafe void OpenData(ReadOnlySpan data) + public void OpenFile(string filePath) => Check(AdlMidiImports.adl_openFile(_device, filePath)); + public unsafe void OpenData(ReadOnlySpan data) + { + fixed (byte* ptr = data) { - fixed (byte* ptr = data) - { - Check(AdlMidiImports.adl_openData(_device, ptr, (uint)data.Length)); - } + Check(AdlMidiImports.adl_openData(_device, ptr, (uint)data.Length)); } + } - public void Dispose() - { - if (_device != IntPtr.Zero) - Close(); - } + public void Dispose() + { + if (_device != IntPtr.Zero) + Close(); + } - public void Close() => AdlMidiImports.adl_close(_device); - public void Reset() => AdlMidiImports.adl_reset(_device); + public void Close() => AdlMidiImports.adl_close(_device); + public void Reset() => AdlMidiImports.adl_reset(_device); - public int NumChips - { - get => AdlMidiImports.adl_getNumChips(_device); - set => AdlMidiImports.adl_setNumChips(_device, value); - } - public int NumChipsObtained => AdlMidiImports.adl_getNumChipsObtained(_device); + public int NumChips + { + get => AdlMidiImports.adl_getNumChips(_device); + set => AdlMidiImports.adl_setNumChips(_device, value); + } + public int NumChipsObtained => AdlMidiImports.adl_getNumChipsObtained(_device); - public int NumFourOpsChn - { - get => AdlMidiImports.adl_getNumFourOpsChn(_device); - set => AdlMidiImports.adl_setNumFourOpsChn(_device, value); - } - public int NumFourOpsChnObtained => AdlMidiImports.adl_getNumFourOpsChnObtained(_device); + public int NumFourOpsChn + { + get => AdlMidiImports.adl_getNumFourOpsChn(_device); + set => AdlMidiImports.adl_setNumFourOpsChn(_device, value); + } + public int NumFourOpsChnObtained => AdlMidiImports.adl_getNumFourOpsChnObtained(_device); - public int Vibrato - { - get => AdlMidiImports.adl_getHVibrato(_device); - set => AdlMidiImports.adl_setHVibrato(_device, value); - } + public int Vibrato + { + get => AdlMidiImports.adl_getHVibrato(_device); + set => AdlMidiImports.adl_setHVibrato(_device, value); + } - public int Tremolo - { - get => AdlMidiImports.adl_getHTremolo(_device); - set => AdlMidiImports.adl_setHTremolo(_device, value); - } + public int Tremolo + { + get => AdlMidiImports.adl_getHTremolo(_device); + set => AdlMidiImports.adl_setHTremolo(_device, value); + } - public VolumeModel VolumeRangeModel - { - get => AdlMidiImports.adl_getVolumeRangeModel(_device); - set => AdlMidiImports.adl_setVolumeRangeModel(_device, value); - } + public VolumeModel VolumeRangeModel + { + get => AdlMidiImports.adl_getVolumeRangeModel(_device); + set => AdlMidiImports.adl_setVolumeRangeModel(_device, value); + } - public int ReserveBanks(uint banks) => AdlMidiImports.adl_reserveBanks(_device, banks); + public int ReserveBanks(uint banks) => AdlMidiImports.adl_reserveBanks(_device, banks); - public Bank GetBank(BankId id, BankAccessFlags flags) - { - Check(AdlMidiImports.adl_getBank(_device, ref id, flags, out var bank)); - return new Bank(_device, bank); - } - public void SetBank(int bank) => Check(AdlMidiImports.adl_setBank(_device, bank)); + public Bank GetBank(BankId id, BankAccessFlags flags) + { + Check(AdlMidiImports.adl_getBank(_device, ref id, flags, out var bank)); + return new Bank(_device, bank); + } + public void SetBank(int bank) => Check(AdlMidiImports.adl_setBank(_device, bank)); - public Bank GetFirstBank() - { - Check(AdlMidiImports.adl_getFirstBank(_device, out var bank)); - return new Bank(_device, bank); - } + public Bank GetFirstBank() + { + Check(AdlMidiImports.adl_getFirstBank(_device, out var bank)); + return new Bank(_device, bank); + } - public Bank GetNextBank() - { - Check(AdlMidiImports.adl_getNextBank(_device, out var bank)); - return new Bank(_device, bank); - } + public Bank GetNextBank() + { + Check(AdlMidiImports.adl_getNextBank(_device, out var bank)); + return new Bank(_device, bank); + } - public void OpenBankFile(string filePath) => Check(AdlMidiImports.adl_openBankFile(_device, filePath)); - public unsafe void OpenBankData(ReadOnlySpan bankData) + public void OpenBankFile(string filePath) => Check(AdlMidiImports.adl_openBankFile(_device, filePath)); + public unsafe void OpenBankData(ReadOnlySpan bankData) + { + fixed (byte* data = bankData) { - fixed (byte* data = bankData) - { - Check(AdlMidiImports.adl_openBankData(_device, data, (uint)bankData.Length)); - } + Check(AdlMidiImports.adl_openBankData(_device, data, (uint)bankData.Length)); } + } - public void SetScaleModulators(int modulatorVolumeScaling) => AdlMidiImports.adl_setScaleModulators(_device, modulatorVolumeScaling); - public void SetFullRangeBrightness(int fullRangeBrightness) => AdlMidiImports.adl_setFullRangeBrightness(_device, fullRangeBrightness); - public void SetLoopEnabled(bool loopEnabled) => AdlMidiImports.adl_setLoopEnabled(_device, loopEnabled); - public void SetSoftPanEnabled(bool softPanEnabled) => AdlMidiImports.adl_setSoftPanEnabled(_device, softPanEnabled); - public string ChipEmulatorName() => AdlMidiImports.adl_chipEmulatorName(_device); - public void SwitchEmulator(Emulator emulator) => Check(AdlMidiImports.adl_switchEmulator(_device, emulator)); - public void SetRunAtPcmRate(bool enabled) => Check(AdlMidiImports.adl_setRunAtPcmRate(_device, enabled)); - public void SetDeviceIdentifier(uint id) => Check(AdlMidiImports.adl_setDeviceIdentifier(_device, id)); - - public string ErrorInfo() => AdlMidiImports.adl_errorInfo(_device); - public double TotalTimeLength() => AdlMidiImports.adl_totalTimeLength(_device); - public double LoopStartTime() => AdlMidiImports.adl_loopStartTime(_device); - public double LoopEndTime() => AdlMidiImports.adl_loopEndTime(_device); - public double PositionTell() => AdlMidiImports.adl_positionTell(_device); - public void PositionSeek(double seconds) => AdlMidiImports.adl_positionSeek(_device, seconds); - public void PositionRewind() => AdlMidiImports.adl_positionRewind(_device); - public void SetTempo(double tempo) => AdlMidiImports.adl_setTempo(_device, tempo); - public int AtEnd() => AdlMidiImports.adl_atEnd(_device); - public UIntPtr TrackCount() => AdlMidiImports.adl_trackCount(_device); - public void SetTrackOptions(UIntPtr trackNumber, TrackOptions trackOptions) => Check(AdlMidiImports.adl_setTrackOptions(_device, trackNumber, trackOptions)); - // public int SetTriggerHandler(AdlMidiImports.TriggerHandler handler, IntPtr userData) => AdlMidiImports.adl_setTriggerHandler(_device, handler, userData); - public string MetaMusicTitle() => AdlMidiImports.adl_metaMusicTitle(_device); - public string MetaMusicCopyright() => AdlMidiImports.adl_metaMusicCopyright(_device); - public UIntPtr MetaTrackTitleCount() => AdlMidiImports.adl_metaTrackTitleCount(_device); - public string MetaTrackTitle(UIntPtr index) => AdlMidiImports.adl_metaTrackTitle(_device, index); - public UIntPtr MetaMarkerCount() => AdlMidiImports.adl_metaMarkerCount(_device); - public MarkerEntry MetaMarker(UIntPtr index) => AdlMidiImports.adl_metaMarker(_device, index); - public unsafe int Play(Span buffer) + public void SetScaleModulators(int modulatorVolumeScaling) => AdlMidiImports.adl_setScaleModulators(_device, modulatorVolumeScaling); + public void SetFullRangeBrightness(int fullRangeBrightness) => AdlMidiImports.adl_setFullRangeBrightness(_device, fullRangeBrightness); + public void SetLoopEnabled(bool loopEnabled) => AdlMidiImports.adl_setLoopEnabled(_device, loopEnabled); + public void SetSoftPanEnabled(bool softPanEnabled) => AdlMidiImports.adl_setSoftPanEnabled(_device, softPanEnabled); + public string ChipEmulatorName() => AdlMidiImports.adl_chipEmulatorName(_device); + public void SwitchEmulator(Emulator emulator) => Check(AdlMidiImports.adl_switchEmulator(_device, emulator)); + public void SetRunAtPcmRate(bool enabled) => Check(AdlMidiImports.adl_setRunAtPcmRate(_device, enabled)); + public void SetDeviceIdentifier(uint id) => Check(AdlMidiImports.adl_setDeviceIdentifier(_device, id)); + + public string ErrorInfo() => AdlMidiImports.adl_errorInfo(_device); + public double TotalTimeLength() => AdlMidiImports.adl_totalTimeLength(_device); + public double LoopStartTime() => AdlMidiImports.adl_loopStartTime(_device); + public double LoopEndTime() => AdlMidiImports.adl_loopEndTime(_device); + public double PositionTell() => AdlMidiImports.adl_positionTell(_device); + public void PositionSeek(double seconds) => AdlMidiImports.adl_positionSeek(_device, seconds); + public void PositionRewind() => AdlMidiImports.adl_positionRewind(_device); + public void SetTempo(double tempo) => AdlMidiImports.adl_setTempo(_device, tempo); + public int AtEnd() => AdlMidiImports.adl_atEnd(_device); + public UIntPtr TrackCount() => AdlMidiImports.adl_trackCount(_device); + public void SetTrackOptions(UIntPtr trackNumber, TrackOptions trackOptions) => Check(AdlMidiImports.adl_setTrackOptions(_device, trackNumber, trackOptions)); + // public int SetTriggerHandler(AdlMidiImports.TriggerHandler handler, IntPtr userData) => AdlMidiImports.adl_setTriggerHandler(_device, handler, userData); + public string MetaMusicTitle() => AdlMidiImports.adl_metaMusicTitle(_device); + public string MetaMusicCopyright() => AdlMidiImports.adl_metaMusicCopyright(_device); + public UIntPtr MetaTrackTitleCount() => AdlMidiImports.adl_metaTrackTitleCount(_device); + public string MetaTrackTitle(UIntPtr index) => AdlMidiImports.adl_metaTrackTitle(_device, index); + public UIntPtr MetaMarkerCount() => AdlMidiImports.adl_metaMarkerCount(_device); + public MarkerEntry MetaMarker(UIntPtr index) => AdlMidiImports.adl_metaMarker(_device, index); + public unsafe int Play(Span buffer) + { + fixed(short* p = buffer) { - fixed(short* p = buffer) - { - return Check(AdlMidiImports.adl_play(_device, buffer.Length, p)); - } + return Check(AdlMidiImports.adl_play(_device, buffer.Length, p)); } + } - public int PlayFormat(int sampleCount, IntPtr left, IntPtr right, ref AudioFormat format) => Check(AdlMidiImports.adl_playFormat(_device, sampleCount, left, right, ref format)); - public unsafe int Generate(Span buffer) + public int PlayFormat(int sampleCount, IntPtr left, IntPtr right, ref AudioFormat format) => Check(AdlMidiImports.adl_playFormat(_device, sampleCount, left, right, ref format)); + public unsafe int Generate(Span buffer) + { + fixed (short* ptr = buffer) { - fixed (short* ptr = buffer) - { - return Check(AdlMidiImports.adl_generate(_device, buffer.Length, ptr)); - } + return Check(AdlMidiImports.adl_generate(_device, buffer.Length, ptr)); } + } - public int GenerateFormat(int sampleCount, IntPtr left, IntPtr right, ref AudioFormat format) => Check(AdlMidiImports.adl_generateFormat(_device, sampleCount, left, right, ref format)); - public double TickEvents(double seconds, double granularity) => AdlMidiImports.adl_tickEvents(_device, seconds, granularity); - public void Panic() => AdlMidiImports.adl_panic(_device); - public void SetNoteHook(NoteHook noteHook, IntPtr userData) => AdlMidiImports.adl_setNoteHook(_device, noteHook, userData); + public int GenerateFormat(int sampleCount, IntPtr left, IntPtr right, ref AudioFormat format) => Check(AdlMidiImports.adl_generateFormat(_device, sampleCount, left, right, ref format)); + public double TickEvents(double seconds, double granularity) => AdlMidiImports.adl_tickEvents(_device, seconds, granularity); + public void Panic() => AdlMidiImports.adl_panic(_device); + public void SetNoteHook(NoteHook noteHook, IntPtr userData) => AdlMidiImports.adl_setNoteHook(_device, noteHook, userData); #if false public void RealTimeResetState() => AdlMidiImports.adl_rt_resetState(_device); @@ -169,6 +169,4 @@ public unsafe int Generate(Span buffer) public void SetRawEventHook(AdlMidiImports.RawEventHook rawEventHook, IntPtr userData) => AdlMidiImports.adl_setRawEventHook(_device, rawEventHook, userData); public int DescribeChannels(string text, string attr, UIntPtr size) => AdlMidiImports.adl_describeChannels(_device, text, attr, size); #endif - } -} - +} \ No newline at end of file diff --git a/src/Modulation.cs b/src/Modulation.cs index a7889b9..c41335a 100644 --- a/src/Modulation.cs +++ b/src/Modulation.cs @@ -1,22 +1,21 @@ using System; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +[Flags] +public enum Modulation : byte { - [Flags] - public enum Modulation : byte - { - // ReSharper disable InconsistentNaming - // Two operator: - FM = 0, - AM = 1, - // ReSharper restore InconsistentNaming + // ReSharper disable InconsistentNaming + // Two operator: + FM = 0, + AM = 1, + // ReSharper restore InconsistentNaming - Feedback1 = 2, - Feedback2 = 4, - Feedback3 = 6, - Feedback4 = 8, - Feedback5 = 10, - Feedback6 = 12, - Feedback7 = 14, - } + Feedback1 = 2, + Feedback2 = 4, + Feedback3 = 6, + Feedback4 = 8, + Feedback5 = 10, + Feedback6 = 12, + Feedback7 = 14, } \ No newline at end of file diff --git a/src/Operator.cs b/src/Operator.cs index 2e9d7e6..eb158b9 100644 --- a/src/Operator.cs +++ b/src/Operator.cs @@ -2,43 +2,42 @@ using System.Runtime.InteropServices; using SerdesNet; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// Operator structure, part of Instrument structure +/// +[StructLayout(LayoutKind.Sequential)] +public struct Operator { - /// - /// Operator structure, part of Instrument structure - /// - [StructLayout(LayoutKind.Sequential)] - public struct Operator - { - byte Z_KeyScaleLevel; // Key Scale Level / Total level register data - byte Z_AttackDecay; // Attack / Decay - byte Z_SustainRelease; // Sustain and Release register data + byte Z_KeyScaleLevel; // Key Scale Level / Total level register data + byte Z_AttackDecay; // Attack / Decay + byte Z_SustainRelease; // Sustain and Release register data - public OperatorFlags Flags; // AM/Vib/Env/Ksr/FMult characteristics - public Waveform Waveform; // Wave form + public OperatorFlags Flags; // AM/Vib/Env/Ksr/FMult characteristics + public Waveform Waveform; // Wave form - public int Attack => (Z_AttackDecay & 0xf0) >> 4; // 0..15 - public int Decay => Z_AttackDecay & 0x0f; // 0..15 - public int Sustain => 0xf - ((Z_SustainRelease & 0xf0) >> 4); // 0..15 - public int Release => Z_SustainRelease & 0x0f; // 0..15 - public int Level => (63 - Z_KeyScaleLevel) & 0x3f; // 0..63 - public int KeyScale => (Z_KeyScaleLevel & 0xc0) >> 6; // 0..3 - public int FreqMultiple => (int)Flags & 0xf; // 0..15 - public static Operator Blank => new() - { - Z_KeyScaleLevel = 63, - Z_SustainRelease = 240 - }; + public int Attack => (Z_AttackDecay & 0xf0) >> 4; // 0..15 + public int Decay => Z_AttackDecay & 0x0f; // 0..15 + public int Sustain => 0xf - ((Z_SustainRelease & 0xf0) >> 4); // 0..15 + public int Release => Z_SustainRelease & 0x0f; // 0..15 + public int Level => (63 - Z_KeyScaleLevel) & 0x3f; // 0..63 + public int KeyScale => (Z_KeyScaleLevel & 0xc0) >> 6; // 0..3 + public int FreqMultiple => (int)Flags & 0xf; // 0..15 + public static Operator Blank => new() + { + Z_KeyScaleLevel = 63, + Z_SustainRelease = 240 + }; - public static Operator Serdes(string _, Operator o, ISerializer s) - { - if (s == null) throw new ArgumentNullException(nameof(s)); - o.Flags = s.EnumU8(nameof(Flags), o.Flags); - o.Z_KeyScaleLevel = s.UInt8(nameof(Z_KeyScaleLevel), o.Z_KeyScaleLevel); - o.Z_AttackDecay = s.UInt8(nameof(Z_AttackDecay), o.Z_AttackDecay); - o.Z_SustainRelease = s.UInt8(nameof(Z_SustainRelease), o.Z_SustainRelease); - o.Waveform = s.EnumU8(nameof(Waveform), o.Waveform); - return o; - } + public static Operator Serdes(string _, Operator o, ISerdes s) + { + if (s == null) throw new ArgumentNullException(nameof(s)); + o.Flags = s.EnumU8(nameof(Flags), o.Flags); + o.Z_KeyScaleLevel = s.UInt8(nameof(Z_KeyScaleLevel), o.Z_KeyScaleLevel); + o.Z_AttackDecay = s.UInt8(nameof(Z_AttackDecay), o.Z_AttackDecay); + o.Z_SustainRelease = s.UInt8(nameof(Z_SustainRelease), o.Z_SustainRelease); + o.Waveform = s.EnumU8(nameof(Waveform), o.Waveform); + return o; } -} +} \ No newline at end of file diff --git a/src/OperatorFlags.cs b/src/OperatorFlags.cs index 0bcfdf2..939426c 100644 --- a/src/OperatorFlags.cs +++ b/src/OperatorFlags.cs @@ -1,29 +1,28 @@ using System; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +[Flags] +public enum OperatorFlags : byte { - [Flags] - public enum OperatorFlags : byte - { - Freq1 = 1, - Freq2 = 2, - Freq3 = 3, - Freq4 = 4, - Freq5 = 5, - Freq6 = 6, - Freq7 = 7, - Freq8 = 8, - Freq9 = 9, - Freq10 = 10, - Freq11 = 11, - Freq12 = 12, - Freq13 = 13, - Freq14 = 14, - Freq15 = 15, + Freq1 = 1, + Freq2 = 2, + Freq3 = 3, + Freq4 = 4, + Freq5 = 5, + Freq6 = 6, + Freq7 = 7, + Freq8 = 8, + Freq9 = 9, + Freq10 = 10, + Freq11 = 11, + Freq12 = 12, + Freq13 = 13, + Freq14 = 14, + Freq15 = 15, - EnvelopeScale = 0x10, // KSR - Sustain = 0x20, // EG - Vibrato = 0x40, // VIB - Tremolo = 0x80, // AM - } -} + EnvelopeScale = 0x10, // KSR + Sustain = 0x20, // EG + Vibrato = 0x40, // VIB + Tremolo = 0x80, // AM +} \ No newline at end of file diff --git a/src/RhythmMode.cs b/src/RhythmMode.cs index 4db6767..a69ac25 100644 --- a/src/RhythmMode.cs +++ b/src/RhythmMode.cs @@ -1,15 +1,14 @@ -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// Rhythm mode / drum type +/// +public enum RhythmMode { - /// - /// Rhythm mode / drum type - /// - public enum RhythmMode - { - Generic = 0, - Bass = 1, - Snare = 2, - Tom = 3, - Cymbal = 4, - HiHat = 5 - } -} + Generic = 0, + Bass = 1, + Snare = 2, + Tom = 3, + Cymbal = 4, + HiHat = 5 +} \ No newline at end of file diff --git a/src/SampleType.cs b/src/SampleType.cs index 3db9826..2d5b675 100644 --- a/src/SampleType.cs +++ b/src/SampleType.cs @@ -1,20 +1,19 @@ -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// Sound output format +/// +public enum SampleType { - /// - /// Sound output format - /// - public enum SampleType - { - S16 = 0, // signed PCM 16-bit - S8, // signed PCM 8-bit - F32, // float 32-bit - F64, // float 64-bit - S24, // signed PCM 24-bit - S32, // signed PCM 32-bit - U8, // unsigned PCM 8-bit - U16, // unsigned PCM 16-bit - U24, // unsigned PCM 24-bit - U32, // unsigned PCM 32-bit - Count // Count of available sample format types - } -} + S16 = 0, // signed PCM 16-bit + S8, // signed PCM 8-bit + F32, // float 32-bit + F64, // float 64-bit + S24, // signed PCM 24-bit + S32, // signed PCM 32-bit + U8, // unsigned PCM 8-bit + U16, // unsigned PCM 16-bit + U24, // unsigned PCM 24-bit + U32, // unsigned PCM 32-bit + Count // Count of available sample format types +} \ No newline at end of file diff --git a/src/TimbreData.cs b/src/TimbreData.cs index 157140e..b26f5a1 100644 --- a/src/TimbreData.cs +++ b/src/TimbreData.cs @@ -1,33 +1,32 @@ using System; using SerdesNet; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +public class TimbreData { - public class TimbreData - { - public override string ToString() - => $"F:{FeedbackConnection} {Carrier.Attack}:{Carrier.Decay} {Carrier.Sustain}:{Carrier.Release} {Carrier.Waveform} {Carrier.Flags} {Carrier.Level} {Modulation.Attack}:{Modulation.Decay} {Modulation.Sustain}:{Modulation.Release} {Modulation.Waveform} {Modulation.Flags} {Modulation.Level}"; + public override string ToString() + => $"F:{FeedbackConnection} {Carrier.Attack}:{Carrier.Decay} {Carrier.Sustain}:{Carrier.Release} {Carrier.Waveform} {Carrier.Flags} {Carrier.Level} {Modulation.Attack}:{Modulation.Decay} {Modulation.Sustain}:{Modulation.Release} {Modulation.Waveform} {Modulation.Flags} {Modulation.Level}"; - public byte MidiPatchNumber { get; set; } // From header - public byte MidiBankNumber { get; set; } + public byte MidiPatchNumber { get; set; } // From header + public byte MidiBankNumber { get; set; } - public ushort Length { get; set; } // Struct length, including the length field itself. Value is always 14 for OPL2 instruments, and 25(?) for OPL3. - public byte Transpose { get; set; } // ! Precise meaning unknown - public Modulation FeedbackConnection { get; set; } // Feedback/connection + public ushort Length { get; set; } // Struct length, including the length field itself. Value is always 14 for OPL2 instruments, and 25(?) for OPL3. + public byte Transpose { get; set; } // ! Precise meaning unknown + public Modulation FeedbackConnection { get; set; } // Feedback/connection - public Operator Modulation { get; set; } - public Operator Carrier { get; set; } + public Operator Modulation { get; set; } + public Operator Carrier { get; set; } - public static TimbreData Serdes(int _, TimbreData data, ISerializer s) - { - if (s == null) throw new ArgumentNullException(nameof(s)); - data ??= new TimbreData(); - data.Length = s.UInt16(nameof(Length), data.Length); - data.Transpose = s.UInt8(nameof(Transpose), data.Transpose); - data.Modulation = s.Object(nameof(data.Modulation), data.Modulation, Operator.Serdes); - data.FeedbackConnection = s.EnumU8(nameof(FeedbackConnection), data.FeedbackConnection); - data.Carrier = s.Object(nameof(data.Carrier), data.Carrier, Operator.Serdes); - return data; - } + public static TimbreData Serdes(int _, TimbreData data, ISerdes s) + { + if (s == null) throw new ArgumentNullException(nameof(s)); + data ??= new TimbreData(); + data.Length = s.UInt16(nameof(Length), data.Length); + data.Transpose = s.UInt8(nameof(Transpose), data.Transpose); + data.Modulation = s.Object(nameof(data.Modulation), data.Modulation, Operator.Serdes); + data.FeedbackConnection = s.EnumU8(nameof(FeedbackConnection), data.FeedbackConnection); + data.Carrier = s.Object(nameof(data.Carrier), data.Carrier, Operator.Serdes); + return data; } -} +} \ No newline at end of file diff --git a/src/TrackOptions.cs b/src/TrackOptions.cs index f5d91eb..7df8cd3 100644 --- a/src/TrackOptions.cs +++ b/src/TrackOptions.cs @@ -1,12 +1,11 @@ -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// Track options +/// +public enum TrackOptions { - /// - /// Track options - /// - public enum TrackOptions - { - On = 1, // Enabled track - Off = 2, // Disabled track - Solo = 3 // Solo track - } -} + On = 1, // Enabled track + Off = 2, // Disabled track + Solo = 3 // Solo track +} \ No newline at end of file diff --git a/src/VolumeModel.cs b/src/VolumeModel.cs index a4615bb..d3ce2a4 100644 --- a/src/VolumeModel.cs +++ b/src/VolumeModel.cs @@ -1,16 +1,15 @@ -namespace ADLMidi.NET +namespace ADLMidi.NET; + +/// +/// Volume scaling models +/// +public enum VolumeModel : byte { - /// - /// Volume scaling models - /// - public enum VolumeModel : byte - { - Auto = 0, // Automatically chosen by the specific bank // / - Generic = 1, // Linearized scaling model, most standard // / - NativeOpl3 = 2, // Native OPL3's logarithmic volume scale // / - Cmf = 2, // Native OPL3's logarithmic volume scale. Alias. // / - Dmx = 3, // Logarithmic volume scale, using volume map table. Used in DMX. // / - Apogee = 4, // Logarithmic volume scale, used in Apogee Sound System. // / - NineX = 5 // Approximated and shorted volume map table. Similar to general, but has less granularity. // / - } -} + Auto = 0, // Automatically chosen by the specific bank // / + Generic = 1, // Linearized scaling model, most standard // / + NativeOpl3 = 2, // Native OPL3's logarithmic volume scale // / + Cmf = 2, // Native OPL3's logarithmic volume scale. Alias. // / + Dmx = 3, // Logarithmic volume scale, using volume map table. Used in DMX. // / + Apogee = 4, // Logarithmic volume scale, used in Apogee Sound System. // / + NineX = 5 // Approximated and shorted volume map table. Similar to general, but has less granularity. // / +} \ No newline at end of file diff --git a/src/Waveform.cs b/src/Waveform.cs index 3e5f1aa..99f13a8 100644 --- a/src/Waveform.cs +++ b/src/Waveform.cs @@ -1,14 +1,13 @@ -namespace ADLMidi.NET +namespace ADLMidi.NET; + +public enum Waveform : byte { - public enum Waveform : byte - { - Sine = 0, - HalfSine, - AbsSine, - PulseSine, - SineEvenPeriods, - AbsSineEventPeriods, - Square, - DerivedSquare - } + Sine = 0, + HalfSine, + AbsSine, + PulseSine, + SineEvenPeriods, + AbsSineEventPeriods, + Square, + DerivedSquare } \ No newline at end of file diff --git a/src/WoplBank.cs b/src/WoplBank.cs index 79ea4b7..78c89b5 100644 --- a/src/WoplBank.cs +++ b/src/WoplBank.cs @@ -1,23 +1,22 @@ -namespace ADLMidi.NET +namespace ADLMidi.NET; + +public class WoplBank { - public class WoplBank - { - public const int BankSize = 128; - public const int MaxNameLength = 32; - string _name; + public const int BankSize = 128; + public const int MaxNameLength = 32; + string _name; - public ushort Id { get; set; } - public string Name + public ushort Id { get; set; } + public string Name + { + get => _name; + set { - get => _name; - set - { - _name = (value ?? ""); - if (_name.Length > MaxNameLength) - _name = _name.Substring(0, MaxNameLength); - } - + _name = (value ?? ""); + if (_name.Length > MaxNameLength) + _name = _name.Substring(0, MaxNameLength); } - public WoplInstrument[] Instruments { get; } = new WoplInstrument[BankSize]; + } + public WoplInstrument[] Instruments { get; } = new WoplInstrument[BankSize]; } \ No newline at end of file diff --git a/src/WoplFile.cs b/src/WoplFile.cs index afba4d9..88d1cfa 100644 --- a/src/WoplFile.cs +++ b/src/WoplFile.cs @@ -4,108 +4,107 @@ using System.Text; using SerdesNet; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +public class WoplFile { - public class WoplFile - { - const string Magic = "WOPL3-BANK"; - public IList Melodic { get; } = new List(); - public IList Percussion { get; } = new List(); + const string Magic = "WOPL3-BANK"; + public IList Melodic { get; } = new List(); + public IList Percussion { get; } = new List(); - public static WoplFile Serdes(WoplFile w, ISerializer s) - { - if (s == null) throw new ArgumentNullException(nameof(s)); - w ??= new WoplFile(); + public static WoplFile Serdes(WoplFile w, ISerdes s) + { + if (s == null) throw new ArgumentNullException(nameof(s)); + w ??= new WoplFile(); - ushort melodicBanks = (ushort)w.Melodic.Count; - ushort percussionBanks = (ushort)w.Percussion.Count; + ushort melodicBanks = (ushort)w.Melodic.Count; + ushort percussionBanks = (ushort)w.Percussion.Count; - var magic = s.NullTerminatedString(nameof(Magic), Magic); - if(magic != Magic) - throw new InvalidOperationException("Magic string missing (invalid WOPL file)"); + var magic = s.NullTerminatedString(nameof(Magic), Magic); + if(magic != Magic) + throw new InvalidOperationException("Magic string missing (invalid WOPL file)"); - w.Version = s.UInt16(nameof(Version), w.Version); - melodicBanks = s.UInt16BE(nameof(melodicBanks), melodicBanks); - percussionBanks = s.UInt16BE(nameof(percussionBanks), percussionBanks); - w.GlobalFlags = s.EnumU8(nameof(GlobalFlags), w.GlobalFlags); - w.VolumeModel = s.EnumU8(nameof(VolumeModel), w.VolumeModel); + w.Version = s.UInt16(nameof(Version), w.Version); + melodicBanks = s.UInt16BE(nameof(melodicBanks), melodicBanks); + percussionBanks = s.UInt16BE(nameof(percussionBanks), percussionBanks); + w.GlobalFlags = s.EnumU8(nameof(GlobalFlags), w.GlobalFlags); + w.VolumeModel = s.EnumU8(nameof(VolumeModel), w.VolumeModel); - while(w.Melodic.Count < melodicBanks) w.Melodic.Add(new WoplBank()); - while(w.Percussion.Count < percussionBanks) w.Percussion.Add(new WoplBank()); + while(w.Melodic.Count < melodicBanks) w.Melodic.Add(new WoplBank()); + while(w.Percussion.Count < percussionBanks) w.Percussion.Add(new WoplBank()); - if (w.Version >= 2) + if (w.Version >= 2) + { + foreach(var bank in w.Melodic) { - foreach(var bank in w.Melodic) - { - bank.Name = s.FixedLengthString(nameof(bank.Name), bank.Name, WoplBank.MaxNameLength); - bank.Id = s.UInt16(nameof(bank.Id), bank.Id); - } - - foreach(var bank in w.Percussion) - { - bank.Name = s.FixedLengthString(nameof(bank.Name), bank.Name, WoplBank.MaxNameLength); - bank.Id = s.UInt16(nameof(bank.Id), bank.Id); - } + bank.Name = s.FixedLengthString(nameof(bank.Name), bank.Name, WoplBank.MaxNameLength); + bank.Id = s.UInt16(nameof(bank.Id), bank.Id); } - // Load instruments (128 per bank) - foreach (var bank in w.Melodic) - s.List(nameof(w.Melodic), bank.Instruments, bank.Instruments.Length, - (i2, w2, s2) => WoplInstrument.Serdes(i2, w2, s2, w.Version)); + foreach(var bank in w.Percussion) + { + bank.Name = s.FixedLengthString(nameof(bank.Name), bank.Name, WoplBank.MaxNameLength); + bank.Id = s.UInt16(nameof(bank.Id), bank.Id); + } + } - foreach (var bank in w.Percussion) - s.List(nameof(w.Percussion), bank.Instruments, bank.Instruments.Length, - (i2, w2, s2) => WoplInstrument.Serdes(i2, w2, s2, w.Version)); + // Load instruments (128 per bank) + foreach (var bank in w.Melodic) + s.List(nameof(w.Melodic), bank.Instruments, bank.Instruments.Length, + (i2, w2, s2) => WoplInstrument.Serdes(i2, w2, s2, w.Version)); - return w; - } + foreach (var bank in w.Percussion) + s.List(nameof(w.Percussion), bank.Instruments, bank.Instruments.Length, + (i2, w2, s2) => WoplInstrument.Serdes(i2, w2, s2, w.Version)); - public ushort Version { get; set; } = 3; - public GlobalBankFlags GlobalFlags { get; set; } - public VolumeModel VolumeModel { get; set; } + return w; + } - public WoplFile() { } - public WoplFile(GlobalTimbreLibrary timbreLibrary) - { - Version = 3; - GlobalFlags = GlobalBankFlags.DeepTremolo | GlobalBankFlags.DeepVibrato; - VolumeModel = VolumeModel.Auto; + public ushort Version { get; set; } = 3; + public GlobalBankFlags GlobalFlags { get; set; } + public VolumeModel VolumeModel { get; set; } - Melodic.Add(new WoplBank { Id = 0, Name = "" }); - Percussion.Add(new WoplBank { Id = 0, Name = "" }); + public WoplFile() { } + public WoplFile(GlobalTimbreLibrary timbreLibrary) + { + Version = 3; + GlobalFlags = GlobalBankFlags.DeepTremolo | GlobalBankFlags.DeepVibrato; + VolumeModel = VolumeModel.Auto; - for(int i = 0; i < timbreLibrary.Data.Count; i++) - { - var timbre = timbreLibrary.Data[i]; - WoplInstrument x = - i < 128 - ? Melodic[0].Instruments[i] ?? new WoplInstrument() - : Percussion[0].Instruments[i - 128 + 35] ?? new WoplInstrument(); - - x.Name = ""; - x.NoteOffset1 = timbre.MidiPatchNumber; - x.NoteOffset2 = timbre.MidiBankNumber; - x.InstrumentMode = InstrumentMode.TwoOperator; - x.FbConn1C0 = timbre.FeedbackConnection; - x.Operator0 = timbre.Carrier; - x.Operator1 = timbre.Modulation; - x.Operator2 = Operator.Blank; - x.Operator3 = Operator.Blank; - - if (i < 128) - Melodic[0].Instruments[i] = x; - else - Percussion[0].Instruments[i - 128 + 35] = x; - } - } + Melodic.Add(new WoplBank { Id = 0, Name = "" }); + Percussion.Add(new WoplBank { Id = 0, Name = "" }); - public byte[] GetRawWoplBytes(Action assertionFailed) + for(int i = 0; i < timbreLibrary.Data.Count; i++) { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - using var gbw = new GenericBinaryWriter(bw, Encoding.ASCII.GetBytes, assertionFailed); - Serdes(this, gbw); - return ms.ToArray(); + var timbre = timbreLibrary.Data[i]; + WoplInstrument x = + i < 128 + ? Melodic[0].Instruments[i] ?? new WoplInstrument() + : Percussion[0].Instruments[i - 128 + 35] ?? new WoplInstrument(); + + x.Name = ""; + x.NoteOffset1 = timbre.MidiPatchNumber; + x.NoteOffset2 = timbre.MidiBankNumber; + x.InstrumentMode = InstrumentMode.TwoOperator; + x.FbConn1C0 = timbre.FeedbackConnection; + x.Operator0 = timbre.Carrier; + x.Operator1 = timbre.Modulation; + x.Operator2 = Operator.Blank; + x.Operator3 = Operator.Blank; + + if (i < 128) + Melodic[0].Instruments[i] = x; + else + Percussion[0].Instruments[i - 128 + 35] = x; } } -} + + public byte[] GetRawWoplBytes(Action assertionFailed) + { + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + using var gbw = new WriterSerdes(bw, Encoding.ASCII.GetBytes, assertionFailed); + Serdes(this, gbw); + return ms.ToArray(); + } +} \ No newline at end of file diff --git a/src/WoplInstrument.cs b/src/WoplInstrument.cs index 493e492..1834b3b 100644 --- a/src/WoplInstrument.cs +++ b/src/WoplInstrument.cs @@ -1,74 +1,73 @@ using System; using SerdesNet; -namespace ADLMidi.NET +namespace ADLMidi.NET; + +public class WoplInstrument { - public class WoplInstrument - { - public string Name { get; set; } - Instrument _data; + public string Name { get; set; } + Instrument _data; - static Instrument SerdesI(Instrument w, ISerializer s, int version) + static Instrument SerdesI(Instrument w, ISerdes s, int version) + { + if (s == null) throw new ArgumentNullException(nameof(s)); + w.NoteOffset1 = s.Int16 (nameof(Instrument.NoteOffset1), w.NoteOffset1); + w.NoteOffset2 = s.Int16 (nameof(Instrument.NoteOffset2), w.NoteOffset2); + w.MidiVelocityOffset = s.Int8 (nameof(Instrument.MidiVelocityOffset), w.MidiVelocityOffset); + w.SecondVoiceDetune = s.Int8 (nameof(Instrument.SecondVoiceDetune), w.SecondVoiceDetune); + w.PercussionKeyNumber = s.UInt8 (nameof(Instrument.PercussionKeyNumber), w.PercussionKeyNumber); + w.Flags = s.UInt8 (nameof(Instrument.Flags), w.Flags); + w.FbConn1C0 = s.EnumU8 (nameof(Instrument.FbConn1C0), w.FbConn1C0); + w.FbConn2C0 = s.EnumU8 (nameof(Instrument.FbConn2C0), w.FbConn2C0); + w.Operator0 = s.Object (nameof(Instrument.Operator0), w.Operator0, Operator.Serdes); + w.Operator1 = s.Object (nameof(Instrument.Operator1), w.Operator1, Operator.Serdes); + w.Operator2 = s.Object (nameof(Instrument.Operator2), w.Operator2, Operator.Serdes); + w.Operator3 = s.Object (nameof(Instrument.Operator3), w.Operator3, Operator.Serdes); + if (version >= 3) { - if (s == null) throw new ArgumentNullException(nameof(s)); - w.NoteOffset1 = s.Int16 (nameof(Instrument.NoteOffset1), w.NoteOffset1); - w.NoteOffset2 = s.Int16 (nameof(Instrument.NoteOffset2), w.NoteOffset2); - w.MidiVelocityOffset = s.Int8 (nameof(Instrument.MidiVelocityOffset), w.MidiVelocityOffset); - w.SecondVoiceDetune = s.Int8 (nameof(Instrument.SecondVoiceDetune), w.SecondVoiceDetune); - w.PercussionKeyNumber = s.UInt8 (nameof(Instrument.PercussionKeyNumber), w.PercussionKeyNumber); - w.Flags = s.UInt8 (nameof(Instrument.Flags), w.Flags); - w.FbConn1C0 = s.EnumU8 (nameof(Instrument.FbConn1C0), w.FbConn1C0); - w.FbConn2C0 = s.EnumU8 (nameof(Instrument.FbConn2C0), w.FbConn2C0); - w.Operator0 = s.Object (nameof(Instrument.Operator0), w.Operator0, Operator.Serdes); - w.Operator1 = s.Object (nameof(Instrument.Operator1), w.Operator1, Operator.Serdes); - w.Operator2 = s.Object (nameof(Instrument.Operator2), w.Operator2, Operator.Serdes); - w.Operator3 = s.Object (nameof(Instrument.Operator3), w.Operator3, Operator.Serdes); - if (version >= 3) - { - w.DelayOnMs = s.UInt16(nameof(Instrument.DelayOnMs), w.DelayOnMs); - w.DelayOffMs = s.UInt16(nameof(Instrument.DelayOffMs), w.DelayOffMs); - } - - return w; + w.DelayOnMs = s.UInt16(nameof(Instrument.DelayOnMs), w.DelayOnMs); + w.DelayOffMs = s.UInt16(nameof(Instrument.DelayOffMs), w.DelayOffMs); } - public override string ToString() - => $"F:{FbConn1C0} {Operator0.Attack}:{Operator0.Decay} {Operator0.Sustain}:{Operator0.Release} {Operator0.Waveform} {Operator0.Flags} {Operator0.Level} {Operator1.Attack}:{Operator1.Decay} {Operator1.Sustain}:{Operator1.Release} {Operator1.Waveform} {Operator1.Flags} {Operator1.Level}"; - public static WoplInstrument Serdes(int _, WoplInstrument w, ISerializer s, int version) - { - if (s == null) throw new ArgumentNullException(nameof(s)); - w ??= new WoplInstrument(); - w.Name = s.FixedLengthString(nameof(Name), w.Name, 32); - w._data = s.Object(nameof(_data), w._data, (_, w2, s2) => SerdesI(w2, s2, version)); - return w; - } + return w; + } - public int Version { get => _data.Version; set => _data.Version = value; } - public short NoteOffset1 { get => _data.NoteOffset1; set => _data.NoteOffset1 = value; } - public short NoteOffset2 { get => _data.NoteOffset2; set => _data.NoteOffset2 = value; } - public sbyte MidiVelocityOffset { get => _data.MidiVelocityOffset; set => _data.MidiVelocityOffset = value; } - public sbyte SecondVoiceDetune { get => _data.SecondVoiceDetune; set => _data.SecondVoiceDetune = value; } - public byte PercussionKeyNumber { get => _data.PercussionKeyNumber; set => _data.PercussionKeyNumber = value; } + public override string ToString() + => $"F:{FbConn1C0} {Operator0.Attack}:{Operator0.Decay} {Operator0.Sustain}:{Operator0.Release} {Operator0.Waveform} {Operator0.Flags} {Operator0.Level} {Operator1.Attack}:{Operator1.Decay} {Operator1.Sustain}:{Operator1.Release} {Operator1.Waveform} {Operator1.Flags} {Operator1.Level}"; + public static WoplInstrument Serdes(int _, WoplInstrument w, ISerdes s, int version) + { + if (s == null) throw new ArgumentNullException(nameof(s)); + w ??= new WoplInstrument(); + w.Name = s.FixedLengthString(nameof(Name), w.Name, 32); + w._data = s.Object(nameof(_data), w._data, (_, w2, s2) => SerdesI(w2, s2, version)); + return w; + } - public InstrumentMode InstrumentMode - { - get => (InstrumentMode)(_data.Flags & 0x7); - set => _data.Flags = (byte)((_data.Flags & ~0x7) | ((int)value & 0x7)); - } + public int Version { get => _data.Version; set => _data.Version = value; } + public short NoteOffset1 { get => _data.NoteOffset1; set => _data.NoteOffset1 = value; } + public short NoteOffset2 { get => _data.NoteOffset2; set => _data.NoteOffset2 = value; } + public sbyte MidiVelocityOffset { get => _data.MidiVelocityOffset; set => _data.MidiVelocityOffset = value; } + public sbyte SecondVoiceDetune { get => _data.SecondVoiceDetune; set => _data.SecondVoiceDetune = value; } + public byte PercussionKeyNumber { get => _data.PercussionKeyNumber; set => _data.PercussionKeyNumber = value; } - public RhythmMode RhythmMode - { - get => (RhythmMode)((_data.Flags & 0x38) >> 3); - set => _data.Flags = (byte)((_data.Flags & ~0x38) | (((int)value & 0x7) << 3)); - } + public InstrumentMode InstrumentMode + { + get => (InstrumentMode)(_data.Flags & 0x7); + set => _data.Flags = (byte)((_data.Flags & ~0x7) | ((int)value & 0x7)); + } - public Modulation FbConn1C0 { get => _data.FbConn1C0; set => _data.FbConn1C0 = value; } - public Modulation FbConn2C0 { get => _data.FbConn2C0; set => _data.FbConn2C0 = value; } - public Operator Operator0 { get => _data.Operator0; set => _data.Operator0 = value; } - public Operator Operator1 { get => _data.Operator1; set => _data.Operator1 = value; } - public Operator Operator2 { get => _data.Operator2; set => _data.Operator2 = value; } - public Operator Operator3 { get => _data.Operator3; set => _data.Operator3 = value; } - public ushort DelayOnMs { get => _data.DelayOnMs; set => _data.DelayOnMs = value; } - public ushort DelayOffMs { get => _data.DelayOffMs; set => _data.DelayOffMs = value; } + public RhythmMode RhythmMode + { + get => (RhythmMode)((_data.Flags & 0x38) >> 3); + set => _data.Flags = (byte)((_data.Flags & ~0x38) | (((int)value & 0x7) << 3)); } -} + + public Modulation FbConn1C0 { get => _data.FbConn1C0; set => _data.FbConn1C0 = value; } + public Modulation FbConn2C0 { get => _data.FbConn2C0; set => _data.FbConn2C0 = value; } + public Operator Operator0 { get => _data.Operator0; set => _data.Operator0 = value; } + public Operator Operator1 { get => _data.Operator1; set => _data.Operator1 = value; } + public Operator Operator2 { get => _data.Operator2; set => _data.Operator2 = value; } + public Operator Operator3 { get => _data.Operator3; set => _data.Operator3 = value; } + public ushort DelayOnMs { get => _data.DelayOnMs; set => _data.DelayOnMs = value; } + public ushort DelayOffMs { get => _data.DelayOffMs; set => _data.DelayOffMs = value; } +} \ No newline at end of file