Skip to content

Commit

Permalink
Update after since ages since a long time
Browse files Browse the repository at this point in the history
Kermalis committed Sep 11, 2020
1 parent 0aae6b2 commit aedbd7b
Showing 6 changed files with 618 additions and 463 deletions.
3 changes: 0 additions & 3 deletions SoundFont2.sln
Original file line number Diff line number Diff line change
@@ -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
102 changes: 39 additions & 63 deletions SoundFont2/SF2.cs
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
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
/// <summary>For creating</summary>
public SF2()
{
InfoChunk = new InfoListChunk(this);
SoundChunk = new SdtaListChunk(this);
HydraChunk = new PdtaListChunk(this);
}

// For reading
/// <summary>For reading</summary>
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
/// <summary>Returns sample index</summary>
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,81 +78,53 @@ 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
/// <summary>Returns instrument index</summary>
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()
{
HydraChunk.IBAGSubChunk.AddBag(new SF2Bag(this, false));
}
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()
{
HydraChunk.PBAGSubChunk.AddBag(new SF2Bag(this, true));
}
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;
897 changes: 533 additions & 364 deletions SoundFont2/SF2Chunks.cs

Large diffs are not rendered by default.

45 changes: 31 additions & 14 deletions SoundFont2/SF2Types.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
using System.Runtime.InteropServices;
using Kermalis.EndianBinaryIO;
using System.Runtime.InteropServices;

namespace Kermalis.SoundFont2
{
// SF2 v2.1 spec page 16
/// <summary>SF2 v2.1 spec page 16</summary>
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
/// <summary>SF2 spec v2.1 page 19 - Two bytes that can handle either two 8-bit values or a single 16-bit value</summary>
[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
/// <summary>SF2 v2.1 spec page 20</summary>
public enum SF2SampleLink : ushort
{
MonoSample = 1,
@@ -44,7 +62,7 @@ public enum SF2SampleLink : ushort
RomLinkedSample = 0x8008
}

// SF2 v2.1 spec page 38
/// <summary>SF2 v2.1 spec page 38</summary>
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
/// <summary>SF2 v2.1 spec page 50</summary>
public enum SF2Modulator : ushort
{
None = 0,
@@ -115,7 +132,7 @@ public enum SF2Modulator : ushort
PitchWheelSensivity = 16
}

// SF2 v2.1 spec page 52
/// <summary>SF2 v2.1 spec page 52</summary>
public enum SF2Transform : ushort
{
Linear = 0,
15 changes: 0 additions & 15 deletions SoundFont2/SF2Utils.cs

This file was deleted.

19 changes: 15 additions & 4 deletions SoundFont2/SoundFont2.csproj
Original file line number Diff line number Diff line change
@@ -2,14 +2,25 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\Build</OutputPath>
<Configurations>Release</Configurations>
<Authors>Kermalis</Authors>
<Company />
<PackageId>SoundFont2</PackageId>
<Product>SoundFont2</Product>
<AssemblyName>SoundFont2</AssemblyName>
<RootNamespace>Kermalis.SoundFont2</RootNamespace>
<Version>1.0.0.0</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputPath>..\Build</OutputPath>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="EndianBinaryIO" Version="1.1.1" />
</ItemGroup>

</Project>

0 comments on commit aedbd7b

Please sign in to comment.