<commit_before>// FIXMEs:
// - some bad mappings:
//	- C int -> C# int
//	- C long -> C# int
// not sure what they should be.
// The sources are wrong. Those C code should not use int and long for each.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

using PmDeviceID = System.Int32;
using PmTimestamp = System.Int32;
using PortMidiStream = System.IntPtr;
using PmMessage = System.Int32;
using PmError = Commons.Music.Midi.PortMidi.MidiErrorType;

namespace Commons.Music.Midi.PortMidi
{
	public class MidiDeviceManager
	{
		static MidiDeviceManager ()
		{
			PortMidiMarshal.Pm_Initialize ();
			AppDomain.CurrentDomain.DomainUnload += delegate (object o, EventArgs e) {
				PortMidiMarshal.Pm_Terminate ();
			};
		}

		public static int DeviceCount {
			get { return PortMidiMarshal.Pm_CountDevices (); }
		}

		public static int DefaultInputDeviceID {
			get { return PortMidiMarshal.Pm_GetDefaultInputDeviceID (); }
		}

		public static int DefaultOutputDeviceID {
			get { return PortMidiMarshal.Pm_GetDefaultOutputDeviceID (); }
		}

		public static IEnumerable<MidiDeviceInfo> AllDevices {
			get {
				for (int i = 0; i < DeviceCount; i++)
					yield return GetDeviceInfo (i);
			}
		}

		public static MidiDeviceInfo GetDeviceInfo (PmDeviceID id)
		{
			return new MidiDeviceInfo (id, PortMidiMarshal.Pm_GetDeviceInfo (id));
		}

		public static MidiInput OpenInput (PmDeviceID inputDevice)
		{
			return OpenInput (inputDevice, default_buffer_size);
		}

		const int default_buffer_size = 1024;

		public static MidiInput OpenInput (PmDeviceID inputDevice, int bufferSize)
		{
			PortMidiStream stream;
			var e = PortMidiMarshal.Pm_OpenInput (out stream, inputDevice, IntPtr.Zero, bufferSize, null, IntPtr.Zero);
			if (e != PmError.NoError)
				throw new MidiException (e, String.Format ("Failed to open MIDI input device {0}", e));
			return new MidiInput (stream, inputDevice);
		}

		public static MidiOutput OpenOutput (PmDeviceID outputDevice)
		{
			PortMidiStream stream;
			var e = PortMidiMarshal.Pm_OpenOutput (out stream, outputDevice, IntPtr.Zero, 0, null, IntPtr.Zero, 0);
			if (e != PmError.NoError)
				throw new MidiException (e, String.Format ("Failed to open MIDI output device {0}", e));
			return new MidiOutput (stream, outputDevice, 0);
		}
	}

	public enum MidiErrorType
	{
		NoError = 0,
		NoData = 0,
		GotData = 1,
		HostError = -10000,
		InvalidDeviceId,
		InsufficientMemory,
		BufferTooSmall,
		BufferOverflow,
		BadPointer,
		BadData,
		InternalError,
		BufferMaxSize,
	}

	public class MidiException : Exception
	{
		PmError error_type;

		public MidiException (PmError errorType, string message)
			: this (errorType, message, null)
		{
		}

		public MidiException (PmError errorType, string message, Exception innerException)
			: base (message, innerException)
		{
			error_type = errorType;
		}

		public PmError ErrorType {
			get { return error_type; }
		}
	}

	public struct MidiDeviceInfo
	{
		int id;
		PmDeviceInfo info;

		internal MidiDeviceInfo (int id, IntPtr ptr)
		{
			this.id = id;
			this.info = (PmDeviceInfo) Marshal.PtrToStructure (ptr, typeof (PmDeviceInfo));
		}

		public int ID {
			get { return id; }
			set { id = value; }
		}

		public string Interface {
			get { return Marshal.PtrToStringAnsi (info.Interface); }
		}

