using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace CsbBuilder.Audio
{
///
/// Represents a static class for calling native VGMSTREAM methods.
///
public static class VGMStreamNative
{
///
/// Path of the VGMSTREAM DLL file.
///
public const string DllName = "vgmstream.dll";
#region VGMStream Exports
///
/// Initializes a VGMSTREAM from source file name by doing format detection and returns a usable pointer
/// to it, or NULL on failure.
///
/// Path to source file name.
/// Pointer to VGMSTREAM or NULL on failure.
[DllImport(DllName, EntryPoint = "init_vgmstream", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr Initialize(string sourceFileName);
///
/// Initializes a VGMSTREAM from stream file by doing format detection and returns a usable pointer
/// to it, or NULL on failure.
///
/// Pointer to stream file.
/// Pointer to VGMSTREAM or NULL on failure.
[DllImport(DllName, EntryPoint = "init_from_STREAMFILE", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr InitializeFromStreamFile(IntPtr streamFile);
///
/// Resets a VGMSTREAM to start of stream.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "reset_vgmstream", CallingConvention = CallingConvention.Cdecl)]
public static extern void Reset(IntPtr vgmstream);
///
/// Closes an open VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "close_vgmstream", CallingConvention = CallingConvention.Cdecl)]
public static extern void Close(IntPtr vgmstream);
///
/// Calculates the number of samples to be played based on looping parameters.
///
[DllImport(DllName, EntryPoint = "get_vgmstream_play_samples", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetPlaySamples(double loopTimes, double fadeSeconds, double fadeDelaySeconds, IntPtr vgmstream);
///
/// Renders VGMSTREAM to sample buffer.
///
/// Destination sample buffer.
/// Amount of samples to render.
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "render_vgmstream", CallingConvention = CallingConvention.Cdecl)]
public static extern void Render(short[] buffer, int sampleCount, IntPtr vgmstream);
///
/// Renders VGMSTREAM to byte buffer.
///
/// Destination byte buffer.
/// Amount of samples to render.
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "render_vgmstream", CallingConvention = CallingConvention.Cdecl)]
public static extern void Render8(byte[] buffer, int sampleCount, IntPtr vgmstream);
///
/// Writes a description of the stream into array pointed by description,
/// which must be length bytes long. Will always be null-terminated if length > 0
///
[DllImport(DllName, EntryPoint = "describe_vgmstream", CallingConvention = CallingConvention.Cdecl)]
public static extern void Describe(IntPtr vgmstream, IntPtr description, int length);
///
/// Returns the average bitrate in bps of all unique files contained within
/// this stream. Compares files by absolute paths.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "get_vgmstream_average_bitrate", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetAverageBitrate(IntPtr vgmstream);
///
/// Allocates a VGMSTREAM.
///
[DllImport(DllName, EntryPoint = "allocate_vgmstream", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr Allocate(int channelCount, [MarshalAs(UnmanagedType.I4)]bool looped);
///
/// smallest self-contained group of samples is a frame
///
[DllImport(DllName, EntryPoint = "get_vgmstream_samples_per_frame", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetSamplesPerFrame(IntPtr vgmstream);
///
/// Gets the number of bytes per frame.
///
[DllImport(DllName, EntryPoint = "get_vgmstream_frame_size", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetFrameSize(IntPtr vgmstream);
///
/// in NDS IMA the frame size is the block size, so the last one is short
///
[DllImport(DllName, EntryPoint = "get_vgmstream_samples_per_shortframe", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetSamplesPerShortframe(IntPtr vgmstream);
[DllImport(DllName, EntryPoint = "get_vgmstream_shortframe_size", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetShortframeSize(IntPtr vgmstream);
///
/// Assumes that we have written samplesWrittem into the buffer already, and we have samplesToDo consecutive
/// samples ahead of us. Decode those samples into the buffer.
///
[DllImport(DllName, EntryPoint = "decode_vgmstream", CallingConvention = CallingConvention.Cdecl)]
public static extern void Decode(IntPtr vgmstream, int samplesWritten, int samplesToDo, short[] buffer);
///
/// Assumes additionally that we have samplesToDo consecutive samples in "data",
/// and this this is for channel number "channel".
///
[DllImport(DllName, EntryPoint = "decode_vgmstream_mem", CallingConvention = CallingConvention.Cdecl)]
public static extern void DecodeMem(IntPtr vgmstream, int samplesWritten, int samplesToDo, short[] buffer, byte[] data, int channel);
///
/// Calculates number of consecutive samples to do (taking into account stopping for loop start and end.)
///
[DllImport(DllName, EntryPoint = "vgmstream_samples_to_do", CallingConvention = CallingConvention.Cdecl)]
public static extern int SamplesToDo(int samplesThisBlock, int samplesPerFrame, IntPtr vgmstream);
///
/// Detects start and save values, also detects end and restore values. Only works on exact sample values.
///
[DllImport(DllName, EntryPoint = "vgmstream_do_loop", CallingConvention = CallingConvention.Cdecl)]
public static extern int DoLoop(IntPtr vgmstream);
///
/// Opens a stream for reading at offset (standarized taking into account layouts, channels and so on.)
/// returns 0 on failure
///
[DllImport(DllName, EntryPoint = "vgmstream_open_stream", CallingConvention = CallingConvention.Cdecl)]
public static extern int OpenStream(IntPtr vgmstream, IntPtr streamFile, long position);
#endregion
#region Format Exports
///
/// Gets a pointer to the array of supported formats.
///
[DllImport(DllName, EntryPoint = "vgmstream_get_formats", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetFormatsPtr(out int count);
[DllImport(DllName, EntryPoint = "get_vgmstream_coding_description", CallingConvention = CallingConvention.Cdecl)]
public static extern string GetCodingDescription(int codingEnumCode);
[DllImport(DllName, EntryPoint = "get_vgmstream_layout_description", CallingConvention = CallingConvention.Cdecl)]
public static extern string GetLayoutDescription(int layoutEnumCode);
[DllImport(DllName, EntryPoint = "get_vgmstream_meta_description", CallingConvention = CallingConvention.Cdecl)]
public static extern string GetMetaDescription(int metaEnumCode);
#endregion
#region Helper Methods
///
/// Gets the sample count of a VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "get_vgmstream_sample_count", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetSampleCount(IntPtr vgmstream);
///
/// Gets the sample rate of a VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "get_vgmstream_sample_rate", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetSampleRate(IntPtr vgmstream);
///
/// Gets the channel count of a VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "get_vgmstream_channels", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetChannelCount(IntPtr vgmstream);
///
/// Gets the absolute sample count of a VGMSTREAM.
/// (sample count * channel count)
///
/// Pointer to VGMSTREAM.
public static int GetAbsoluteSampleCount(IntPtr vgmstream)
{
return GetSampleCount(vgmstream) * GetChannelCount(vgmstream);
}
///
/// Gets the loop flag of a VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "get_vgmstream_loop_flag", CallingConvention = CallingConvention.Cdecl)]
public static extern bool GetLoopFlag(IntPtr vgmstream);
///
/// Sets the loop flag of a VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "set_vgmstream_loop_flag", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetLoopFlag(IntPtr vgmstream, bool value);
///
/// Gets the loop start sample of a VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "get_vgmstream_loop_start_sample", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetLoopStartSample(IntPtr vgmstream);
///
/// Sets the loop start sample of a VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "set_vgmstream_loop_start_sample", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetLoopStartSample(IntPtr vgmstream, int value);
///
/// Gets the loop end sample of a VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "get_vgmstream_loop_end_sample", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetLoopEndSample(IntPtr vgmstream);
///
/// Sets the loop end sample of a VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "set_vgmstream_loop_end_sample", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetLoopEndSample(IntPtr vgmstream, int value);
///
/// Gets the current sample of a VGMSTREAM.
///
/// Pointer to VGMSTREAM.
[DllImport(DllName, EntryPoint = "get_vgmstream_current_sample", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetCurrentSample(IntPtr vgmstream);
///
/// Gets an array of supported formats.
///
/// Pointer to VGMSTREAM.
public static string[] GetFormats()
{
IntPtr ptr = GetFormatsPtr(out int count);
string[] formats = new string[count];
for (int i = 0; i < formats.Length; i++)
{
IntPtr stringPtr = Marshal.ReadIntPtr(ptr, i * IntPtr.Size);
formats[i] = Marshal.PtrToStringAnsi(stringPtr);
}
return formats;
}
#endregion
}
}