diff --git a/SoundFont2.sln b/SoundFont2.sln
index 6a791d7..b8d3f51 100644
--- a/SoundFont2.sln
+++ b/SoundFont2.sln
@@ -7,12 +7,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoundFont2", "SoundFont2\So
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {3C554511-03EA-41F0-AA5D-BABB9C330A33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3C554511-03EA-41F0-AA5D-BABB9C330A33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C554511-03EA-41F0-AA5D-BABB9C330A33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C554511-03EA-41F0-AA5D-BABB9C330A33}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
diff --git a/SoundFont2/SF2.cs b/SoundFont2/SF2.cs
index 9db36da..1811dc1 100644
--- a/SoundFont2/SF2.cs
+++ b/SoundFont2/SF2.cs
@@ -1,16 +1,16 @@
-using System.IO;
-using System.Text;
+using Kermalis.EndianBinaryIO;
+using System.IO;
namespace Kermalis.SoundFont2
{
public sealed class SF2
{
- uint size;
- public readonly InfoListChunk InfoChunk;
- public readonly SdtaListChunk SoundChunk;
- public readonly PdtaListChunk HydraChunk;
+ private uint _size;
+ public InfoListChunk InfoChunk { get; }
+ public SdtaListChunk SoundChunk { get; }
+ public PdtaListChunk HydraChunk { get; }
- // For creating
+ /// For creating
public SF2()
{
InfoChunk = new InfoListChunk(this);
@@ -18,20 +18,22 @@ public SF2()
HydraChunk = new PdtaListChunk(this);
}
- // For reading
+ /// For reading
public SF2(string path)
{
- using (var reader = new BinaryReader(File.Open(path, FileMode.Open), Encoding.ASCII))
+ using (var reader = new EndianBinaryReader(File.Open(path, FileMode.Open)))
{
- char[] chars = reader.ReadChars(4);
- if (new string(chars) != "RIFF")
+ string str = reader.ReadString(4, false);
+ if (str != "RIFF")
+ {
throw new InvalidDataException("RIFF header was not found at the start of the file.");
-
- size = reader.ReadUInt32();
- chars = reader.ReadChars(4);
- if (new string(chars) != "sfbk")
+ }
+ _size = reader.ReadUInt32();
+ str = reader.ReadString(4, false);
+ if (str != "sfbk")
+ {
throw new InvalidDataException("sfbk header was not found at the expected offset.");
-
+ }
InfoChunk = new InfoListChunk(this, reader);
SoundChunk = new SdtaListChunk(this, reader);
HydraChunk = new PdtaListChunk(this, reader);
@@ -40,13 +42,13 @@ public SF2(string path)
public void Save(string path)
{
- using (var writer = new BinaryWriter(File.Open(path, FileMode.Create), Encoding.ASCII))
+ using (var writer = new EndianBinaryWriter(File.Open(path, FileMode.Create)))
{
AddTerminals();
- writer.Write("RIFF".ToCharArray());
- writer.Write(size);
- writer.Write("sfbk".ToCharArray());
+ writer.Write("RIFF", 4);
+ writer.Write(_size);
+ writer.Write("sfbk", 4);
InfoChunk.Write(writer);
SoundChunk.Write(writer);
@@ -55,7 +57,7 @@ public void Save(string path)
}
- // Returns sample index
+ /// Returns sample index
public uint AddSample(short[] pcm16, string name, bool bLoop, uint loopPos, uint sampleRate, byte originalKey, sbyte pitchCorrection)
{
uint start = SoundChunk.SMPLSubChunk.AddSample(pcm16, bLoop, loopPos);
@@ -76,14 +78,10 @@ public uint AddSample(short[] pcm16, string name, bool bLoop, uint loopPos, uint
return AddSampleHeader(name, start, end, loopStart, loopEnd, sampleRate, originalKey, pitchCorrection);
}
- // Returns instrument index
+ /// Returns instrument index
public uint AddInstrument(string name)
{
- return HydraChunk.INSTSubChunk.AddInstrument(new SF2Instrument(this)
- {
- InstrumentName = name,
- InstrumentBagIndex = (ushort)HydraChunk.IBAGSubChunk.Count
- });
+ return HydraChunk.INSTSubChunk.AddInstrument(new SF2Instrument(name, (ushort)HydraChunk.IBAGSubChunk.Count));
}
public void AddInstrumentBag()
{
@@ -91,29 +89,19 @@ public void AddInstrumentBag()
}
public void AddInstrumentModulator()
{
- HydraChunk.IMODSubChunk.AddModulator(new SF2ModulatorList(this));
+ HydraChunk.IMODSubChunk.AddModulator(new SF2ModulatorList());
}
public void AddInstrumentGenerator()
{
- HydraChunk.IGENSubChunk.AddGenerator(new SF2GeneratorList(this));
+ HydraChunk.IGENSubChunk.AddGenerator(new SF2GeneratorList());
}
public void AddInstrumentGenerator(SF2Generator generator, SF2GeneratorAmount amount)
{
- HydraChunk.IGENSubChunk.AddGenerator(new SF2GeneratorList(this)
- {
- Generator = generator,
- GeneratorAmount = amount
- });
+ HydraChunk.IGENSubChunk.AddGenerator(new SF2GeneratorList(generator, amount));
}
public void AddPreset(string name, ushort preset, ushort bank)
{
- HydraChunk.PHDRSubChunk.AddPreset(new SF2PresetHeader(this)
- {
- PresetName = name,
- Preset = preset,
- Bank = bank,
- PresetBagIndex = (ushort)HydraChunk.PBAGSubChunk.Count
- });
+ HydraChunk.PHDRSubChunk.AddPreset(new SF2PresetHeader(name, preset, bank, (ushort)HydraChunk.PBAGSubChunk.Count));
}
public void AddPresetBag()
{
@@ -121,36 +109,22 @@ public void AddPresetBag()
}
public void AddPresetModulator()
{
- HydraChunk.PMODSubChunk.AddModulator(new SF2ModulatorList(this));
+ HydraChunk.PMODSubChunk.AddModulator(new SF2ModulatorList());
}
public void AddPresetGenerator()
{
- HydraChunk.PGENSubChunk.AddGenerator(new SF2GeneratorList(this));
+ HydraChunk.PGENSubChunk.AddGenerator(new SF2GeneratorList());
}
public void AddPresetGenerator(SF2Generator generator, SF2GeneratorAmount amount)
{
- HydraChunk.PGENSubChunk.AddGenerator(new SF2GeneratorList(this)
- {
- Generator = generator,
- GeneratorAmount = amount
- });
+ HydraChunk.PGENSubChunk.AddGenerator(new SF2GeneratorList(generator, amount));
}
- uint AddSampleHeader(string name, uint start, uint end, uint loopStart, uint loopEnd, uint sampleRate, byte originalKey, sbyte pitchCorrection)
+ private uint AddSampleHeader(string name, uint start, uint end, uint loopStart, uint loopEnd, uint sampleRate, byte originalKey, sbyte pitchCorrection)
{
- return HydraChunk.SHDRSubChunk.AddSample(new SF2SampleHeader(this)
- {
- SampleName = name,
- Start = start,
- End = end,
- LoopStart = loopStart,
- LoopEnd = loopEnd,
- SampleRate = sampleRate,
- OriginalKey = originalKey,
- PitchCorrection = pitchCorrection
- });
- }
- void AddTerminals()
+ return HydraChunk.SHDRSubChunk.AddSample(new SF2SampleHeader(name, start, end, loopStart, loopEnd, sampleRate, originalKey, pitchCorrection));
+ }
+ private void AddTerminals()
{
AddSampleHeader("EOS", 0, 0, 0, 0, 0, 0, 0);
AddInstrument("EOI");
@@ -166,8 +140,10 @@ void AddTerminals()
internal void UpdateSize()
{
if (InfoChunk == null || SoundChunk == null || HydraChunk == null)
+ {
return;
- size = 4
+ }
+ _size = 4
+ InfoChunk.UpdateSize() + 8
+ SoundChunk.UpdateSize() + 8
+ HydraChunk.UpdateSize() + 8;
diff --git a/SoundFont2/SF2Chunks.cs b/SoundFont2/SF2Chunks.cs
index e1e6f22..9601304 100644
--- a/SoundFont2/SF2Chunks.cs
+++ b/SoundFont2/SF2Chunks.cs
@@ -1,277 +1,288 @@
-using System;
+using Kermalis.EndianBinaryIO;
+using System;
using System.Collections.Generic;
-using System.IO;
-using System.Linq;
namespace Kermalis.SoundFont2
{
public class SF2Chunk
{
- protected readonly SF2 sf2;
+ protected readonly SF2 _sf2;
- readonly char[] chunkName; // Length 4
- public string ChunkName => new string(chunkName);
- public uint Size { get; protected set; } // Size in bytes
+ /// Length 4
+ public string ChunkName { get; }
+ /// Size in bytes
+ public uint Size { get; protected set; }
protected SF2Chunk(SF2 inSf2, string name)
{
- sf2 = inSf2;
- chunkName = name.ToCharArray();
+ _sf2 = inSf2;
+ ChunkName = name;
}
- protected SF2Chunk(SF2 inSf2, BinaryReader reader)
+ protected SF2Chunk(SF2 inSf2, EndianBinaryReader reader)
{
- sf2 = inSf2;
- chunkName = reader.ReadChars(4);
+ _sf2 = inSf2;
+ ChunkName = reader.ReadString(4, false);
Size = reader.ReadUInt32();
}
- internal virtual void Write(BinaryWriter writer)
+
+ internal virtual void Write(EndianBinaryWriter writer)
{
- writer.Write(chunkName);
+ writer.Write(ChunkName, 4);
writer.Write(Size);
}
}
public abstract class SF2ListChunk : SF2Chunk
{
- readonly char[] listChunkName; // Length 4
- public string ListChunkName => new string(listChunkName);
+ ///Length 4
+ public string ListChunkName { get; }
protected SF2ListChunk(SF2 inSf2, string name) : base(inSf2, "LIST")
{
- listChunkName = name.ToCharArray();
+ ListChunkName = name;
Size = 4;
}
- protected SF2ListChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ protected SF2ListChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
- listChunkName = reader.ReadChars(4);
+ ListChunkName = reader.ReadString(4, false);
}
- internal override void Write(BinaryWriter writer)
+
+ internal abstract uint UpdateSize();
+
+ internal override void Write(EndianBinaryWriter writer)
{
base.Write(writer);
- writer.Write(listChunkName);
+ writer.Write(ListChunkName, 4);
}
-
- internal abstract uint UpdateSize();
}
public sealed class SF2PresetHeader
{
public const uint Size = 38;
- readonly SF2 sf2;
- char[] presetName; // Length 20
- public string PresetName
- {
- get => new string(presetName).TrimEnd('\0');
- set => SF2Utils.TruncateOrNot(value, 20, ref presetName);
- }
- public ushort Preset, Bank, PresetBagIndex;
+ /// Length 20
+ public string PresetName { get; set; }
+ public ushort Preset { get; set; }
+ public ushort Bank { get; set; }
+ public ushort PresetBagIndex { get; set; }
// Reserved for future implementations
- readonly uint library = 0, genre = 0, morphology = 0;
+ private readonly uint _library;
+ private readonly uint _genre;
+ private readonly uint _morphology;
- internal SF2PresetHeader(SF2 inSf2)
+ internal SF2PresetHeader(string name, ushort preset, ushort bank, ushort index)
{
- sf2 = inSf2;
- presetName = new char[20];
+ PresetName = name;
+ Preset = preset;
+ Bank = bank;
+ PresetBagIndex = index;
}
- internal SF2PresetHeader(SF2 inSf2, BinaryReader reader)
+ internal SF2PresetHeader(EndianBinaryReader reader)
{
- sf2 = inSf2;
- presetName = reader.ReadChars(20);
+ PresetName = reader.ReadString(20, true);
Preset = reader.ReadUInt16();
Bank = reader.ReadUInt16();
PresetBagIndex = reader.ReadUInt16();
- library = reader.ReadUInt32();
- genre = reader.ReadUInt32();
- morphology = reader.ReadUInt32();
+ _library = reader.ReadUInt32();
+ _genre = reader.ReadUInt32();
+ _morphology = reader.ReadUInt32();
}
- internal void Write(BinaryWriter writer)
+
+ internal void Write(EndianBinaryWriter writer)
{
- writer.Write(presetName);
+ writer.Write(PresetName, 20);
writer.Write(Preset);
writer.Write(Bank);
writer.Write(PresetBagIndex);
- writer.Write(library);
- writer.Write(genre);
- writer.Write(morphology);
+ writer.Write(_library);
+ writer.Write(_genre);
+ writer.Write(_morphology);
}
- public override string ToString() => $"Preset Header - Bank = {Bank}, " +
- $"\nPreset = {Preset}, " +
- $"\nName = \"{PresetName}\"";
+ public override string ToString()
+ {
+ return $"Preset Header - Bank = {Bank}" +
+ $",\nPreset = {Preset}" +
+ $",\nName = \"{PresetName}\"";
+ }
}
- // Covers sfPresetBag and sfInstBag
+ /// Covers sfPresetBag and sfInstBag
public sealed class SF2Bag
{
public const uint Size = 4;
- readonly SF2 sf2;
- public ushort GeneratorIndex; // Index in list of generators
- public ushort ModulatorIndex; // Index in list of modulators
+ /// Index in list of generators
+ public ushort GeneratorIndex { get; set; }
+ /// Index in list of modulators
+ public ushort ModulatorIndex { get; set; }
- internal SF2Bag(SF2 inSf2, bool preset)
+ internal SF2Bag(SF2 inSf2, bool isPresetBag)
{
- sf2 = inSf2;
- if (preset)
+ if (isPresetBag)
{
- GeneratorIndex = (ushort)sf2.HydraChunk.PGENSubChunk.Count;
- ModulatorIndex = (ushort)sf2.HydraChunk.PMODSubChunk.Count;
+ GeneratorIndex = (ushort)inSf2.HydraChunk.PGENSubChunk.Count;
+ ModulatorIndex = (ushort)inSf2.HydraChunk.PMODSubChunk.Count;
}
else
{
- GeneratorIndex = (ushort)sf2.HydraChunk.IGENSubChunk.Count;
- ModulatorIndex = (ushort)sf2.HydraChunk.IMODSubChunk.Count;
+ GeneratorIndex = (ushort)inSf2.HydraChunk.IGENSubChunk.Count;
+ ModulatorIndex = (ushort)inSf2.HydraChunk.IMODSubChunk.Count;
}
}
- internal SF2Bag(SF2 inSf2, BinaryReader reader)
+ internal SF2Bag(EndianBinaryReader reader)
{
- sf2 = inSf2;
GeneratorIndex = reader.ReadUInt16();
ModulatorIndex = reader.ReadUInt16();
}
- internal void Write(BinaryWriter writer)
+
+ internal void Write(EndianBinaryWriter writer)
{
writer.Write(GeneratorIndex);
writer.Write(ModulatorIndex);
}
- public override string ToString() => $"Bag - Generator index = {GeneratorIndex}, " +
- $"\nModulator index = {ModulatorIndex}";
+ public override string ToString()
+ {
+ return $"Bag - Generator index = {GeneratorIndex}" +
+ $",\nModulator index = {ModulatorIndex}";
+ }
}
- // Covers sfModList and sfInstModList
+ /// Covers sfModList and sfInstModList
public sealed class SF2ModulatorList
{
public const uint Size = 10;
- readonly SF2 sf2;
- public SF2Modulator ModulatorSource;
- public SF2Generator ModulatorDestination;
- public short ModulatorAmount;
- public SF2Modulator ModulatorAmountSource;
- public SF2Transform ModulatorTransform;
+ public SF2Modulator ModulatorSource { get; set; }
+ public SF2Generator ModulatorDestination { get; set; }
+ public short ModulatorAmount { get; set; }
+ public SF2Modulator ModulatorAmountSource { get; set; }
+ public SF2Transform ModulatorTransform { get; set; }
- internal SF2ModulatorList(SF2 inSf2)
- {
- sf2 = inSf2;
- }
- internal SF2ModulatorList(SF2 inSf2, BinaryReader reader)
+ internal SF2ModulatorList() { }
+ internal SF2ModulatorList(EndianBinaryReader reader)
{
- sf2 = inSf2;
- ModulatorSource = (SF2Modulator)reader.ReadUInt16();
- ModulatorDestination = (SF2Generator)reader.ReadUInt16();
+ ModulatorSource = reader.ReadEnum();
+ ModulatorDestination = reader.ReadEnum();
ModulatorAmount = reader.ReadInt16();
- ModulatorAmountSource = (SF2Modulator)reader.ReadUInt16();
- ModulatorTransform = (SF2Transform)reader.ReadUInt16();
+ ModulatorAmountSource = reader.ReadEnum();
+ ModulatorTransform = reader.ReadEnum();
}
- internal void Write(BinaryWriter writer)
+
+ internal void Write(EndianBinaryWriter writer)
{
- writer.Write((ushort)ModulatorSource);
- writer.Write((ushort)ModulatorDestination);
+ writer.Write(ModulatorSource);
+ writer.Write(ModulatorDestination);
writer.Write(ModulatorAmount);
- writer.Write((ushort)ModulatorAmountSource);
- writer.Write((ushort)ModulatorTransform);
+ writer.Write(ModulatorAmountSource);
+ writer.Write(ModulatorTransform);
}
- public override string ToString() => $"Modulator List - Modulator source = {ModulatorSource}, " +
- $"\nModulator destination = {ModulatorDestination}, " +
- $"\nModulator amount = {ModulatorAmount}, " +
- $"\nModulator amount source = {ModulatorAmountSource}, " +
- $"\nModulator transform = {ModulatorTransform}";
+ public override string ToString()
+ {
+ return $"Modulator List - Modulator source = {ModulatorSource}" +
+ $",\nModulator destination = {ModulatorDestination}" +
+ $",\nModulator amount = {ModulatorAmount}" +
+ $",\nModulator amount source = {ModulatorAmountSource}" +
+ $",\nModulator transform = {ModulatorTransform}";
+ }
}
public sealed class SF2GeneratorList
{
public const uint Size = 4;
- readonly SF2 sf2;
- public SF2Generator Generator;
- public SF2GeneratorAmount GeneratorAmount;
+ public SF2Generator Generator { get; set; }
+ public SF2GeneratorAmount GeneratorAmount { get; set; }
- internal SF2GeneratorList(SF2 inSf2)
+ internal SF2GeneratorList() { }
+ internal SF2GeneratorList(SF2Generator generator, SF2GeneratorAmount amount)
{
- sf2 = inSf2;
+ Generator = generator;
+ GeneratorAmount = amount;
}
- internal SF2GeneratorList(SF2 inSf2, BinaryReader reader)
+ internal SF2GeneratorList(EndianBinaryReader reader)
{
- sf2 = inSf2;
- Generator = (SF2Generator)reader.ReadUInt16();
- GeneratorAmount = new SF2GeneratorAmount { UAmount = reader.ReadUInt16() };
+ Generator = reader.ReadEnum();
+ GeneratorAmount = new SF2GeneratorAmount { Amount = reader.ReadInt16() };
}
- public void Write(BinaryWriter writer)
+
+ public void Write(EndianBinaryWriter writer)
{
- writer.Write((ushort)Generator);
- writer.Write(GeneratorAmount.UAmount);
+ writer.Write(Generator);
+ writer.Write(GeneratorAmount.Amount);
}
- public override string ToString() => $"Generator List - Generator = {Generator}, " +
- $"\nGenerator amount = \"{GeneratorAmount}\"";
+ public override string ToString()
+ {
+ return $"Generator List - Generator = {Generator}" +
+ $",\nGenerator amount = \"{GeneratorAmount}\"";
+ }
}
public sealed class SF2Instrument
{
public const uint Size = 22;
- readonly SF2 sf2;
- char[] instrumentName; // Length 20
- public string InstrumentName
- {
- get => new string(instrumentName).TrimEnd('\0');
- set => SF2Utils.TruncateOrNot(value, 20, ref instrumentName);
- }
- public ushort InstrumentBagIndex;
+ /// Length 20
+ public string InstrumentName { get; set; }
+ public ushort InstrumentBagIndex { get; set; }
- internal SF2Instrument(SF2 inSf2)
+ internal SF2Instrument(string name, ushort index)
{
- sf2 = inSf2;
- instrumentName = new char[20];
+ InstrumentName = name;
+ InstrumentBagIndex = index;
}
- internal SF2Instrument(SF2 inSf2, BinaryReader reader)
+ internal SF2Instrument(EndianBinaryReader reader)
{
- sf2 = inSf2;
- instrumentName = reader.ReadChars(20);
+ InstrumentName = reader.ReadString(20, true);
InstrumentBagIndex = reader.ReadUInt16();
}
- internal void Write(BinaryWriter writer)
+
+ internal void Write(EndianBinaryWriter writer)
{
- writer.Write(instrumentName);
+ writer.Write(InstrumentName, 20);
writer.Write(InstrumentBagIndex);
}
- public override string ToString() => $"Instrument - Name = \"{InstrumentName}\"";
+ public override string ToString()
+ {
+ return $"Instrument - Name = \"{InstrumentName}\"";
+ }
}
public sealed class SF2SampleHeader
{
public const uint Size = 46;
- readonly SF2 sf2;
-
- char[] sampleName; // Length 20
- public string SampleName
- {
- get => new string(sampleName).TrimEnd('\0');
- set => SF2Utils.TruncateOrNot(value, 20, ref sampleName);
- }
- public uint Start;
- public uint End;
- public uint LoopStart;
- public uint LoopEnd;
- public uint SampleRate;
- public byte OriginalKey;
- public sbyte PitchCorrection;
- public ushort SampleLink;
- public SF2SampleLink SampleType = SF2SampleLink.MonoSample;
- internal SF2SampleHeader(SF2 inSf2)
- {
- sf2 = inSf2;
- sampleName = new char[20];
- }
- internal SF2SampleHeader(SF2 inSf2, BinaryReader reader)
- {
- sf2 = inSf2;
- sampleName = reader.ReadChars(20);
+ /// Length 20
+ public string SampleName { get; set; }
+ public uint Start { get; set; }
+ public uint End { get; set; }
+ public uint LoopStart { get; set; }
+ public uint LoopEnd { get; set; }
+ public uint SampleRate { get; set; }
+ public byte OriginalKey { get; set; }
+ public sbyte PitchCorrection { get; set; }
+ public ushort SampleLink { get; set; }
+ public SF2SampleLink SampleType { get; set; }
+
+ internal SF2SampleHeader(string name, uint start, uint end, uint loopStart, uint loopEnd, uint sampleRate, byte originalKey, sbyte pitchCorrection)
+ {
+ SampleName = name;
+ Start = start;
+ End = end;
+ LoopStart = loopStart;
+ LoopEnd = loopEnd;
+ SampleRate = sampleRate;
+ OriginalKey = originalKey;
+ PitchCorrection = pitchCorrection;
+ SampleType = SF2SampleLink.MonoSample;
+ }
+ internal SF2SampleHeader(EndianBinaryReader reader)
+ {
+ SampleName = reader.ReadString(20, true);
Start = reader.ReadUInt32();
End = reader.ReadUInt32();
LoopStart = reader.ReadUInt32();
@@ -280,11 +291,12 @@ internal SF2SampleHeader(SF2 inSf2, BinaryReader reader)
OriginalKey = reader.ReadByte();
PitchCorrection = reader.ReadSByte();
SampleLink = reader.ReadUInt16();
- SampleType = (SF2SampleLink)reader.ReadUInt16();
+ SampleType = reader.ReadEnum();
}
- internal void Write(BinaryWriter writer)
+
+ internal void Write(EndianBinaryWriter writer)
{
- writer.Write(sampleName);
+ writer.Write(SampleName, 20);
writer.Write(Start);
writer.Write(End);
writer.Write(LoopStart);
@@ -293,113 +305,117 @@ internal void Write(BinaryWriter writer)
writer.Write(OriginalKey);
writer.Write(PitchCorrection);
writer.Write(SampleLink);
- writer.Write((ushort)SampleType);
+ writer.Write(SampleType);
}
- public override string ToString() => $"Sample - Name = \"{SampleName}\", " +
- $"\nType = {SampleType}";
+ public override string ToString()
+ {
+ return $"Sample - Name = \"{SampleName}\"" +
+ $",\nType = {SampleType}";
+ }
}
#region Sub-Chunks
public sealed class VersionSubChunk : SF2Chunk
{
- public SF2VersionTag Version;
+ public SF2VersionTag Version { get; set; }
internal VersionSubChunk(SF2 inSf2, string subChunkName) : base(inSf2, subChunkName)
{
Size = SF2VersionTag.Size;
- sf2.UpdateSize();
+ inSf2.UpdateSize();
}
- internal VersionSubChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal VersionSubChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
- Version = new SF2VersionTag(reader.ReadUInt16(), reader.ReadUInt16());
+ Version = new SF2VersionTag(reader);
}
- internal override void Write(BinaryWriter writer)
+
+ internal override void Write(EndianBinaryWriter writer)
{
base.Write(writer);
- writer.Write(Version.Major);
- writer.Write(Version.Minor);
+ Version.Write(writer);
}
- public override string ToString() => $"Version Chunk - Revision = {Version}";
+ public override string ToString()
+ {
+ return $"Version Chunk - Revision = {Version}";
+ }
}
public sealed class HeaderSubChunk : SF2Chunk
{
- readonly int maxSize;
-
- char[] field;
+ public int MaxSize { get; }
+ private int _fieldTargetLength;
+ private string _field;
+ /// Length
public string Field
{
- get => new string(field).TrimEnd('\0');
+ get => _field;
set
{
- var strAsList = value.ToCharArray().ToList();
- if (strAsList.Count >= maxSize) // Input too long; cut it down
+ if (value.Length >= MaxSize) // Input too long; cut it down
{
- strAsList = strAsList.Take(maxSize).ToList();
- strAsList[maxSize - 1] = '\0';
+ _fieldTargetLength = MaxSize;
}
- else if (strAsList.Count % 2 == 0) // Even amount of characters
+ else if (value.Length % 2 == 0) // Even amount of characters
{
- strAsList.Add('\0'); // Add two null-terminators to keep the byte count even
- strAsList.Add('\0');
+ _fieldTargetLength = value.Length + 2; // Add two null-terminators to keep the byte count even
}
else // Odd amount of characters
{
- strAsList.Add('\0'); // Add one null-terminator since that would make byte the count even
+ _fieldTargetLength = value.Length + 1; // Add one null-terminator since that would make byte the count even
}
- field = strAsList.ToArray();
- Size = (uint)field.Length;
- sf2.UpdateSize();
+ _field = value;
+ Size = (uint)_fieldTargetLength;
+ _sf2.UpdateSize();
}
}
internal HeaderSubChunk(SF2 inSf2, string subChunkName, int maxSize = 0x100) : base(inSf2, subChunkName)
{
- this.maxSize = maxSize;
+ MaxSize = maxSize;
}
- internal HeaderSubChunk(SF2 inSf2, BinaryReader reader, int maxSize = 0x100) : base(inSf2, reader)
+ internal HeaderSubChunk(SF2 inSf2, EndianBinaryReader reader, int maxSize = 0x100) : base(inSf2, reader)
{
- this.maxSize = maxSize;
- field = reader.ReadChars((int)Size);
+ MaxSize = maxSize;
+ _field = reader.ReadString((int)Size, true);
}
- internal override void Write(BinaryWriter writer)
+
+ internal override void Write(EndianBinaryWriter writer)
{
base.Write(writer);
- writer.Write(field);
+ writer.Write(_field, _fieldTargetLength);
}
- public override string ToString() => $"Header Chunk - Name = \"{ChunkName}\", " +
- $"\nField Max Size = {maxSize}, " +
- $"\nField = \"{Field}\"";
+ public override string ToString()
+ {
+ return $"Header Chunk - Name = \"{ChunkName}\"" +
+ $",\nField Max Size = {MaxSize}" +
+ $",\nField = \"{Field}\"";
+ }
}
public sealed class SMPLSubChunk : SF2Chunk
{
- List samples = new List(); // Block of sample data
+ private readonly List _samples = new List(); // Block of sample data
internal SMPLSubChunk(SF2 inSf2) : base(inSf2, "smpl") { }
- internal SMPLSubChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal SMPLSubChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
for (int i = 0; i < Size / sizeof(short); i++)
- samples.Add(reader.ReadInt16());
- }
- internal override void Write(BinaryWriter writer)
- {
- base.Write(writer);
- foreach (short s in samples)
- writer.Write(s);
+ {
+ _samples.Add(reader.ReadInt16());
+ }
}
// Returns index of the start of the sample
internal uint AddSample(short[] pcm16, bool bLoop, uint loopPos)
{
- uint start = (uint)samples.Count;
+ uint start = (uint)_samples.Count;
// Write wave
- samples.AddRange(pcm16);
+ _samples.AddRange(pcm16);
// If looping is enabled, write 8 samples from the loop point
if (bLoop)
@@ -407,191 +423,253 @@ internal uint AddSample(short[] pcm16, bool bLoop, uint loopPos)
// In case (loopPos + i) is greater than the sample length
uint max = (uint)pcm16.Length - loopPos;
for (uint i = 0; i < 8; i++)
- samples.Add(pcm16[loopPos + (i % max)]);
+ {
+ _samples.Add(pcm16[loopPos + (i % max)]);
+ }
}
// Write 46 empty samples
- samples.AddRange(new short[46]);
+ _samples.AddRange(new short[46]);
- Size = (uint)samples.Count * sizeof(short);
- sf2.UpdateSize();
+ Size = (uint)_samples.Count * sizeof(short);
+ _sf2.UpdateSize();
return start;
}
- public override string ToString() => $"Sample Data Chunk";
+ internal override void Write(EndianBinaryWriter writer)
+ {
+ base.Write(writer);
+ foreach (short s in _samples)
+ {
+ writer.Write(s);
+ }
+ }
+
+ public override string ToString()
+ {
+ return $"Sample Data Chunk";
+ }
}
public sealed class PHDRSubChunk : SF2Chunk
{
- readonly List presets = new List();
- public uint Count => (uint)presets.Count;
+ private readonly List _presets = new List();
+ public uint Count => (uint)_presets.Count;
internal PHDRSubChunk(SF2 inSf2) : base(inSf2, "phdr") { }
- internal PHDRSubChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal PHDRSubChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
for (int i = 0; i < Size / SF2PresetHeader.Size; i++)
- presets.Add(new SF2PresetHeader(inSf2, reader));
+ {
+ _presets.Add(new SF2PresetHeader(reader));
+ }
+ }
+
+ internal void AddPreset(SF2PresetHeader preset)
+ {
+ _presets.Add(preset);
+ Size = Count * SF2PresetHeader.Size;
+ _sf2.UpdateSize();
}
- internal override void Write(BinaryWriter writer)
+
+ internal override void Write(EndianBinaryWriter writer)
{
base.Write(writer);
for (int i = 0; i < Count; i++)
- presets[i].Write(writer);
+ {
+ _presets[i].Write(writer);
+ }
}
- internal void AddPreset(SF2PresetHeader preset)
+ public override string ToString()
{
- presets.Add(preset);
- Size = Count * SF2PresetHeader.Size;
- sf2.UpdateSize();
+ return $"Preset Header Chunk - Preset count = {Count}";
}
-
- public override string ToString() => $"Preset Header Chunk - Preset count = {Count}";
}
public sealed class INSTSubChunk : SF2Chunk
{
- readonly List instruments = new List();
- public uint Count => (uint)instruments.Count;
+ private readonly List _instruments = new List();
+ public uint Count => (uint)_instruments.Count;
internal INSTSubChunk(SF2 inSf2) : base(inSf2, "inst") { }
- internal INSTSubChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal INSTSubChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
for (int i = 0; i < Size / SF2Instrument.Size; i++)
- instruments.Add(new SF2Instrument(inSf2, reader));
- }
- internal override void Write(BinaryWriter writer)
- {
- base.Write(writer);
- for (int i = 0; i < Count; i++)
- instruments[i].Write(writer);
+ {
+ _instruments.Add(new SF2Instrument(reader));
+ }
}
internal uint AddInstrument(SF2Instrument instrument)
{
- instruments.Add(instrument);
+ _instruments.Add(instrument);
Size = Count * SF2Instrument.Size;
- sf2.UpdateSize();
+ _sf2.UpdateSize();
return Count - 1;
}
- public override string ToString() => $"Instrument Chunk - Instrument count = {Count}";
+ internal override void Write(EndianBinaryWriter writer)
+ {
+ base.Write(writer);
+ for (int i = 0; i < Count; i++)
+ {
+ _instruments[i].Write(writer);
+ }
+ }
+
+ public override string ToString()
+ {
+ return $"Instrument Chunk - Instrument count = {Count}";
+ }
}
public sealed class BAGSubChunk : SF2Chunk
{
- readonly List bags = new List();
- public uint Count => (uint)bags.Count;
+ private readonly List _bags = new List();
+ public uint Count => (uint)_bags.Count;
internal BAGSubChunk(SF2 inSf2, bool preset) : base(inSf2, preset ? "pbag" : "ibag") { }
- internal BAGSubChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal BAGSubChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
for (int i = 0; i < Size / SF2Bag.Size; i++)
- bags.Add(new SF2Bag(inSf2, reader));
+ {
+ _bags.Add(new SF2Bag(reader));
+ }
}
- internal override void Write(BinaryWriter writer)
+
+ internal void AddBag(SF2Bag bag)
+ {
+ _bags.Add(bag);
+ Size = Count * SF2Bag.Size;
+ _sf2.UpdateSize();
+ }
+
+ internal override void Write(EndianBinaryWriter writer)
{
base.Write(writer);
for (int i = 0; i < Count; i++)
- bags[i].Write(writer);
+ {
+ _bags[i].Write(writer);
+ }
}
- internal void AddBag(SF2Bag bag)
+ public override string ToString()
{
- bags.Add(bag);
- Size = Count * SF2Bag.Size;
- sf2.UpdateSize();
+ return $"Bag Chunk - Name = \"{ChunkName}\"" +
+ $",\nBag count = {Count}";
}
-
- public override string ToString() => $"Bag Chunk - Name = \"{ChunkName}\", " +
- $"\nBag count = {Count}";
}
public sealed class MODSubChunk : SF2Chunk
{
- readonly List modulators = new List();
- public uint Count => (uint)modulators.Count;
+ private readonly List _modulators = new List();
+ public uint Count => (uint)_modulators.Count;
internal MODSubChunk(SF2 inSf2, bool preset) : base(inSf2, preset ? "pmod" : "imod") { }
- internal MODSubChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal MODSubChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
for (int i = 0; i < Size / SF2ModulatorList.Size; i++)
- modulators.Add(new SF2ModulatorList(inSf2, reader));
+ {
+ _modulators.Add(new SF2ModulatorList(reader));
+ }
}
- internal override void Write(BinaryWriter writer)
+
+ internal void AddModulator(SF2ModulatorList modulator)
+ {
+ _modulators.Add(modulator);
+ Size = Count * SF2ModulatorList.Size;
+ _sf2.UpdateSize();
+ }
+
+ internal override void Write(EndianBinaryWriter writer)
{
base.Write(writer);
for (int i = 0; i < Count; i++)
- modulators[i].Write(writer);
+ {
+ _modulators[i].Write(writer);
+ }
}
- internal void AddModulator(SF2ModulatorList modulator)
+ public override string ToString()
{
- modulators.Add(modulator);
- Size = Count * SF2ModulatorList.Size;
- sf2.UpdateSize();
+ return $"Modulator Chunk - Name = \"{ChunkName}\"" +
+ $",\nModulator count = {Count}";
}
-
- public override string ToString() => $"Modulator Chunk - Name = \"{ChunkName}\", " +
- $"\nModulator count = {Count}";
}
public sealed class GENSubChunk : SF2Chunk
{
- readonly List generators = new List();
- public uint Count => (uint)generators.Count;
+ private readonly List _generators = new List();
+ public uint Count => (uint)_generators.Count;
internal GENSubChunk(SF2 inSf2, bool preset) : base(inSf2, preset ? "pgen" : "igen") { }
- internal GENSubChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal GENSubChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
for (int i = 0; i < Size / SF2GeneratorList.Size; i++)
- generators.Add(new SF2GeneratorList(inSf2, reader));
+ {
+ _generators.Add(new SF2GeneratorList(reader));
+ }
}
- internal override void Write(BinaryWriter writer)
+
+ internal void AddGenerator(SF2GeneratorList generator)
+ {
+ _generators.Add(generator);
+ Size = Count * SF2GeneratorList.Size;
+ _sf2.UpdateSize();
+ }
+
+ internal override void Write(EndianBinaryWriter writer)
{
base.Write(writer);
for (int i = 0; i < Count; i++)
- generators[i].Write(writer);
+ {
+ _generators[i].Write(writer);
+ }
}
- internal void AddGenerator(SF2GeneratorList generator)
+ public override string ToString()
{
- generators.Add(generator);
- Size = Count * SF2GeneratorList.Size;
- sf2.UpdateSize();
+ return $"Generator Chunk - Name = \"{ChunkName}\"" +
+ $",\nGenerator count = {Count}";
}
-
- public override string ToString() => $"Generator Chunk - Name = \"{ChunkName}\", " +
- $"\nGenerator count = {Count}";
}
public sealed class SHDRSubChunk : SF2Chunk
{
- readonly List samples = new List();
- public uint Count => (uint)samples.Count;
+ private readonly List _samples = new List();
+ public uint Count => (uint)_samples.Count;
internal SHDRSubChunk(SF2 inSf2) : base(inSf2, "shdr") { }
- internal SHDRSubChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal SHDRSubChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
for (int i = 0; i < Size / SF2SampleHeader.Size; i++)
- samples.Add(new SF2SampleHeader(inSf2, reader));
- }
- internal override void Write(BinaryWriter writer)
- {
- base.Write(writer);
- for (int i = 0; i < Count; i++)
- samples[i].Write(writer);
+ {
+ _samples.Add(new SF2SampleHeader(reader));
+ }
}
internal uint AddSample(SF2SampleHeader sample)
{
- samples.Add(sample);
+ _samples.Add(sample);
Size = Count * SF2SampleHeader.Size;
- sf2.UpdateSize();
+ _sf2.UpdateSize();
return Count - 1;
}
- public override string ToString() => $"Sample Header Chunk - Sample header count = {Count}";
+ internal override void Write(EndianBinaryWriter writer)
+ {
+ base.Write(writer);
+ for (int i = 0; i < Count; i++)
+ {
+ _samples[i].Write(writer);
+ }
+ }
+
+ public override string ToString()
+ {
+ return $"Sample Header Chunk - Sample header count = {Count}";
+ }
}
#endregion
@@ -600,210 +678,286 @@ internal uint AddSample(SF2SampleHeader sample)
public sealed class InfoListChunk : SF2ListChunk
{
- readonly List subChunks = new List();
-
- const string defaultEngine = "EMU8000";
+ private readonly List _subChunks = new List();
+ private const string DefaultEngine = "EMU8000";
public string Engine
{
get
{
- if (subChunks.Find(s => s.ChunkName == "isng") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "isng") is HeaderSubChunk chunk)
+ {
return chunk.Field;
+ }
else
{
- subChunks.Add(new HeaderSubChunk(sf2, "isng") { Field = defaultEngine });
- return defaultEngine;
+ _subChunks.Add(new HeaderSubChunk(_sf2, "isng") { Field = DefaultEngine });
+ return DefaultEngine;
}
}
set
{
- if (subChunks.Find(s => s.ChunkName == "isng") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "isng") is HeaderSubChunk chunk)
+ {
chunk.Field = value;
+ }
else
- subChunks.Add(new HeaderSubChunk(sf2, "isng") { Field = value });
+ {
+ _subChunks.Add(new HeaderSubChunk(_sf2, "isng") { Field = value });
+ }
}
}
- const string defaultBank = "General MIDI";
+
+ private const string DefaultBank = "General MIDI";
public string Bank
{
get
{
- if (subChunks.Find(s => s.ChunkName == "INAM") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "INAM") is HeaderSubChunk chunk)
+ {
return chunk.Field;
+ }
else
{
- subChunks.Add(new HeaderSubChunk(sf2, "INAM") { Field = defaultBank });
- return defaultBank;
+ _subChunks.Add(new HeaderSubChunk(_sf2, "INAM") { Field = DefaultBank });
+ return DefaultBank;
}
}
set
{
- if (subChunks.Find(s => s.ChunkName == "INAM") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "INAM") is HeaderSubChunk chunk)
+ {
chunk.Field = value;
+ }
else
- subChunks.Add(new HeaderSubChunk(sf2, "INAM") { Field = value });
+ {
+ _subChunks.Add(new HeaderSubChunk(_sf2, "INAM") { Field = value });
+ }
}
}
public string ROM
{
get
{
- if (subChunks.Find(s => s.ChunkName == "irom") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "irom") is HeaderSubChunk chunk)
+ {
return chunk.Field;
+ }
else
+ {
return string.Empty;
+ }
}
set
{
- if (subChunks.Find(s => s.ChunkName == "irom") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "irom") is HeaderSubChunk chunk)
+ {
chunk.Field = value;
+ }
else
- subChunks.Add(new HeaderSubChunk(sf2, "irom") { Field = value });
+ {
+ _subChunks.Add(new HeaderSubChunk(_sf2, "irom") { Field = value });
+ }
}
}
public SF2VersionTag ROMVersion
{
get
{
- if (subChunks.Find(s => s.ChunkName == "iver") is VersionSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "iver") is VersionSubChunk chunk)
+ {
return chunk.Version;
+ }
else
+ {
return null;
+ }
}
set
{
- if (subChunks.Find(s => s.ChunkName == "iver") is VersionSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "iver") is VersionSubChunk chunk)
+ {
chunk.Version = value;
+ }
else
- subChunks.Add(new VersionSubChunk(sf2, "iver") { Version = value });
+ {
+ _subChunks.Add(new VersionSubChunk(_sf2, "iver") { Version = value });
+ }
}
}
public string Date
{
get
{
- if (subChunks.Find(s => s.ChunkName == "ICRD") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "ICRD") is HeaderSubChunk chunk)
+ {
return chunk.Field;
+ }
else
+ {
return string.Empty;
+ }
}
set
{
- if (subChunks.Find(s => s.ChunkName == "ICRD") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "ICRD") is HeaderSubChunk chunk)
+ {
chunk.Field = value;
+ }
else
- subChunks.Add(new HeaderSubChunk(sf2, "ICRD") { Field = value });
+ {
+ _subChunks.Add(new HeaderSubChunk(_sf2, "ICRD") { Field = value });
+ }
}
}
public string Designer
{
get
{
- if (subChunks.Find(s => s.ChunkName == "IENG") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "IENG") is HeaderSubChunk chunk)
+ {
return chunk.Field;
+ }
else
+ {
return string.Empty;
+ }
}
set
{
- if (subChunks.Find(s => s.ChunkName == "IENG") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "IENG") is HeaderSubChunk chunk)
+ {
chunk.Field = value;
+ }
else
- subChunks.Add(new HeaderSubChunk(sf2, "IENG") { Field = value });
+ {
+ _subChunks.Add(new HeaderSubChunk(_sf2, "IENG") { Field = value });
+ }
}
}
public string Products
{
get
{
- if (subChunks.Find(s => s.ChunkName == "IPRD") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "IPRD") is HeaderSubChunk chunk)
+ {
return chunk.Field;
+ }
else
+ {
return string.Empty;
+ }
}
set
{
- if (subChunks.Find(s => s.ChunkName == "IPRD") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "IPRD") is HeaderSubChunk chunk)
+ {
chunk.Field = value;
+ }
else
- subChunks.Add(new HeaderSubChunk(sf2, "IPRD") { Field = value });
+ {
+ _subChunks.Add(new HeaderSubChunk(_sf2, "IPRD") { Field = value });
+ }
}
}
public string Copyright
{
get
{
- if (subChunks.Find(s => s.ChunkName == "ICOP") is HeaderSubChunk icop)
+ if (_subChunks.Find(s => s.ChunkName == "ICOP") is HeaderSubChunk icop)
+ {
return icop.Field;
+ }
else
+ {
return string.Empty;
+ }
}
set
{
- if (subChunks.Find(s => s.ChunkName == "ICOP") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "ICOP") is HeaderSubChunk chunk)
+ {
chunk.Field = value;
+ }
else
- subChunks.Add(new HeaderSubChunk(sf2, "ICOP") { Field = value });
+ {
+ _subChunks.Add(new HeaderSubChunk(_sf2, "ICOP") { Field = value });
+ }
}
}
- const int commentMaxSize = 0x10000;
+
+ private const int CommentMaxSize = 0x10000;
public string Comment
{
get
{
- if (subChunks.Find(s => s.ChunkName == "ICMT") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "ICMT") is HeaderSubChunk chunk)
+ {
return chunk.Field;
+ }
else
+ {
return string.Empty;
+ }
}
set
{
- if (subChunks.Find(s => s.ChunkName == "ICMT") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "ICMT") is HeaderSubChunk chunk)
+ {
chunk.Field = value;
+ }
else
- subChunks.Add(new HeaderSubChunk(sf2, "ICMT", commentMaxSize) { Field = value });
+ {
+ _subChunks.Add(new HeaderSubChunk(_sf2, "ICMT", maxSize: CommentMaxSize) { Field = value });
+ }
}
}
public string Tools
{
get
{
- if (subChunks.Find(s => s.ChunkName == "ISFT") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "ISFT") is HeaderSubChunk chunk)
+ {
return chunk.Field;
+ }
else
+ {
return string.Empty;
+ }
}
set
{
- if (subChunks.Find(s => s.ChunkName == "ISFT") is HeaderSubChunk chunk)
+ if (_subChunks.Find(s => s.ChunkName == "ISFT") is HeaderSubChunk chunk)
+ {
chunk.Field = value;
+ }
else
- subChunks.Add(new HeaderSubChunk(sf2, "ISFT") { Field = value });
+ {
+ _subChunks.Add(new HeaderSubChunk(_sf2, "ISFT") { Field = value });
+ }
}
}
-
+
internal InfoListChunk(SF2 inSf2) : base(inSf2, "INFO")
{
// Mandatory sub-chunks
- subChunks.Add(new VersionSubChunk(inSf2, "ifil") { Version = new SF2VersionTag(2, 1) });
- subChunks.Add(new HeaderSubChunk(inSf2, "isng") { Field = defaultEngine });
- subChunks.Add(new HeaderSubChunk(inSf2, "INAM") { Field = defaultBank });
- sf2.UpdateSize();
+ _subChunks.Add(new VersionSubChunk(inSf2, "ifil") { Version = new SF2VersionTag(2, 1) });
+ _subChunks.Add(new HeaderSubChunk(inSf2, "isng") { Field = DefaultEngine });
+ _subChunks.Add(new HeaderSubChunk(inSf2, "INAM") { Field = DefaultBank });
+ inSf2.UpdateSize();
}
- internal InfoListChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal InfoListChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
- var startOffset = reader.BaseStream.Position;
+ long startOffset = reader.BaseStream.Position;
while (reader.BaseStream.Position < startOffset + Size - 4) // The 4 represents the INFO that was already read
{
// Peek 4 chars for the chunk name
- char[] name = reader.ReadChars(4);
+ string name = reader.ReadString(4, false);
reader.BaseStream.Position -= 4;
- string strName = new string(name);
- switch (strName)
+ switch (name)
{
- case "ICMT": subChunks.Add(new HeaderSubChunk(inSf2, reader, commentMaxSize)); break;
+ case "ICMT": _subChunks.Add(new HeaderSubChunk(inSf2, reader, maxSize: CommentMaxSize)); break;
case "ifil":
- case "iver": subChunks.Add(new VersionSubChunk(inSf2, reader)); break;
+ case "iver": _subChunks.Add(new VersionSubChunk(inSf2, reader)); break;
case "isng":
case "INAM":
case "ICRD":
@@ -811,48 +965,51 @@ internal InfoListChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
case "IPRD":
case "ICOP":
case "ISFT":
- case "irom": subChunks.Add(new HeaderSubChunk(inSf2, reader)); break;
- default:
- throw new NotSupportedException($"Unsupported chunk name at 0x{reader.BaseStream.Position:X}: \"{strName}\"");
+ case "irom": _subChunks.Add(new HeaderSubChunk(inSf2, reader)); break;
+ default: throw new NotSupportedException($"Unsupported chunk name at 0x{reader.BaseStream.Position:X}: \"{name}\"");
}
}
}
- internal override void Write(BinaryWriter writer)
- {
- base.Write(writer);
- foreach (var sub in subChunks)
- sub.Write(writer);
- }
internal override uint UpdateSize()
{
Size = 4;
- foreach (var sub in subChunks)
+ foreach (SF2Chunk sub in _subChunks)
+ {
Size += sub.Size + 8;
+ }
+
return Size;
}
- public override string ToString() => $"Info List Chunk - Sub-chunk count = {subChunks.Count}";
+ internal override void Write(EndianBinaryWriter writer)
+ {
+ base.Write(writer);
+ foreach (SF2Chunk sub in _subChunks)
+ {
+ sub.Write(writer);
+ }
+ }
+
+ public override string ToString()
+ {
+ return $"Info List Chunk - Sub-chunk count = {_subChunks.Count}";
+ }
}
public sealed class SdtaListChunk : SF2ListChunk
{
- public readonly SMPLSubChunk SMPLSubChunk;
+ public SMPLSubChunk SMPLSubChunk { get; }
internal SdtaListChunk(SF2 inSf2) : base(inSf2, "sdta")
{
SMPLSubChunk = new SMPLSubChunk(inSf2);
- sf2.UpdateSize();
+ inSf2.UpdateSize();
}
- internal SdtaListChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal SdtaListChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
SMPLSubChunk = new SMPLSubChunk(inSf2, reader);
}
- internal override void Write(BinaryWriter writer)
- {
- base.Write(writer);
- SMPLSubChunk.Write(writer);
- }
internal override uint UpdateSize()
{
@@ -860,20 +1017,29 @@ internal override uint UpdateSize()
+ SMPLSubChunk.Size + 8;
}
- public override string ToString() => $"Sample Data List Chunk";
+ internal override void Write(EndianBinaryWriter writer)
+ {
+ base.Write(writer);
+ SMPLSubChunk.Write(writer);
+ }
+
+ public override string ToString()
+ {
+ return $"Sample Data List Chunk";
+ }
}
public sealed class PdtaListChunk : SF2ListChunk
{
- public readonly PHDRSubChunk PHDRSubChunk;
- public readonly BAGSubChunk PBAGSubChunk;
- public readonly MODSubChunk PMODSubChunk;
- public readonly GENSubChunk PGENSubChunk;
- public readonly INSTSubChunk INSTSubChunk;
- public readonly BAGSubChunk IBAGSubChunk;
- public readonly MODSubChunk IMODSubChunk;
- public readonly GENSubChunk IGENSubChunk;
- public readonly SHDRSubChunk SHDRSubChunk;
+ public PHDRSubChunk PHDRSubChunk { get; }
+ public BAGSubChunk PBAGSubChunk { get; }
+ public MODSubChunk PMODSubChunk { get; }
+ public GENSubChunk PGENSubChunk { get; }
+ public INSTSubChunk INSTSubChunk { get; }
+ public BAGSubChunk IBAGSubChunk { get; }
+ public MODSubChunk IMODSubChunk { get; }
+ public GENSubChunk IGENSubChunk { get; }
+ public SHDRSubChunk SHDRSubChunk { get; }
internal PdtaListChunk(SF2 inSf2) : base(inSf2, "pdta")
{
@@ -886,9 +1052,9 @@ internal PdtaListChunk(SF2 inSf2) : base(inSf2, "pdta")
IMODSubChunk = new MODSubChunk(inSf2, false);
IGENSubChunk = new GENSubChunk(inSf2, false);
SHDRSubChunk = new SHDRSubChunk(inSf2);
- sf2.UpdateSize();
+ inSf2.UpdateSize();
}
- internal PdtaListChunk(SF2 inSf2, BinaryReader reader) : base(inSf2, reader)
+ internal PdtaListChunk(SF2 inSf2, EndianBinaryReader reader) : base(inSf2, reader)
{
PHDRSubChunk = new PHDRSubChunk(inSf2, reader);
PBAGSubChunk = new BAGSubChunk(inSf2, reader);
@@ -915,7 +1081,7 @@ internal override uint UpdateSize()
+ SHDRSubChunk.Size + 8;
}
- internal override void Write(BinaryWriter writer)
+ internal override void Write(EndianBinaryWriter writer)
{
base.Write(writer);
PHDRSubChunk.Write(writer);
@@ -929,7 +1095,10 @@ internal override void Write(BinaryWriter writer)
SHDRSubChunk.Write(writer);
}
- public override string ToString() => $"Hydra List Chunk";
+ public override string ToString()
+ {
+ return $"Hydra List Chunk";
+ }
}
#endregion
diff --git a/SoundFont2/SF2Types.cs b/SoundFont2/SF2Types.cs
index 9a5b153..b297d80 100644
--- a/SoundFont2/SF2Types.cs
+++ b/SoundFont2/SF2Types.cs
@@ -1,25 +1,40 @@
-using System.Runtime.InteropServices;
+using Kermalis.EndianBinaryIO;
+using System.Runtime.InteropServices;
namespace Kermalis.SoundFont2
{
- // SF2 v2.1 spec page 16
+ /// SF2 v2.1 spec page 16
public sealed class SF2VersionTag
{
public const uint Size = 4;
- public readonly ushort Major;
- public readonly ushort Minor;
+ public ushort Major { get; }
+ public ushort Minor { get; }
public SF2VersionTag(ushort major, ushort minor)
{
- Major = major; Minor = minor;
+ Major = major;
+ Minor = minor;
+ }
+ internal SF2VersionTag(EndianBinaryReader reader)
+ {
+ Major = reader.ReadUInt16();
+ Minor = reader.ReadUInt16();
+ }
+
+ internal void Write(EndianBinaryWriter writer)
+ {
+ writer.Write(Major);
+ writer.Write(Minor);
}
- public override string ToString() => $"v{Major}.{Minor}";
+ public override string ToString()
+ {
+ return $"v{Major}.{Minor}";
+ }
}
- // SF2 spec v2.1 page 19
- // Two bytes that can handle either two 8-bit values or a single 16-bit value
+ /// SF2 spec v2.1 page 19 - Two bytes that can handle either two 8-bit values or a single 16-bit value
[StructLayout(LayoutKind.Explicit)]
public struct SF2GeneratorAmount
{
@@ -28,10 +43,13 @@ public struct SF2GeneratorAmount
[FieldOffset(0)] public short Amount;
[FieldOffset(0)] public ushort UAmount;
- public override string ToString() => $"BLo = {LowByte}, BHi = {HighByte}, Sh = {Amount}, U = {UAmount}";
+ public override string ToString()
+ {
+ return $"BLo = {LowByte}, BHi = {HighByte}, Sh = {Amount}, U = {UAmount}";
+ }
}
- // SF2 v2.1 spec page 20
+ /// SF2 v2.1 spec page 20
public enum SF2SampleLink : ushort
{
MonoSample = 1,
@@ -44,7 +62,7 @@ public enum SF2SampleLink : ushort
RomLinkedSample = 0x8008
}
- // SF2 v2.1 spec page 38
+ /// SF2 v2.1 spec page 38
public enum SF2Generator : ushort
{
StartAddrsOffset = 0,
@@ -102,8 +120,7 @@ public enum SF2Generator : ushort
EndOper = 60
}
- // Modulator's internal enumeration class
- // SF2 v2.1 spec page 50
+ /// SF2 v2.1 spec page 50
public enum SF2Modulator : ushort
{
None = 0,
@@ -115,7 +132,7 @@ public enum SF2Modulator : ushort
PitchWheelSensivity = 16
}
- // SF2 v2.1 spec page 52
+ /// SF2 v2.1 spec page 52
public enum SF2Transform : ushort
{
Linear = 0,
diff --git a/SoundFont2/SF2Utils.cs b/SoundFont2/SF2Utils.cs
deleted file mode 100644
index da76c4d..0000000
--- a/SoundFont2/SF2Utils.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Linq;
-
-namespace Kermalis.SoundFont2
-{
- static class SF2Utils
- {
- public static void TruncateOrNot(string str, int length, ref char[] toArray)
- {
- toArray = new char[length];
- var strAsChars = str.ToCharArray().Take(length).ToArray();
- Buffer.BlockCopy(strAsChars, 0, toArray, 0, strAsChars.Length * 2);
- }
- }
-}
diff --git a/SoundFont2/SoundFont2.csproj b/SoundFont2/SoundFont2.csproj
index ac2e748..3ed4200 100644
--- a/SoundFont2/SoundFont2.csproj
+++ b/SoundFont2/SoundFont2.csproj
@@ -2,14 +2,25 @@
netstandard2.0
-
-
-
- ..\Build
+ Release
+ Kermalis
+
+ SoundFont2
+ SoundFont2
+ SoundFont2
+ Kermalis.SoundFont2
+ 1.0.0.0
..\Build
+ Auto
+ none
+ false
+
+
+
+