-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 53ec877
Showing
19 changed files
with
1,095 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.vs | ||
*.suo | ||
bin/ | ||
obj/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace LADSPA.NET | ||
{ | ||
public class DssiDescriptor | ||
{ | ||
public readonly LadspaLibraryContext Library; | ||
public readonly LadspaDescriptor LadspaDescriptor; | ||
public readonly bool IsSynth; | ||
|
||
internal readonly IntPtr DataHandle; | ||
internal readonly DssiDescriptorConfigureCallback Configure; | ||
internal readonly DssiDescriptorGetProgramCallback GetProgram; | ||
internal readonly DssiDescriptorSelectProgramCallback SelectProgram; | ||
internal readonly DssiDescriptorGetMidiControllerForPortCallback GetMidiControllerForPort; | ||
internal readonly DssiDescriptorRunSynthCallback RunSynth; | ||
internal readonly DssiDescriptorRunSynthCallback RunSynthAdding; | ||
internal readonly DssiDescriptorRunMultiSynthCallback RunMultiSynth; | ||
internal readonly DssiDescriptorRunMultiSynthCallback RunMultiSynthAdding; | ||
|
||
private DssiProgramDescriptor[] _programs; | ||
public DssiProgramDescriptor[] Programs | ||
{ | ||
get | ||
{ | ||
lock (this) | ||
{ | ||
if (_programs == null) | ||
{ | ||
if (LadspaDescriptor.Instantiate != null && LadspaDescriptor.Cleanup != null) | ||
{ | ||
IntPtr handle = LadspaDescriptor.Instantiate(LadspaDescriptor.DataHandle, 44100); | ||
if (handle != IntPtr.Zero) | ||
{ | ||
try { _programs = LoadProgramsFromHandle(handle); } | ||
finally { LadspaDescriptor.Cleanup(handle); } | ||
} | ||
} | ||
if (_programs == null) { _programs = new DssiProgramDescriptor[0]; } | ||
} | ||
return (_programs); | ||
} | ||
} | ||
} | ||
|
||
internal DssiDescriptor(LadspaLibraryContext library, uint index, IntPtr dataPtr) | ||
{ | ||
DssiDescriptorStruct data = (DssiDescriptorStruct)Marshal.PtrToStructure(dataPtr, typeof(DssiDescriptorStruct)); | ||
Library = library; | ||
DataHandle = dataPtr; | ||
LadspaDescriptor = new LadspaDescriptor(library, index, data.LadspaDescriptor); | ||
if (data.Configure != IntPtr.Zero) { Configure = (DssiDescriptorConfigureCallback)Marshal.GetDelegateForFunctionPointer(data.Configure, typeof(DssiDescriptorConfigureCallback)); } | ||
if (data.GetProgram != IntPtr.Zero) { GetProgram = (DssiDescriptorGetProgramCallback)Marshal.GetDelegateForFunctionPointer(data.GetProgram, typeof(DssiDescriptorGetProgramCallback)); } | ||
if (data.SelectProgram != IntPtr.Zero) { SelectProgram = (DssiDescriptorSelectProgramCallback)Marshal.GetDelegateForFunctionPointer(data.SelectProgram, typeof(DssiDescriptorSelectProgramCallback)); } | ||
if (data.GetMidiControllerForPort != IntPtr.Zero) { GetMidiControllerForPort = (DssiDescriptorGetMidiControllerForPortCallback)Marshal.GetDelegateForFunctionPointer(data.GetMidiControllerForPort, typeof(DssiDescriptorGetMidiControllerForPortCallback)); } | ||
if (data.RunSynth != IntPtr.Zero) { RunSynth = (DssiDescriptorRunSynthCallback)Marshal.GetDelegateForFunctionPointer(data.RunSynth, typeof(DssiDescriptorRunSynthCallback)); } | ||
if (data.RunSynthAdding != IntPtr.Zero) { RunSynthAdding = (DssiDescriptorRunSynthCallback)Marshal.GetDelegateForFunctionPointer(data.RunSynthAdding, typeof(DssiDescriptorRunSynthCallback)); } | ||
if (data.RunMultiSynth != IntPtr.Zero) { RunMultiSynth = (DssiDescriptorRunMultiSynthCallback)Marshal.GetDelegateForFunctionPointer(data.RunMultiSynth, typeof(DssiDescriptorRunMultiSynthCallback)); } | ||
if (data.RunMultiSynthAdding != IntPtr.Zero) { RunMultiSynthAdding = (DssiDescriptorRunMultiSynthCallback)Marshal.GetDelegateForFunctionPointer(data.RunMultiSynthAdding, typeof(DssiDescriptorRunMultiSynthCallback)); } | ||
IsSynth = data.RunSynth != null; | ||
} | ||
|
||
public DssiInstance CreateInstance(int sampleRate, int bufferSize = 1024) | ||
{ | ||
IntPtr handle = LadspaDescriptor.Instantiate != null ? LadspaDescriptor.Instantiate(LadspaDescriptor.DataHandle, (uint)sampleRate) : IntPtr.Zero; | ||
if (handle == IntPtr.Zero) { throw new Exception("Failed to create instance."); } | ||
lock (this) { if (_programs == null) { _programs = LoadProgramsFromHandle(handle); } } | ||
return (new DssiInstance(this, handle, sampleRate, bufferSize)); | ||
} | ||
|
||
private DssiProgramDescriptor[] LoadProgramsFromHandle(IntPtr handle) | ||
{ | ||
List<DssiProgramDescriptor> programs = new List<DssiProgramDescriptor>(); | ||
if (GetProgram != null) | ||
{ | ||
for (uint index = 0; true; index++) | ||
{ | ||
IntPtr programPtr = GetProgram(handle, index); | ||
if (programPtr == IntPtr.Zero) { break; } | ||
programs.Add((DssiProgramDescriptor)Marshal.PtrToStructure(programPtr, typeof(DssiProgramDescriptor))); | ||
} | ||
} | ||
return (programs.ToArray()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace LADSPA.NET | ||
{ | ||
[StructLayout(LayoutKind.Sequential)] | ||
internal struct DssiDescriptorStruct | ||
{ | ||
public uint APIVersion; | ||
public IntPtr LadspaDescriptor; // LadspaDescriptorStruct | ||
public IntPtr Configure; // string (IntPtr handle, string key, string value) | ||
public IntPtr GetProgram; // IntPtr (IntPtr handle, uint index) | ||
public IntPtr SelectProgram; // void (IntPtr handle, uint bank, uint program) | ||
public IntPtr GetMidiControllerForPort; // int (IntPtr handle, uint port) | ||
public IntPtr RunSynth; // void (IntPtr thisPtr, uint sampleCount, IntPtr events, uint eventCount) | ||
public IntPtr RunSynthAdding; // void (IntPtr thisPtr, uint sampleCount, IntPtr events, uint eventCount) | ||
public IntPtr RunMultiSynth; // void (uint thisCount, IntPtr thisPtrs, uint sampleCount, IntPtr events, IntPtr eventCounts) | ||
public IntPtr RunMultiSynthAdding; // void (uint thisCount, IntPtr thisPtrs, uint sampleCount, IntPtr events, IntPtr eventCounts) | ||
} | ||
|
||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
internal delegate string DssiDescriptorConfigureCallback(IntPtr thisPtr, string key, string value); | ||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
internal delegate IntPtr DssiDescriptorGetProgramCallback(IntPtr thisPtr, uint index); | ||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
internal delegate void DssiDescriptorSelectProgramCallback(IntPtr thisPtr, uint bank, uint program); | ||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
internal delegate int DssiDescriptorGetMidiControllerForPortCallback(IntPtr thisPtr, uint port); | ||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
internal delegate void DssiDescriptorRunSynthCallback(IntPtr thisPtr, uint sampleCount, IntPtr events, uint eventCount); | ||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
internal delegate void DssiDescriptorRunMultiSynthCallback(uint thisCount, IntPtr thisPtrs, uint sampleCount, IntPtr events, IntPtr eventCounts); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace LADSPA.NET | ||
{ | ||
public class DssiInstance : LadspaInstance | ||
{ | ||
public readonly DssiDescriptor DssiDescriptor; | ||
|
||
protected readonly List<DssiMidiEvent> eventList = new List<DssiMidiEvent>(); | ||
protected IntPtr eventBuffer; | ||
protected int eventBufferSize; | ||
protected int eventBufferCount; | ||
|
||
internal DssiInstance(DssiDescriptor descriptor, IntPtr handle, int sampleRate, int bufferSize) | ||
: base(descriptor.LadspaDescriptor, handle, sampleRate, bufferSize) | ||
{ | ||
DssiDescriptor = descriptor; | ||
} | ||
|
||
protected void PrepareEvents() | ||
{ | ||
int i, offset, count = eventList.Count; | ||
int size = count * 28; | ||
if (eventBuffer == IntPtr.Zero || eventBufferSize < size) | ||
{ | ||
if (eventBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(eventBuffer); eventBuffer = IntPtr.Zero; } | ||
eventBuffer = Marshal.AllocHGlobal(eventBufferSize = size + 140); | ||
} | ||
for (i = 0, offset = 0, eventBufferCount = 0; i < count; i++) | ||
{ | ||
DssiMidiEvent e = eventList[i]; | ||
int command = e.MidiCommand & 0xf0; | ||
switch (command) | ||
{ | ||
case 0x80: // Note Off | ||
case 0x90: // Note On | ||
case 0xA0: // Aftertouch | ||
int code = (command == 0x80 || (e.MidiData1 == 0 && command == 0x90)) ? 7 : command == 0x90 ? 6 : 8; | ||
Marshal.WriteInt32(eventBuffer, offset, code); offset += 4; // Type code | ||
Marshal.WriteInt32(eventBuffer, offset, e.SampleIndex); offset += 4; // Ticks | ||
Marshal.WriteInt64(eventBuffer, offset, 0); offset += 8; // Realtime timestamp + addresses (not used) | ||
Marshal.WriteByte(eventBuffer, offset, (byte)(e.MidiCommand & 0x0f)); offset++; // Channel | ||
Marshal.WriteByte(eventBuffer, offset, e.MidiData0); offset++; // Pitch | ||
Marshal.WriteByte(eventBuffer, offset, e.MidiData1 == 0 ? (byte)64 : e.MidiData1); offset++; // Velocity | ||
Marshal.WriteByte(eventBuffer, offset, 0); offset++; // Off Velocity (not used) | ||
Marshal.WriteInt64(eventBuffer, offset, 0); offset += 8; // Duration (not used) | ||
eventBufferCount++; | ||
break; | ||
|
||
case 0xB0: // Controller | ||
Marshal.WriteInt32(eventBuffer, offset, 10); offset += 4; // Type code | ||
Marshal.WriteInt32(eventBuffer, offset, e.SampleIndex); offset += 4; // Ticks | ||
Marshal.WriteInt64(eventBuffer, offset, 0); offset += 8; // Realtime timestamp + addresses (not used) | ||
Marshal.WriteInt32(eventBuffer, offset, e.MidiCommand & 0x0f); offset += 4; // Channel + Unused | ||
Marshal.WriteInt32(eventBuffer, offset, e.MidiData0); offset += 4; // Control parameter | ||
Marshal.WriteInt32(eventBuffer, offset, e.MidiData1); offset += 4; // Value | ||
eventBufferCount++; | ||
break; | ||
|
||
case 0xC0: // Change program | ||
SelectProgram((uint)(e.MidiCommand & 0x0f), e.MidiData0); | ||
break; | ||
|
||
case 0xD0: // Channel pressure | ||
Marshal.WriteInt32(eventBuffer, offset, 12); offset += 4; // Type code | ||
Marshal.WriteInt32(eventBuffer, offset, e.SampleIndex); offset += 4; // Ticks | ||
Marshal.WriteInt64(eventBuffer, offset, 0); offset += 8; // Realtime timestamp + addresses (not used) | ||
Marshal.WriteInt32(eventBuffer, offset, e.MidiCommand & 0x0f); offset += 4; // Channel + Unused | ||
Marshal.WriteInt32(eventBuffer, offset, 0); offset += 4; // Control parameter | ||
Marshal.WriteInt32(eventBuffer, offset, e.MidiData0); offset += 4; // Value | ||
eventBufferCount++; | ||
break; | ||
|
||
case 0xE0: // Pitchbend | ||
Marshal.WriteInt32(eventBuffer, offset, 13); offset += 4; // Type code | ||
Marshal.WriteInt32(eventBuffer, offset, e.SampleIndex); offset += 4; // Ticks | ||
Marshal.WriteInt64(eventBuffer, offset, 0); offset += 8; // Realtime timestamp + addresses (not used) | ||
Marshal.WriteInt32(eventBuffer, offset, e.MidiCommand & 0x0f); offset += 4; // Channel + Unused | ||
Marshal.WriteInt32(eventBuffer, offset, 0); offset += 4; // Control parameter | ||
Marshal.WriteInt32(eventBuffer, offset, (short)(((int)e.MidiData0 << 2) + ((int)e.MidiData1 << 9)) >> 2); offset += 4; // Value | ||
eventBufferCount++; | ||
break; | ||
} | ||
} | ||
eventList.Clear(); | ||
} | ||
|
||
public string Configure(string key, string value) | ||
{ | ||
if (handle == IntPtr.Zero || DssiDescriptor.Configure == null) { return (null); } | ||
return (DssiDescriptor.Configure(handle, key, value)); | ||
} | ||
|
||
public void SelectProgram(uint bank, uint program) | ||
{ | ||
if (handle == IntPtr.Zero || DssiDescriptor.SelectProgram == null) { return; } | ||
DssiDescriptor.SelectProgram(handle, bank, program); | ||
} | ||
|
||
public int GetMidiControllerForPort(uint port) | ||
{ | ||
if (handle == IntPtr.Zero || DssiDescriptor.GetMidiControllerForPort == null) { return (0); } | ||
return (DssiDescriptor.GetMidiControllerForPort(handle, port)); | ||
} | ||
|
||
public void AddSynthEvents(params DssiMidiEvent[] events) | ||
{ | ||
if (events != null && events.Length > 0) | ||
{ | ||
eventList.AddRange(events); | ||
} | ||
} | ||
|
||
public bool Run(float[][] outputs) | ||
{ | ||
if (handle != IntPtr.Zero) | ||
{ | ||
if (DssiDescriptor.RunSynth != null) | ||
{ | ||
PrepareEvents(); | ||
DssiDescriptor.RunSynth(handle, (uint)bufferSize, eventBuffer, (uint)eventBufferCount); | ||
CopyOutputs(outputs); | ||
return (true); | ||
} | ||
else if (LadspaDescriptor.Run != null) | ||
{ | ||
LadspaDescriptor.Run(handle, (uint)bufferSize); | ||
CopyOutputs(outputs); | ||
return (true); | ||
} | ||
} | ||
if (eventList.Count > 0) { eventList.Clear(); } | ||
return (false); | ||
} | ||
|
||
public bool RunAdding(float[][] outputs) | ||
{ | ||
if (handle != IntPtr.Zero) | ||
{ | ||
if (DssiDescriptor.RunSynthAdding != null) | ||
{ | ||
PrepareEvents(); | ||
DssiDescriptor.RunSynthAdding(handle, (uint)bufferSize, eventBuffer, (uint)eventBufferCount); | ||
CopyOutputs(outputs); | ||
return (true); | ||
} | ||
else if (LadspaDescriptor.RunAdding != null) | ||
{ | ||
LadspaDescriptor.RunAdding(handle, (uint)bufferSize); | ||
CopyOutputs(outputs); | ||
return (true); | ||
} | ||
} | ||
if (eventList.Count > 0) { eventList.Clear(); } | ||
return (false); | ||
} | ||
|
||
public override bool Run(float[][] inputs, float[][] outputs) | ||
{ | ||
if (handle != IntPtr.Zero) { CopyInputs(inputs); } | ||
return (Run(outputs)); | ||
} | ||
|
||
public override bool RunAdding(float[][] inputs, float[][] outputs) | ||
{ | ||
if (handle != IntPtr.Zero) { CopyInputs(inputs); } | ||
return (RunAdding(outputs)); | ||
} | ||
|
||
public override LadspaInstance Clone(int sampleRate = 0, int bufferSize = 0) | ||
{ | ||
if (sampleRate == 0) { sampleRate = this.sampleRate; } | ||
if (bufferSize == 0) { bufferSize = this.bufferSize; } | ||
DssiInstance instance = DssiDescriptor.CreateInstance(sampleRate, bufferSize); | ||
for (int i = 0; i < LadspaDescriptor.Ports.Length; i++) { instance.SetParameter(i, GetParameter(i)); } | ||
return (instance); | ||
} | ||
|
||
public override void Dispose() | ||
{ | ||
base.Dispose(); | ||
if (eventBuffer != IntPtr.Zero) | ||
{ | ||
Marshal.FreeHGlobal(eventBuffer); | ||
eventBuffer = IntPtr.Zero; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace LADSPA.NET | ||
{ | ||
public struct DssiMidiEvent | ||
{ | ||
public int SampleIndex; | ||
public byte MidiCommand; | ||
public byte MidiData0; | ||
public byte MidiData1; | ||
public byte MidiData2; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace LADSPA.NET | ||
{ | ||
[StructLayout(LayoutKind.Sequential)] | ||
public struct DssiProgramDescriptor | ||
{ | ||
public uint Bank; | ||
public uint Program; | ||
public string Name; | ||
} | ||
} |
Oops, something went wrong.