		public string Name {
			get { return Marshal.PtrToStringAnsi (info.Name); }
		}

		public bool IsInput { get { return info.Input != 0; } }
		public bool IsOutput { get { return info.Output != 0; } }
		public bool IsOpened { get { return info.Opened != 0; } }

		public override string ToString ()
		{
			return String.Format ("{0} - {1} ({2} {3})", Interface, Name, IsInput ? (IsOutput ? "I/O" : "Input") : (IsOutput ? "Output" : "N/A"), IsOpened ? "open" : String.Empty);
		}
	}

	public abstract class MidiStream : IDisposable
	{
		public static IEnumerable<MidiEvent> Convert (byte [] bytes, int index, int size)
		{
			int i = index;
			int end = index + size;
			while (i < end) {
				if (bytes [i] == 0xF0 || bytes [i] == 0xF7) {
					var tmp = new byte [size];
					Array.Copy (bytes, i, tmp, 0, tmp.Length);
					yield return new MidiEvent () {Message = new MidiMessage (0xF0, 0, 0), Data = tmp};
					i += size + 1;
				} else {
					if (end < i + 3)
						throw new MidiException (MidiErrorType.NoError, "Received data was incomplete to build MIDI status message");
					yield return new MidiEvent () {Message = new MidiMessage (bytes [i], bytes [i + 1], bytes [i + 2])};
					i += 3;
				}
			}
		}

		internal PortMidiStream stream;
		internal PmDeviceID device;

		protected MidiStream (PortMidiStream stream, PmDeviceID deviceID)
		{
			this.stream = stream;
			device = deviceID;
		}

		public void Abort ()
		{
			PortMidiMarshal.Pm_Abort (stream);
		}

		public void Close ()
		{
			Dispose ();
		}
<commit_msg>[portmidi] message size is not always 3 for byte[] outputs, namely ProgramChange.<commit_after>// FIXMEs:
// - some bad mappings:
//	- C int -> C# int
//	- C long -> C# int
// not sure what they should be.
// The sources are wrong. Those C code should not use int and long for each.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

using PmDeviceID = System.Int32;
using PmTimestamp = System.Int32;
using PortMidiStream = System.IntPtr;
using PmMessage = System.Int32;
using PmError = Commons.Music.Midi.PortMidi.MidiErrorType;

namespace Commons.Music.Midi.PortMidi
{
	public class MidiDeviceManager
	{
		static MidiDeviceManager ()
		{
			PortMidiMarshal.Pm_Initialize ();
			AppDomain.CurrentDomain.DomainUnload += delegate (object o, EventArgs e) {
				PortMidiMarshal.Pm_Terminate ();
			};
		}

		public static int DeviceCount {
			get { return PortMidiMarshal.Pm_CountDevices (); }
		}

		public static int DefaultInputDeviceID {
			get { return PortMidiMarshal.Pm_GetDefaultInputDeviceID (); }
		}

		public static int DefaultOutputDeviceID {
			get { return PortMidiMarshal.Pm_GetDefaultOutputDeviceID (); }
		}

		public static IEnumerable<MidiDeviceInfo> AllDevices {
			get {
				for (int i = 0; i < DeviceCount; i++)
					yield return GetDeviceInfo (i);
			}
		}

		public static MidiDeviceInfo GetDeviceInfo (PmDeviceID id)
		{
			return new MidiDeviceInfo (id, PortMidiMarshal.Pm_GetDeviceInfo (id));
		}

		public static MidiInput OpenInput (PmDeviceID inputDevice)
		{
			return OpenInput (inputDevice, default_buffer_size);
		}

		const int default_buffer_size = 1024;

		public static MidiInput OpenInput (PmDeviceID inputDevice, int bufferSize)
		{
			PortMidiStream stream;
			var e = PortMidiMarshal.Pm_OpenInput (out stream, inputDevice, IntPtr.Zero, bufferSize, null, IntPtr.Zero);
			if (e != PmError.NoError)
				throw new MidiException (e, String.Format ("Failed to open MIDI input device {0}", e));
			return new MidiInput (stream, inputDevice);
		}

