using System.Runtime.InteropServices; namespace Robovoice.Tts.LibPiper; [StructLayout(LayoutKind.Sequential)] internal struct PiperSynthesizeOptions { public int SpeakerId; public float LengthScale; public float NoiseScale; public float NoiseWScale; } [StructLayout(LayoutKind.Sequential)] internal struct PiperAudioChunk { public IntPtr Samples; public nuint NumSamples; public int SampleRate; [MarshalAs(UnmanagedType.U1)] public bool IsLast; public IntPtr Phonemes; public nuint NumPhonemes; public IntPtr PhonemeIds; public nuint NumPhonemeIds; public IntPtr Alignments; public nuint NumAlignments; } internal static class PiperNative { private const string LibName = "piper"; public const int PiperOk = 0; public const int PiperDone = 1; public const int PiperErrGeneric = -1; [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr piper_create( IntPtr modelPath, IntPtr configPath, IntPtr espeakDataPath); [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] public static extern void piper_free(IntPtr synth); [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] public static extern PiperSynthesizeOptions piper_default_synthesize_options(IntPtr synth); [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] public static extern int piper_synthesize_start( IntPtr synth, IntPtr text, in PiperSynthesizeOptions options); [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] public static extern int piper_synthesize_next( IntPtr synth, out PiperAudioChunk chunk); [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr piper_version(); }