		public static MidiOutput OpenOutput (PmDeviceID outputDevice)
		{
			PortMidiStream stream;
			var e = PortMidiMarshal.Pm_OpenOutput (out stream, outputDevice, IntPtr.Zero, 0, null, IntPtr.Zero, 0);
			if (e != PmError.NoError)
				throw new MidiException (e, String.Format ("Failed to open MIDI output device {0}", e));
			return new MidiOutput (stream, outputDevice, 0);
		}
	}

	public enum MidiErrorType
	{
		NoError = 0,
		NoData = 0,
		GotData = 1,
		HostError = -10000,
		InvalidDeviceId,
		InsufficientMemory,
		BufferTooSmall,
		BufferOverflow,
		BadPointer,
		BadData,
		InternalError,
		BufferMaxSize,
	}

	public class MidiException : Exception
	{
		PmError error_type;

		public MidiException (PmError errorType, string message)
			: this (errorType, message, null)
		{
		}

		public MidiException (PmError errorType, string message, Exception innerException)
			: base (message, innerException)
		{
			error_type = errorType;
		}

		public PmError ErrorType {
			get { return error_type; }
		}
	}

	public struct MidiDeviceInfo
	{
		int id;
		PmDeviceInfo info;

		internal MidiDeviceInfo (int id, IntPtr ptr)
		{
			this.id = id;
			this.info = (PmDeviceInfo) Marshal.PtrToStructure (ptr, typeof (PmDeviceInfo));
		}

		public int ID {
			get { return id; }
			set { id = value; }
		}

		public string Interface {
			get { return Marshal.PtrToStringAnsi (info.Interface); }
		}

		public string Name {
			get { return Marshal.PtrToStringAnsi (info.Name); }
		}

		public bool IsInput { get { return info.Input != 0; } }
		public bool IsOutput { get { return info.Output != 0; } }
		public bool IsOpened { get { return info.Opened != 0; } }

		public override string ToString ()
		{
			return String.Format ("{0} - {1} ({2} {3})", Interface, Name, IsInput ? (IsOutput ? "I/O" : "Input") : (IsOutput ? "Output" : "N/A"), IsOpened ? "open" : String.Empty);
		}
	}

	public abstract class MidiStream : IDisposable
	{
		public static IEnumerable<MidiEvent> Convert (byte [] bytes, int index, int size)
		{
			int i = index;
			int end = index + size;
			while (i < end) {
				if (bytes [i] == 0xF0 || bytes [i] == 0xF7) {
					var tmp = new byte [size];
					Array.Copy (bytes, i, tmp, 0, tmp.Length);
					yield return new MidiEvent () {Message = new MidiMessage (0xF0, 0, 0), Data = tmp};
					i += size + 1;
				} else {
					var dsize = SmfEvent.FixedDataSize (bytes [i]);
					if (end <= i + dsize)
						throw new MidiException (MidiErrorType.NoError, "Received data was incomplete to build MIDI status message");
					yield return new MidiEvent () {Message = new MidiMessage (bytes [i], bytes [i + 1], dsize == 1 ? 0 : bytes [i + 2])};
					i += dsize + 1;
				}
			}
		}

		internal PortMidiStream stream;
		internal PmDeviceID device;

		protected MidiStream (PortMidiStream stream, PmDeviceID deviceID)
		{
			this.stream = stream;
			device = deviceID;
		}

		public void Abort ()
		{
			PortMidiMarshal.Pm_Abort (stream);
		}

		public void Close ()
		{
			Dispose ();
		}

{'fraction_non_alphanumeric': 0.10782626303533462, 'fraction_numerical': 0.009314569201174445, 'mean_word_length': 3.435563538392456, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5813138', 'n_tokens_mistral': 3818, 'n_tokens_neox': 3262, 'n_words': 968}