From: tyiki badwell Date: Sun, 17 Feb 2013 07:14:40 +0000 (+0900) Subject: リセット X-Git-Url: http://git.sourceforge.jp/view?a=commitdiff_plain;p=momiji%2Fmomiji_main.git リセット --- 7f92b0477a37202b363182821357ada2253b8e61 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0f3a6b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Debug +Release diff --git a/Core/AssemblyInfo.cpp b/Core/AssemblyInfo.cpp new file mode 100644 index 0000000..5cdd03a --- /dev/null +++ b/Core/AssemblyInfo.cpp @@ -0,0 +1,62 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +AssemblyInfo.cpp + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "stdafx.h" + +using namespace System; +using namespace System::Reflection; +using namespace System::Runtime::CompilerServices; +using namespace System::Runtime::InteropServices; +using namespace System::Security::Permissions; + +// +// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 +// アセンブリに関連付けられている情報を変更するには、 +// これらの属性値を変更してください。 +// +[assembly:AssemblyTitleAttribute("Momiji.Core")]; +[assembly:AssemblyDescriptionAttribute("")]; +[assembly:AssemblyConfigurationAttribute("")]; +[assembly:AssemblyCompanyAttribute("xx laboratory")]; +[assembly:AssemblyProductAttribute("Momiji.Core")]; +[assembly:AssemblyCopyrightAttribute("Copyright (c) tyiki badwell 2011")]; +[assembly:AssemblyTrademarkAttribute("")]; +[assembly:AssemblyCultureAttribute("")]; + +// +// アセンブリのバージョン情報は、以下の 4 つの値で構成されています: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// すべての値を指定するか、下のように '*' を使ってリビジョンおよびビルド番号を +// 既定値にすることができます: + +[assembly:AssemblyVersionAttribute("0.0.*")]; + +[assembly:ComVisible(false)]; + +[assembly:CLSCompliantAttribute(true)]; + +[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = false)]; diff --git a/Core/Momiji.Core.Buffer.cpp b/Core/Momiji.Core.Buffer.cpp new file mode 100644 index 0000000..f59f292 --- /dev/null +++ b/Core/Momiji.Core.Buffer.cpp @@ -0,0 +1,264 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Winmm.cpp + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Core.Buffer.h" + +namespace Momiji { +namespace Core { +namespace Buffer { + + generic + BufferPool::Buffer::Buffer(Allocator^ allocator) + :_allocator(allocator) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->Alloc(); + } + + generic + BufferPool::Buffer::~Buffer() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Buffer(); + } + + generic + BufferPool::Buffer::!Buffer() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->Free(); + } + + generic + void BufferPool::Buffer::Alloc() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_buffer = this->_allocator(); + this->_bufferHandle = InteropServices::GCHandle::Alloc(this->_buffer, InteropServices::GCHandleType::Pinned); + } + + generic + void BufferPool::Buffer::Free() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + if (this->_bufferHandle.IsAllocated) + { + this->_bufferHandle.Free(); + delete this->_buffer; + } + } + + generic + System::IntPtr BufferPool::Buffer::GetBufferIntPtr() + { + return this->_bufferHandle.AddrOfPinnedObject(); + } + + generic + DATA_TYPE% BufferPool::Buffer::GetBuffer() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + return this->_buffer; + } + + + + + + + generic + BufferPool::BufferPool( + System::UInt32 defaultPoolSize, + Allocator^ allocator + ): _allocator(allocator), + _buffers(gcnew System::Collections::Generic::List()), + _idleBuffers(gcnew System::Collections::Generic::Dictionary()), + _busyBuffers(gcnew System::Collections::Generic::Dictionary()), + _defaultPoolSize(defaultPoolSize) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + for (System::UInt32 i = 0; i < this->_defaultPoolSize; i++) + { + this->MakeBuffer(); + } + } + + generic + BufferPool::~BufferPool() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!BufferPool(); + } + + generic + BufferPool::!BufferPool() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + for each (Buffer^ buffer in this->_buffers) + { + delete buffer; + } + this->_buffers->Clear(); + this->_idleBuffers->Clear(); + this->_busyBuffers->Clear(); + } + + generic + BufferPool::Buffer^ BufferPool::Get() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + System::Threading::Monitor::Enter(this); + try + { + if (this->_idleBuffers->Count == 0) + { + //暇なバッファが無ければ、1回分のバッファを新規作成 + this->MakeBuffer(); + } + + System::Collections::Generic::KeyValuePair pair = + System::Linq::Enumerable::First(this->_idleBuffers); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] buffer ptr[{1}]", __FUNCTION__, pair.Key); + #endif + + Buffer^ buffer = pair.Value; + auto intPtr = buffer->GetBufferIntPtr(); + if (!this->_idleBuffers->Remove(intPtr)) + { + throw gcnew System::Exception("バッファの確保に失敗しました。"); + } + this->_busyBuffers->Add(intPtr, buffer); + + //#ifdef _DEBUG + System::Console::WriteLine("[{0}] alloc[{1}] idle[{2}] busy[{3}]", __FUNCTION__, this->_buffers->Count, this->_idleBuffers->Count, this->_busyBuffers->Count); + //#endif + + return buffer; + } + finally + { + System::Threading::Monitor::Exit(this); + } + } + + generic + BufferPool::Buffer^ BufferPool::GetBusy(System::IntPtr bufferPtr) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}][{1}]",__FUNCTION__, bufferPtr); + #endif + + BufferPool::Buffer^ buffer = nullptr; + if (!this->_busyBuffers->TryGetValue(bufferPtr, buffer)) + { + throw gcnew System::Exception("使用済みバッファの取得に失敗しました。"); + } + + return buffer; + } + + generic + void BufferPool::Release(Buffer^ buffer) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + System::Threading::Monitor::Enter(this); + try + { + auto intPtr = buffer->GetBufferIntPtr(); + if (!this->_busyBuffers->Remove(intPtr)) + { + throw gcnew System::Exception("使用済みバッファの開放に失敗しました。"); + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] buffer ptr[{1}]", __FUNCTION__, intPtr); + #endif + this->_idleBuffers->Add(intPtr, buffer); + + //#ifdef _DEBUG + System::Console::WriteLine("[{0}] alloc[{1}] idle[{2}] busy[{3}]", __FUNCTION__, this->_buffers->Count, this->_idleBuffers->Count, this->_busyBuffers->Count); + //#endif + } + finally + { + System::Threading::Monitor::Exit(this); + } + } + + generic + BufferPool::Buffer^ BufferPool::MakeBuffer() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + BufferPool::Buffer^ buffer = gcnew BufferPool::Buffer(this->_allocator); + this->_buffers->Add(buffer); + this->_idleBuffers->Add(buffer->GetBufferIntPtr(), buffer); + + //#ifdef _DEBUG + System::Console::WriteLine("[{0}] alloc[{1}] idle[{2}] busy[{3}]", __FUNCTION__, this->_buffers->Count, this->_idleBuffers->Count, this->_busyBuffers->Count); + //#endif + + return buffer; + } + + generic + System::Boolean BufferPool::IsBusy() + { + return (this->_busyBuffers->Count > 0); + } + +} +} +} diff --git a/Core/Momiji.Core.Buffer.h b/Core/Momiji.Core.Buffer.h new file mode 100644 index 0000000..3df7237 --- /dev/null +++ b/Core/Momiji.Core.Buffer.h @@ -0,0 +1,94 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Buffer.h + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +//#include "Momiji.Core.Interface.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Buffer { + + generic + public ref class BufferPool + { + public: + delegate DATA_TYPE Allocator(); + + ref class Buffer + { + private: + DATA_TYPE _buffer; + InteropServices::GCHandle _bufferHandle; + Allocator^ _allocator; + + public: + Buffer(Allocator^ allocator); + virtual ~Buffer(); + + protected: + !Buffer(); + + private: + void Alloc(); + void Free(); + + public: + System::IntPtr GetBufferIntPtr(); + DATA_TYPE% GetBuffer(); + }; + + private: + System::Collections::Generic::List^ _buffers; //開放用の集合 + System::Collections::Generic::Dictionary^ _idleBuffers; //暇になっているバッファの集合 + System::Collections::Generic::Dictionary^ _busyBuffers; //再生中のバッファの集合 + + System::UInt32 _defaultPoolSize; + Allocator^ _allocator; + + public: + BufferPool( + System::UInt32 defaultPoolSize, + Allocator^ allocator + ); + ~BufferPool(); + + protected: + !BufferPool(); + + public: + Buffer^ Get(); + Buffer^ GetBusy(System::IntPtr bufferPtr); + void Release(Buffer^ buffer); + System::Boolean IsBusy(); + + private: + Buffer^ MakeBuffer(); + + }; + +} +} +} diff --git a/Core/Momiji.Core.DeviceInfo.cpp b/Core/Momiji.Core.DeviceInfo.cpp new file mode 100644 index 0000000..78a4029 --- /dev/null +++ b/Core/Momiji.Core.DeviceInfo.cpp @@ -0,0 +1,424 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.DeviceInfo.cpp + device information. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Interop.Setupapi.h" +#include "Momiji.Interop.Kernel32.h" + +#include "Momiji.Core.DeviceInfo.h" + +namespace Momiji { +namespace Core { +namespace DeviceInfo { + + + Devices::Devices( + Interop::Guiddef::Guid category, + Interop::Setupapi::DIGCF digcf, + System::String^ deviceName + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}][category:{1}][digcf:{2:F}][{3}]",__FUNCTION__, category, digcf, deviceName); + #endif + + this->_category = category; + + this->_handle = + Interop::Setupapi::Function::SetupDiGetClassDevs( + this->_category, + deviceName, + InteropServices::HandleRef(nullptr, System::IntPtr::Zero), + digcf + ); + + if (_handle->IsInvalid) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] error {1:X} {2}",__FUNCTION__, error, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + InteropServices::Marshal::ThrowExceptionForHR(error); + } + } + + Devices::~Devices() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Devices(); + } + + Devices::!Devices() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->_handle->Close(); + } + + Devices::Detail::Detail( + Devices^ devices, + System::UInt32 index + ): + _devices(devices) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->GetDetail(index); + } + + Devices::Detail::~Detail() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Detail(); + } + + Devices::Detail::!Detail() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + void Devices::Detail::GetDetail( + System::UInt32 index + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}][index: {1}]",__FUNCTION__, index); + #endif + + auto data = Interop::Setupapi::SpDeviceInterfaceData(); + data.cbSize = safe_cast(InteropServices::Marshal::SizeOf(data)); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] data->cbSize {1}",__FUNCTION__, data.cbSize); + #endif + if ( + !Interop::Setupapi::Function::SetupDiEnumDeviceInterfaces( + this->_devices->_handle, + nullptr, + this->_devices->_category, + index, + data + ) + ) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] error [{1}]",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + if (error == 0x80070103) //ERROR_NO_MORE_ITEMS + { + this->_noMoreItems = true; + return; + } + else + { + InteropServices::Marshal::ThrowExceptionForHR(error); + } + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] data [{1}]", __FUNCTION__, data); + #endif + + this->_data = data; + + //データサイズ確認 + System::UInt32 reqired = 0; + + if ( + !Interop::Setupapi::Function::SetupDiGetDeviceInterfaceDetail( + this->_devices->_handle, + this->_data, + System::IntPtr::Zero, + 0, + reqired, + System::IntPtr::Zero + ) + ) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] error [{1}]",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + if (error != 0x8007007A)//ERROR_INSUFFICIENT_BUFFER + { + InteropServices::Marshal::ThrowExceptionForHR(error); + } + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] reqired {1}",__FUNCTION__, reqired); + #endif + + //・・・はしてるものの、結局今は、1024byte固定で読み込んでいる + auto detail = Interop::Setupapi::SpDeviceInterfaceDetailData(); + detail.cbSize = 8;//safe_cast(InteropServices::Marshal::SizeOf(detail->cbSize) + InteropServices::Marshal::SystemDefaultCharSize); + + auto info = Interop::Setupapi::SpDevinfoData(); + info.cbSize = safe_cast(InteropServices::Marshal::SizeOf(info)); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] detail->cbSize {1}",__FUNCTION__, detail.cbSize); + #endif + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] info->cbSize {1}",__FUNCTION__, info.cbSize); + #endif + + if ( + !Interop::Setupapi::Function::SetupDiGetDeviceInterfaceDetail( + this->_devices->_handle, + this->_data, + detail, + reqired, + reqired, + info + ) + ) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + InteropServices::Marshal::ThrowExceptionForHR(error); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] detail [{1}]",__FUNCTION__, detail); + System::Console::WriteLine("[{0}] info [{1}]", __FUNCTION__, info); + #endif + + this->_devicePath = detail.DevicePath; + this->_info = info; + } + + Interop::Setupapi::SpDeviceInterfaceData^ Devices::Detail::GetAlias( + Interop::Guiddef::Guid subCategory + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}][{1}]",__FUNCTION__, subCategory); + #endif + auto data = Interop::Setupapi::SpDeviceInterfaceData(); + data.cbSize = safe_cast(InteropServices::Marshal::SizeOf(data)); + + if ( + !Interop::Setupapi::Function::SetupDiGetDeviceInterfaceAlias( + this->_devices->_handle, + this->_data, + subCategory, + data + ) + ) + { + #ifdef _DEBUG + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + System::Console::WriteLine("[{0}] error [{1}]",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + return nullptr; + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] alias [{1}]", __FUNCTION__, data); + #endif + return data; + } + + System::String^ Devices::Detail::GetDeviceRegistryProperty( + Interop::Setupapi::SPDRP spdrp + ) + { + #ifdef _DEBUG + // System::Console::WriteLine("[{0}][{1}]",__FUNCTION__, spdrp); + #endif + System::UInt32 regDataType = 0; + System::UInt32 reqired = 0; + if ( + !Interop::Setupapi::Function::SetupDiGetDeviceRegistryProperty( + this->_devices->_handle, + this->_info, + spdrp, + regDataType, + nullptr, + 0, + reqired + ) + ) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] error {1:X}",__FUNCTION__, error); + #endif + if (error != 0x8007007A)//ERROR_INSUFFICIENT_BUFFER + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] {1} [{2}]",__FUNCTION__, spdrp, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + return nullptr; + } + } + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] reqired {1}",__FUNCTION__, reqired); + #endif + auto buf = gcnew System::Text::StringBuilder(safe_cast(reqired)); + + if ( + !Interop::Setupapi::Function::SetupDiGetDeviceRegistryProperty( + this->_devices->_handle, + this->_info, + spdrp, + regDataType, + buf, + reqired, + reqired + ) + ) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] error {1:X}",__FUNCTION__, error); + #endif + InteropServices::Marshal::ThrowExceptionForHR(error); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] {1} [{2}]",__FUNCTION__, spdrp, buf->ToString()); + #endif + return buf->ToString(); + } + + System::String^ Devices::Detail::GetDeviceRegistryProperty( + System::String^ name + ) + { + #ifdef _DEBUG + // System::Console::WriteLine("[{0}][{1}]",__FUNCTION__, name); + #endif + Interop::Setupapi::Function::RegKey^ regKey; + + { + regKey = + Interop::Setupapi::Function::SetupDiOpenDeviceInterfaceRegKey( + this->_devices->_handle, + this->_data, + 0, + Interop::Kernel32::ACCESS_TYPES::KEY_READ + ); + if (regKey->IsInvalid) + { + #ifdef _DEBUG + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + System::Console::WriteLine("[{0}] error {1:X}",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + return nullptr; + } + } + + try + { + System::UInt32 type = 0; + System::UInt32 size = 1024; + auto data = InteropServices::Marshal::AllocHGlobal(size); + try + { + System::UInt32 error = + Interop::Setupapi::Function::RegQueryValueEx( + regKey, + name, + System::IntPtr::Zero, + type, + data, + size + ); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] error {1:X}",__FUNCTION__, error); + #endif + if (error != 0) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] msg {1}",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + return nullptr; + } + + auto result = InteropServices::Marshal::PtrToStringAuto(data); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] {1} [{2}]",__FUNCTION__, name, result); + #endif + return result; + } + finally + { + InteropServices::Marshal::FreeHGlobal(data); + } + } + finally + { + delete regKey; + } + } + + + + Devices::DetailEnum::DetailEnum( + Devices^ devices + ): + _devices(devices), + _index(0) //一般的な用法からは外して、MoveNext後に+1している + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + System::Boolean Devices::DetailEnum::MoveNext() + { + auto detail = + gcnew Detail( + this->_devices, + this->_index++ + ); + + this->_detail = + (detail->IsNoMoreItems) + ? nullptr + : detail + ; + return !detail->IsNoMoreItems; + } + + void Devices::DetailEnum::Reset() + { + this->_detail = nullptr; + this->_index = 0; + } + + +} +} +} diff --git a/Core/Momiji.Core.DeviceInfo.h b/Core/Momiji.Core.DeviceInfo.h new file mode 100644 index 0000000..0eff317 --- /dev/null +++ b/Core/Momiji.Core.DeviceInfo.h @@ -0,0 +1,132 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.DeviceInfo.h + device information +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +#include "Momiji.Interop.Setupapi.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace DeviceInfo { + + public ref class Devices + { + public: + ref class Detail + { + private: + Devices^ _devices; + Interop::Setupapi::SpDeviceInterfaceData _data; + Interop::Setupapi::SpDevinfoData _info; + + System::String^ _devicePath; + + System::Boolean _noMoreItems; + + public: + Detail( + Devices^ devices, + System::UInt32 index + ); + ~Detail(); + + protected: + !Detail(); + + public: + property System::Boolean IsNoMoreItems { System::Boolean get() { return this->_noMoreItems; } } + property System::String^ DevicePath { System::String^ get() { return this->_devicePath; } } + + private: + void GetDetail(System::UInt32 index); + + public: + Interop::Setupapi::SpDeviceInterfaceData^ GetAlias(Interop::Guiddef::Guid subCategory); + System::String^ GetDeviceRegistryProperty(Interop::Setupapi::SPDRP spdrp); + System::String^ GetDeviceRegistryProperty(System::String^ name); + }; + + ref class DetailEnum: System::Collections::Generic::IEnumerator + { + private: + Devices^ _devices; + Detail^ _detail; + + System::UInt32 _index; + + public: + DetailEnum(Devices^ devices); + ~DetailEnum() {}; + + public: + virtual System::Boolean MoveNext(); + virtual void Reset(); + + public: + property Detail^ Current { virtual Detail^ get() {return this->_detail;} } + + private: + property System::Object^ _Current { virtual System::Object^ get() sealed = System::Collections::IEnumerator::Current::get {return this->_detail;} } + + }; + + ref class DetailEnumerable: System::Collections::Generic::IEnumerable + { + private: + Devices^ _devices; + + public: + DetailEnumerable(Devices^ devices): _devices(devices){}; + + virtual System::Collections::Generic::IEnumerator^ GetEnumerator() { return gcnew DetailEnum(this->_devices); }; + + private: + virtual System::Collections::IEnumerator^ _GetEnumerator() sealed = System::Collections::IEnumerable::GetEnumerator { return this->GetEnumerator(); }; + }; + + private: + Interop::Setupapi::Function::DeviceInfoSet^ _handle; + Interop::Guiddef::Guid _category; + + public: + Devices( + Interop::Guiddef::Guid category, + Interop::Setupapi::DIGCF digcf, + System::String^ deviceName + ); + + ~Devices(); + protected: + !Devices(); + + public: + property DetailEnumerable^ Enum { DetailEnumerable^ get() { return gcnew DetailEnumerable(this); } }; + + }; + +} +} +} diff --git a/Core/Momiji.Core.Interface.h b/Core/Momiji.Core.Interface.h new file mode 100644 index 0000000..7be974b --- /dev/null +++ b/Core/Momiji.Core.Interface.h @@ -0,0 +1,75 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Interface.h + momiji interface. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { + + public interface class IData + { + }; + + public interface class IPacket + { + property IData^ data{ IData^ get(); }; + property System::UInt64 tick{ System::UInt64 get(); }; + }; + + public interface class IStreamPacket + : public IPacket + { + property IStreamPacket^ next{ IStreamPacket^ get(); }; + property System::Boolean hasNext{ System::Boolean get(); }; + }; + + public interface class ITrack + { + void Rewind(); + array^ GetStreamPacket(System::Double deltaTime); + property IStreamPacket^ head{ IStreamPacket^ get(); }; + }; + + public interface class IStream + { + array^ GetStreamPacket(System::Double deltaTime); + void Rewind(); + }; + + public interface class ITimer + { + void Start(System::UInt32 period); + void Stop(); + delegate void Event(const System::Double deltaTime); + event Event^ OnInterval; + }; + + public interface class IOut + { + void Send(IData^ data); + }; +} +} diff --git a/Core/Momiji.Core.Ks.Filter.cpp b/Core/Momiji.Core.Ks.Filter.cpp new file mode 100644 index 0000000..0a742d7 --- /dev/null +++ b/Core/Momiji.Core.Ks.Filter.cpp @@ -0,0 +1,154 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Ks.cpp + kernel streaming. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" +#include "Momiji.Core.Ks.Filter.h" + +namespace Momiji { +namespace Core { +namespace Ks { + + FilterHandle::FilterHandle( + System::String^ devicePath + ): _devicePath(devicePath), Irp() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] devicePath {1}",__FUNCTION__, this->_devicePath); + #endif + } + + FilterHandle::~FilterHandle() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!FilterHandle(); + } + + FilterHandle::!FilterHandle() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + Interop::Kernel32::Function::File^ FilterHandle::Open() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto handle = + Interop::Kernel32::Function::CreateFile( + this->_devicePath, + ( + Momiji::Interop::Kernel32::ACCESS_TYPES::GENERIC_READ + | Momiji::Interop::Kernel32::ACCESS_TYPES::GENERIC_WRITE + ), + Momiji::Interop::Kernel32::SHARE_MODE::FILE_SHARE_NONE, + System::IntPtr::Zero, + Momiji::Interop::Kernel32::CREATION_DISPOSITION::OPEN_EXISTING, + ( + Momiji::Interop::Kernel32::FLAG_AND_ATTRIBUTE::FILE_ATTRIBUTE_NORMAL + | Momiji::Interop::Kernel32::FLAG_AND_ATTRIBUTE::FILE_FLAG_OVERLAPPED + ), + System::IntPtr::Zero + ); + if (handle->IsInvalid) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + System::Console::WriteLine("[{0}] error {1:X}",__FUNCTION__, error); + InteropServices::Marshal::ThrowExceptionForHR(error); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, handle->IsInvalid, handle->IsClosed); + #endif + + return handle; + } + + + Filter::Filter( + System::String^ devicePath + ): _handle(gcnew FilterHandle(devicePath)) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->CheckSupprts(); + + this->_propertySetTopology = gcnew PropertySetTopology(this->_handle); + this->_propertySetAudio = gcnew PropertySetAudio(this->_handle); + this->_propertySetPin = gcnew PropertySetPin(this->_handle); + } + + Filter::~Filter() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Filter(); + } + + Filter::!Filter() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + delete this->_handle; + } + + void Filter::CheckSupprts() + { + { + auto param = /*gcnew*/ Interop::Ks::KsIdentifier(); + param.Set = Interop::Guiddef::Guid(); //GUID_NULL + param.Flags = Interop::Ks::PROPERTY_TYPE::SETSUPPORT; + + this->_supportProperties = + this->_handle->GetArray, Interop::Guiddef::Guid>(Interop::Ks::IOCTL_KS::PROPERTY, param); + } + + { + auto param = /*gcnew*/ Interop::Ks::KsIdentifier(); + param.Set = Interop::Guiddef::Guid(); //GUID_NULL + param.Flags = Interop::Ks::METHOD_TYPE::SETSUPPORT; + + this->_supportMethods = + this->_handle->GetArray, Interop::Guiddef::Guid>(Interop::Ks::IOCTL_KS::METHOD, param); + } + + { + auto param = /*gcnew*/ Interop::Ks::KsIdentifier(); + param.Set = Interop::Guiddef::Guid(); //GUID_NULL + param.Flags = Interop::Ks::EVENT_TYPE::SETSUPPORT; + + this->_supportEvents = + this->_handle->GetArray, Interop::Guiddef::Guid>(Interop::Ks::IOCTL_KS::ENABLE_EVENT, param); + } + } + +} +} +} diff --git a/Core/Momiji.Core.Ks.Filter.h b/Core/Momiji.Core.Ks.Filter.h new file mode 100644 index 0000000..a53952b --- /dev/null +++ b/Core/Momiji.Core.Ks.Filter.h @@ -0,0 +1,85 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Ks.h + kernel streaming +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +#include "Momiji.Interop.Guiddef.h" +#include "Momiji.Interop.Ks.h" +#include "Momiji.Core.Ks.h" +#include "Momiji.Core.Ks.PropertySet.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Ks { + + ref class FilterHandle: Irp + { + private: + initonly System::String^ _devicePath; + + public: + FilterHandle(System::String^ devicePath); + virtual ~FilterHandle(); + + protected: + !FilterHandle(); + + protected: + virtual Interop::Kernel32::Function::File^ Open() override; + }; + + public ref class Filter + { + internal: + initonly FilterHandle^ _handle; + + private: + PropertySetTopology^ _propertySetTopology; + PropertySetAudio^ _propertySetAudio; + PropertySetPin^ _propertySetPin; + + public: + Filter(System::String^ devicePath); + virtual ~Filter(); + + protected: + !Filter(); + + private: + array^ _supportProperties; + array^ _supportMethods; + array^ _supportEvents; + + void CheckSupprts(); + + public: + property PropertySetPin^ propertySetPin { PropertySetPin^ get() { return this->_propertySetPin; } }; + + }; + +} +} +} diff --git a/Core/Momiji.Core.Ks.Pin.cpp b/Core/Momiji.Core.Ks.Pin.cpp new file mode 100644 index 0000000..ac8baf2 --- /dev/null +++ b/Core/Momiji.Core.Ks.Pin.cpp @@ -0,0 +1,439 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Ks.Pin.cpp + kernel streaming. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" +#include "Momiji.Core.Ks.Pin.h" + +namespace Momiji { +namespace Core { +namespace Ks { + + PinHandle::PinHandle( + PropertySetPin::Item^ item, + System::UInt16 channels, + System::UInt32 samplesPerSecond, + System::UInt16 bitsPerSample, + Interop::Winmm::WaveFormatExtensiblePart::SPEAKER channelMask, + Interop::Guiddef::Guid formatSubType + ): + _item(item), + _channels(channels), + _samplesPerSecond(samplesPerSecond), + _bitsPerSample(bitsPerSample), + _channelMask(channelMask), + _formatSubType(formatSubType), + Irp() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] pinId {1}",__FUNCTION__, this->_item->pinId); + #endif + } + + PinHandle::~PinHandle() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] pinId {1}",__FUNCTION__, this->_item->pinId); + #endif + this->!PinHandle(); + } + + PinHandle::!PinHandle() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] pinId {1}",__FUNCTION__, this->_item->pinId); + #endif + } + + Interop::Kernel32::Function::File^ PinHandle::Open() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto connect = Interop::Ks::KsPinConnect(); + connect.Interface.Set = Interop::Ks::StaticKs::INTERFACESETID_Standard; + connect.Interface.Id = Interop::Ks::KsPinInterface::ID::STANDARD_STREAMING; + connect.Interface.Flags = 0; + + connect.Medium.Set = Interop::Ks::StaticKs::MEDIUMSETID_Standard; + connect.Medium.Id = Interop::Ks::KsPinMedium::ID::STANDARD_ANYINSTANCE; + connect.Medium.Flags = 0; + + connect.PinId = this->_item->pinId; + connect.PinToHandle = System::IntPtr::Zero; + + connect.Priority.PriorityClass = Interop::Ks::KsPriority::CLASS::NORMAL; + connect.Priority.PrioritySubClass = 1; + + connect.DataFormat.FormatSize = + InteropServices::Marshal::SizeOf(Interop::Ks::KsDataFormat::typeid) + + InteropServices::Marshal::SizeOf(Interop::Winmm::WaveFormatExtensible::typeid) + ; + connect.DataFormat.Flags = 0; + connect.DataFormat.SampleSize = 0; + connect.DataFormat.Reserved = 0; + connect.DataFormat.MajorFormat = Interop::Ks::StaticKs::MEDIATYPE_Audio; + connect.DataFormat.SubFormat = Interop::Ks::StaticKs::SUBTYPE_PCM; + connect.DataFormat.Specifier = Interop::Ks::StaticKs::SPECIFIER_WAVEFORMATEX; + + connect.WaveFormat.wfe.formatType = Interop::Winmm::WaveFormatEx::FORMAT::EXTENSIBLE; + connect.WaveFormat.wfe.channels = this->_channels; + connect.WaveFormat.wfe.samplesPerSecond = this->_samplesPerSecond; + connect.WaveFormat.wfe.bitsPerSample = this->_bitsPerSample; + connect.WaveFormat.wfe.blockAlign = connect.WaveFormat.wfe.channels * connect.WaveFormat.wfe.bitsPerSample / 8; + connect.WaveFormat.wfe.averageBytesPerSecond = connect.WaveFormat.wfe.samplesPerSecond * connect.WaveFormat.wfe.blockAlign; + connect.WaveFormat.wfe.size = safe_cast(InteropServices::Marshal::SizeOf(Interop::Winmm::WaveFormatExtensiblePart::typeid)); + + connect.WaveFormat.exp.validBitsPerSample = connect.WaveFormat.wfe.bitsPerSample; //TODO: 実際にハードウェアでサポートしている限界に揃える + connect.WaveFormat.exp.channelMask = this->_channelMask; + connect.WaveFormat.exp.subFormat = this->_formatSubType; + + + System::Console::WriteLine("[{0}] create pin [{1}]",__FUNCTION__, connect); + + Interop::Kernel32::Function::File^ handle; + + auto error = + Interop::Ks::Function::KsCreatePin( + this->_item->propertySet->irp->handle, + connect, + ( + Momiji::Interop::Kernel32::ACCESS_TYPES::GENERIC_READ + | Momiji::Interop::Kernel32::ACCESS_TYPES::GENERIC_WRITE + ), + handle + ); + + if (error != 0) + { + //HRESULTに変換 + error |= 0x80000000; + error |= 7 << 16; + InteropServices::Marshal::ThrowExceptionForHR(error); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, handle->IsInvalid, handle->IsClosed); + #endif + + return handle; + } + + + generic + Pin::Pin( + PropertySetPin::Item^ item, + System::UInt16 channels, + System::UInt32 samplesPerSecond, + System::UInt16 bitsPerSample, + Interop::Winmm::WaveFormatExtensiblePart::SPEAKER channelMask, + Interop::Guiddef::Guid formatSubType + ) + : _handle( + gcnew PinHandle( + item, + channels, + samplesPerSecond, + bitsPerSample, + channelMask, + formatSubType + ) + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + generic + Pin::~Pin() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Pin(); + } + + generic + Pin::!Pin() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->State = Interop::Ks::KsState::ENUM::STOP; + this->Reset(); + delete this->_handle; + } + + generic + void Pin::Reset() + { + #ifdef _DEBUG + System::Console::WriteLine("========================================================="); + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + System::UInt32 bytesReturned = 0; + auto reset = Interop::Ks::KsReset(); + + { + reset.Value = Interop::Ks::KsReset::ENUM::BEGIN; + auto error = + this->_handle->Put( + Interop::Ks::IOCTL_KS::RESET_STATE, + reset, + bytesReturned + ); + InteropServices::Marshal::ThrowExceptionForHR(error); + } + + { + reset.Value = Interop::Ks::KsReset::ENUM::END; + auto error = + this->_handle->Put( + Interop::Ks::IOCTL_KS::RESET_STATE, + reset, + bytesReturned + ); + InteropServices::Marshal::ThrowExceptionForHR(error); + } + #ifdef _DEBUG + System::Console::WriteLine("========================================================="); + #endif + } + + generic + Interop::Ks::KsState::ENUM Pin::State::get() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto param = Interop::Ks::KsIdentifier(); + param.Set = Interop::Ks::StaticKs::PROPSETID_Connection; + param.Id = Interop::Ks::PROPERTY_ID_CONNECTION::STATE; + param.Flags = Interop::Ks::PROPERTY_TYPE::GET; + + auto v = this->_handle->GetSingle, Interop::Ks::KsState>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + return v->value.Value; + } + + return Interop::Ks::KsState::ENUM::STOP; + } + + generic + void Pin::State::set(Interop::Ks::KsState::ENUM v) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto param = Interop::Ks::KsIdentifier(); + param.Set = Interop::Ks::StaticKs::PROPSETID_Connection; + param.Id = Interop::Ks::PROPERTY_ID_CONNECTION::STATE; + param.Flags = Interop::Ks::PROPERTY_TYPE::SET; + + auto state = Interop::Ks::KsState(); + state.Value = v; + + auto error = this->_handle->IOSync, Interop::Ks::KsState>(Interop::Ks::IOCTL_KS::PROPERTY, param, state); + InteropServices::Marshal::ThrowExceptionForHR(error); + } + + value class A { + public: + static System::Single Modulus(System::Single dividend, System::Single divisor) + { + return + safe_cast( + (System::Math::Abs(dividend) - (System::Math::Abs(divisor) * + (System::Math::Floor(System::Math::Abs(dividend) / System::Math::Abs(divisor))))) * + System::Math::Sign(dividend) + ); + } + }; + + generic + void Pin::Test() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->State; + this->Reset(); + if (this->State == Interop::Ks::KsState::ENUM::STOP) { this->State = Interop::Ks::KsState::ENUM::ACQUIRE; } + if (this->State == Interop::Ks::KsState::ENUM::ACQUIRE) { this->State = Interop::Ks::KsState::ENUM::PAUSE; } + if (this->State == Interop::Ks::KsState::ENUM::PAUSE) { this->State = Interop::Ks::KsState::ENUM::RUN; } + this->State; + + System::UInt32 samplesPerSecond = 48000; + + if (!this->_handle->handle->IsInvalid && !this->_handle->handle->IsClosed) + { + System::UInt32 pulBytesReturned = 0; + + auto data = gcnew array(samplesPerSecond*4); + + for(System::Int32 idx = 0; idx < samplesPerSecond * 4; idx++) + { + System::UInt16 d = (System::Int16::MaxValue / 2); + System::UInt16 ll = safe_cast(samplesPerSecond / (440 + ((440 / (samplesPerSecond * 2)) * idx))); + + if((idx % ll) < (ll / 2)) + //if(idx < (ll / 2)) + { + d += System::UInt16::MaxValue / 440; + } + else + { + d -= System::UInt16::MaxValue / 440; + } + + d = (d > System::UInt16::MaxValue) ? System::UInt16::MaxValue: d; + d = (d < System::UInt16::MinValue) ? System::UInt16::MinValue: d; + + data[idx] = d; + } + + /* + for(System::UInt32 idx = 0; idx < s * 2; idx++) + { + System::Single d = .0; + + System::Single ll = safe_cast(s / (440.0 + ((440.0 / (s * 2)) * idx))); + + if(Modulus(safe_cast(idx), ll) < (ll / 2)) + { + d += System::Single::MaxValue / 4; + } + else + { + d -= System::Single::MaxValue / 4; + } + + d = (d > System::Single::MaxValue) ? System::Single::MaxValue: d; + d = (d < System::Single::MinValue) ? System::Single::MinValue: d; + + data[idx] = d; + } + */ + + auto outSize = /*InteropServices::Marshal::SizeOf(data);//*/samplesPerSecond * 4; + auto out = InteropServices::GCHandle::Alloc(data, InteropServices::GCHandleType::Pinned); + + auto header = Interop::Ks::KsStreamHeader(); + header.Data = out.AddrOfPinnedObject(); + header.FrameExtent = outSize; + header.DataUsed = outSize; + header.Size = InteropServices::Marshal::SizeOf(header); + header.PresentationTime.Numerator = 1; + header.PresentationTime.Denominator = 1; + + System::Console::WriteLine("[{0}] header {1}",__FUNCTION__, header); + + auto cbInBuffer = InteropServices::Marshal::SizeOf(header); + auto pvInBuffer = InteropServices::Marshal::AllocHGlobal(cbInBuffer); + + InteropServices::Marshal::StructureToPtr(header, pvInBuffer, false); + + System::Console::WriteLine("=========================================="); + auto error = + this->_handle->IOSync( + Interop::Ks::IOCTL_KS::WRITE_STREAM, + System::IntPtr::Zero, + 0, + pvInBuffer, + cbInBuffer, + pulBytesReturned + ); + + System::Console::WriteLine("[{0}] write error {1}",__FUNCTION__, error); + System::Console::WriteLine("[{0}] pulBytesReturned {1}",__FUNCTION__, pulBytesReturned); + { + auto h = safe_cast(InteropServices::Marshal::PtrToStructure(pvInBuffer, Interop::Ks::KsStreamHeader::typeid)); + System::Console::WriteLine("[{0}] header {1}",__FUNCTION__, h); + } + + System::Console::WriteLine("=========================================="); + + this->State = Interop::Ks::KsState::ENUM::RUN; + this->State; + + System::Console::WriteLine("=========================================="); + error = + this->_handle->IOSync( + Interop::Ks::IOCTL_KS::WRITE_STREAM, + System::IntPtr::Zero, + 0, + pvInBuffer, + cbInBuffer, + pulBytesReturned + ); + + System::Console::WriteLine("[{0}] write error {1}",__FUNCTION__, error); + System::Console::WriteLine("[{0}] pulBytesReturned {1}",__FUNCTION__, pulBytesReturned); + { + auto h = safe_cast(InteropServices::Marshal::PtrToStructure(pvInBuffer, Interop::Ks::KsStreamHeader::typeid)); + System::Console::WriteLine("[{0}] header {1}",__FUNCTION__, h); + } + + System::Console::WriteLine("=========================================="); + + this->State = Interop::Ks::KsState::ENUM::RUN; + this->State; + + System::Console::WriteLine("=========================================="); + error = + this->_handle->IOSync( + Interop::Ks::IOCTL_KS::WRITE_STREAM, + System::IntPtr::Zero, + 0, + pvInBuffer, + cbInBuffer, + pulBytesReturned + ); + + System::Console::WriteLine("[{0}] write error {1}",__FUNCTION__, error); + System::Console::WriteLine("[{0}] pulBytesReturned {1}",__FUNCTION__, pulBytesReturned); + { + auto h = safe_cast(InteropServices::Marshal::PtrToStructure(pvInBuffer, Interop::Ks::KsStreamHeader::typeid)); + System::Console::WriteLine("[{0}] header {1}",__FUNCTION__, h); + } + + System::Console::WriteLine("=========================================="); + + this->State = Interop::Ks::KsState::ENUM::RUN; + this->State; + + System::Console::ReadLine(); + + InteropServices::Marshal::FreeHGlobal(pvInBuffer); + out.Free(); + } + } + +} +} +} diff --git a/Core/Momiji.Core.Ks.Pin.h b/Core/Momiji.Core.Ks.Pin.h new file mode 100644 index 0000000..2968089 --- /dev/null +++ b/Core/Momiji.Core.Ks.Pin.h @@ -0,0 +1,104 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Ks.Pin.h + kernel streaming +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +#include "Momiji.Interop.Guiddef.h" +#include "Momiji.Interop.Ks.h" +#include "Momiji.Core.Ks.h" +#include "Momiji.Core.Ks.PropertySet.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Ks { + + ref class PinHandle: Irp + { + private: + initonly PropertySetPin::Item^ _item; + System::UInt16 _channels; + System::UInt32 _samplesPerSecond; + System::UInt16 _bitsPerSample; + + Interop::Winmm::WaveFormatExtensiblePart::SPEAKER _channelMask; + Interop::Guiddef::Guid _formatSubType; + + public: + PinHandle( + PropertySetPin::Item^ item, + System::UInt16 channels, + System::UInt32 samplesPerSecond, + System::UInt16 bitsPerSample, + Interop::Winmm::WaveFormatExtensiblePart::SPEAKER channelMask, + Interop::Guiddef::Guid formatSubType + ); + virtual ~PinHandle(); + + protected: + !PinHandle(); + + protected: + virtual Interop::Kernel32::Function::File^ Open() override; + }; + + + generic + public ref class Pin + { + initonly PinHandle^ _handle; + Core::Buffer::BufferPool^ _headerPool; + + public: + Pin( + PropertySetPin::Item^ item, + System::UInt16 channels, + System::UInt32 samplesPerSecond, + System::UInt16 bitsPerSample, + Interop::Winmm::WaveFormatExtensiblePart::SPEAKER channelMask, + Interop::Guiddef::Guid formatSubType + ); + virtual ~Pin(); + + protected: + !Pin(); + + public: + //void Send(array^ data); + void Reset(); + + void Test(); + + public: + property Interop::Ks::KsState::ENUM State + { + Interop::Ks::KsState::ENUM get(); + void set(Interop::Ks::KsState::ENUM v); + }; + }; + +} +} +} diff --git a/Core/Momiji.Core.Ks.PropertySet.cpp b/Core/Momiji.Core.Ks.PropertySet.cpp new file mode 100644 index 0000000..0c8ddb3 --- /dev/null +++ b/Core/Momiji.Core.Ks.PropertySet.cpp @@ -0,0 +1,245 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Ks.PropertySet.cpp + kernel streaming. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" +//#include "Momiji.Core.Ks.h" +//#include "Momiji.Interop.Kernel32.h" +//#include "Momiji.Interop.Ks.h" +#include "Momiji.Core.Ks.Filter.h" + +namespace Momiji { +namespace Core { +namespace Ks { + + + PropertySetTopology::PropertySetTopology( + Irp^ irp + ): + PropertySet(irp) + { + auto param = Interop::Ks::KsIdentifier(); + param.Set = Interop::Ks::StaticKs::PROPSETID_Topology; + param.Flags = Interop::Ks::PROPERTY_TYPE::GET; + + { + param.Id = Interop::Ks::PROPERTY_ID_TOPOLOGY::CATEGORIES; + auto v = this->irp->GetMultiple, Interop::Guiddef::Guid>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + //this->_instances = v->value; + + auto nodeParam = Interop::Ks::KsNode(); + nodeParam.Property.Set = Interop::Ks::StaticKs::PROPSETID_Topology; + nodeParam.Property.Id = Interop::Ks::PROPERTY_ID_TOPOLOGY::NAME; + nodeParam.Property.Flags = Interop::Ks::PROPERTY_TYPE::GET; + + auto i = 0; + for each (Interop::Guiddef::Guid g in v) + { + nodeParam.NodeId = i++; + auto n = this->irp->GetSingle, Interop::Ks::KsName>(Interop::Ks::IOCTL_KS::PROPERTY, nodeParam); + + } + } + } + { + param.Id = Interop::Ks::PROPERTY_ID_TOPOLOGY::NODES; + auto v = this->irp->GetMultiple, Interop::Guiddef::Guid>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + //this->_instances = v->value; + } + } + { + param.Id = Interop::Ks::PROPERTY_ID_TOPOLOGY::CONNECTIONS; + auto v = this->irp->GetMultiple, Interop::Ks::KsTopologyConnection>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + //this->_instances = v->value; + } + } + } + + PropertySetAudio::PropertySetAudio( + Irp^ irp + ): + PropertySet(irp) + { + auto param = Interop::Ks::KsIdentifier(); + param.Set = Interop::Ks::StaticKs::PROPSETID_Audio; + param.Flags = Interop::Ks::PROPERTY_TYPE::GET; + + { + param.Id = Interop::Ks::PROPERTY_ID_AUDIO::LATENCY; + auto v = this->irp->GetMultiple, Interop::Ks::KsTime>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + //this->_instances = v->value; + } + } + } + + + + PropertySetPin::PropertySetPin( + Irp^ irp + ): + PropertySet(irp) + { + auto itemList = gcnew System::Collections::Generic::List; + + auto param = Interop::Ks::KsIdentifier(); + param.Set = Interop::Ks::StaticKs::PROPSETID_Pin; + param.Id = Interop::Ks::PROPERTY_ID::CTYPES; + param.Flags = Interop::Ks::PROPERTY_TYPE::GET; + + auto ctypes = + this->irp->GetSingle, System::UInt32>(Interop::Ks::IOCTL_KS::PROPERTY, param); + for (System::UInt32 idx = 0; idx < ctypes->value; idx++) + { + itemList->Add(gcnew Item(this, idx)); + } + + this->_items = itemList->ToArray(); + } + + PropertySetPin::Item::Item( + PropertySet^ propertySet, + System::UInt32 pinId + ): + _propertySet(propertySet), + _pinId(pinId), + _communication(Interop::Ks::KsPinCommunication::ENUM::NONE), + _dataflow(Interop::Ks::KsPinDataFlow::ENUM::NONE), + _interfaces(nullptr), + _mediums(nullptr), + _dataFormats(nullptr), + _instances(nullptr), + _globalInstances(nullptr), + //_category(nullptr), + _name(nullptr) + { + auto param = Interop::Ks::KsPropertyPin(); + param.Property.Set = Interop::Ks::StaticKs::PROPSETID_Pin; + param.Property.Flags = Interop::Ks::PROPERTY_TYPE::GET; + param.PinId = this->_pinId; + param.Reserved = 0; + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::CINSTANCES; + auto v = this->propertySet->irp->GetSingle, Interop::Ks::KsCInstances>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + this->_instances = v->value; + } + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::DATAFLOW; + auto v = this->propertySet->irp->GetSingle, Interop::Ks::KsPinDataFlow>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + this->_dataflow = v->value.Value; + } + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::DATARANGES; + this->_dataFormats = this->propertySet->irp->GetMultiple, Interop::Ks::KsDataFormat>(Interop::Ks::IOCTL_KS::PROPERTY, param); + } + + {//TODO PPIN + MultipleItem + (DataFormat * n) がINパラメータでなければならない。データ変換結果を取得できるのかな?? + param.Property.Id = Interop::Ks::PROPERTY_ID::DATAINTERSECTION; + this->propertySet->irp->GetSingle, Interop::Ks::KsCInstances>(Interop::Ks::IOCTL_KS::PROPERTY, param); + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::INTERFACES; + this->_interfaces = this->propertySet->irp->GetMultiple, Interop::Ks::KsPinInterface>(Interop::Ks::IOCTL_KS::PROPERTY, param); + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::MEDIUMS; + this->_mediums = this->propertySet->irp->GetMultiple, Interop::Ks::KsPinMedium>(Interop::Ks::IOCTL_KS::PROPERTY, param); + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::COMMUNICATION; + auto v = this->propertySet->irp->GetSingle, Interop::Ks::KsPinCommunication>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + this->_communication = v->value.Value; + } + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::GLOBALCINSTANCES; + auto v = this->propertySet->irp->GetSingle, Interop::Ks::KsCInstances>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + this->_globalInstances = v->value; + } + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::NECESSARYINSTANCES; + this->propertySet->irp->GetSingle, Interop::Ks::KsCInstances>(Interop::Ks::IOCTL_KS::PROPERTY, param); + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::PHYSICALCONNECTION; + this->propertySet->irp->GetSingle, Interop::Ks::KsCInstances>(Interop::Ks::IOCTL_KS::PROPERTY, param); + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::CATEGORY; + auto v = this->propertySet->irp->GetSingle, Interop::Guiddef::Guid>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + this->_category = v->value; + } + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::NAME; + auto v = this->propertySet->irp->GetSingle, Interop::Ks::KsName>(Interop::Ks::IOCTL_KS::PROPERTY, param); + if (v != nullptr) + { + this->_name = v->value.Name; + } + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::CONSTRAINEDDATARANGES; + this->propertySet->irp->GetMultiple, Interop::Ks::KsDataFormat>(Interop::Ks::IOCTL_KS::PROPERTY, param); + } + + { + param.Property.Id = Interop::Ks::PROPERTY_ID::PROPOSEDATAFORMAT; + this->propertySet->irp->GetMultiple, Interop::Ks::KsDataFormat>(Interop::Ks::IOCTL_KS::PROPERTY, param); + } + } + + +} +} +} diff --git a/Core/Momiji.Core.Ks.PropertySet.h b/Core/Momiji.Core.Ks.PropertySet.h new file mode 100644 index 0000000..8f792cf --- /dev/null +++ b/Core/Momiji.Core.Ks.PropertySet.h @@ -0,0 +1,121 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Ks.PropertySet.h + kernel streaming +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +#include "Momiji.Interop.Guiddef.h" +#include "Momiji.Interop.Ks.h" + +#include "Momiji.Core.Ks.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Ks { + + public ref class PropertySet abstract + { + private: + initonly Irp^ _irp; + + internal: + PropertySet(Irp^ irp): _irp(irp) {}; + + property Irp^ irp + { + Irp^ get() { return this->_irp; } + } + }; + + public ref class PropertySetTopology: PropertySet + { + internal: + PropertySetTopology( + Irp^ irp + ); + }; + + public ref class PropertySetAudio: PropertySet + { + internal: + PropertySetAudio( + Irp^ irp + ); + }; + + public ref class PropertySetPin: PropertySet + { + public: + ref class Item + { + private: + initonly PropertySet^ _propertySet; + initonly System::UInt32 _pinId; + + array^ _interfaces; + array^ _mediums; + array^ _dataFormats; + Interop::Ks::KsPinDataFlow::ENUM _dataflow; + Interop::Ks::KsPinCommunication::ENUM _communication; + Interop::Guiddef::Guid _category; + System::String^ _name; + //array^ _constrainedDataRanges; + + Interop::Ks::KsCInstances^ _instances; + Interop::Ks::KsCInstances^ _globalInstances; + + internal: + Item( + PropertySet^ propertySet, + System::UInt32 pinId + ); + + public: + property System::UInt32 pinId + { + System::UInt32 get() { return this->_pinId; } + } + + property PropertySet^ propertySet + { + PropertySet^ get() { return this->_propertySet; } + } + }; + + private: + array^ _items; + + internal: + PropertySetPin( + Irp^ irp + ); + + public: + property array^ Items { array^ get() { return this->_items; } }; + }; + +} +} +} diff --git a/Core/Momiji.Core.Ks.cpp b/Core/Momiji.Core.Ks.cpp new file mode 100644 index 0000000..bbd2ad7 --- /dev/null +++ b/Core/Momiji.Core.Ks.cpp @@ -0,0 +1,631 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Ks.cpp + kernel streaming. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Interop.Kernel32.h" +#include "Momiji.Interop.Ks.h" + +#include "Momiji.Core.Ks.h" + +namespace Momiji { +namespace Core { +namespace Ks { + + Overlapped::Overlapped() + : _waitHandle(gcnew System::Threading::ManualResetEvent(false)) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_overlapped.EventHandle = this->_waitHandle->SafeWaitHandle->DangerousGetHandle(); + this->_overlappedHandle = InteropServices::GCHandle::Alloc(this->_overlapped); + } + + Overlapped::~Overlapped() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Overlapped(); + } + + Overlapped::!Overlapped() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + if (this->_overlappedHandle.IsAllocated) + { + this->_overlappedHandle.Free(); + } + delete _overlapped; + delete _waitHandle; + } + + void Overlapped::Reset() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->_waitHandle->Reset(); + } + + + Irp::Irp() + : _handle(Open()) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + Irp::~Irp() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Irp(); + } + + Irp::!Irp() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->Close(); + } + + void Irp::Close() + { + if (this->_handle == nullptr) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle is null",__FUNCTION__); + #endif + return; + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed); + #endif + if ( + !this->_handle->IsInvalid + && !this->_handle->IsClosed + ) + { + this->_handle->Close(); + } + else + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] openしていない状態なので、無視します。", __FUNCTION__); + #endif + } + + } + + System::UInt32 Irp::IOSync( + Interop::Ks::IOCTL_KS ioControlCode, + System::IntPtr inBuffer, + System::UInt32 inBufferSize, + System::IntPtr outBuffer, + System::UInt32 outBufferSize, + System::UInt32% bytesReturned + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] ioControlCode {1}",__FUNCTION__, ioControlCode); + #endif + if (this == nullptr) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] this is null",__FUNCTION__); + System::Console::WriteLine("========================================================="); + #endif + return 0; + } + + if (this->_handle->IsInvalid || this->_handle->IsClosed) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed); + System::Console::WriteLine("========================================================="); + #endif + return 0; + } + + auto o = gcnew Overlapped(); + try + { + if (!Interop::Ks::Function::DeviceIoControl( + this->_handle, + ioControlCode, + inBuffer, + inBufferSize, + outBuffer, + outBufferSize, + bytesReturned, + o->overlapped + )) { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + //System::Console::WriteLine("[{0}] error {1} pulBytesReturned {2}",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString(), bytesReturned); + + if (error != 0x800703E5)//ERROR_IO_PENDING + { + System::Console::WriteLine("[{0}] DeviceIoControl error {1}",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + return error; + } + + if (!Interop::Ks::Function::GetOverlappedResult( + this->_handle, + o->overlapped, + bytesReturned, + true + )) { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + System::Console::WriteLine("[{0}] GetOverlappedResult error {1}",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + return error; + } + + System::Console::WriteLine( + "[{0}] over rapped InternalHigh[{1}] InternalLow[{2}] OffsetHigh[{3}] OffsetLow[{4}]", + __FUNCTION__, + o->overlapped.InternalHigh, + o->overlapped.InternalLow, + o->overlapped.OffsetHigh, + o->overlapped.OffsetLow + ); + } + System::Console::WriteLine("[{0}] pendding {1}",__FUNCTION__, o->pendding); + return 0; + } + finally + { + delete o; + } + } + + /* + System::UInt32 Irp::DeviceIoControlSync( + Interop::Ks::IOCTL_KS ioControlCode, + System::IntPtr inBuffer, + System::UInt32 inBufferSize, + System::IntPtr outBuffer, + System::UInt32 outBufferSize, + System::UInt32% bytesReturned + ) + { + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] ioControlCode {1}",__FUNCTION__, ioControlCode); + #endif + + if (this == nullptr) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] this is null",__FUNCTION__); + System::Console::WriteLine("========================================================="); + #endif + return 0; + } + + if (this->_handle->IsInvalid || this->_handle->IsClosed) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed); + System::Console::WriteLine("========================================================="); + #endif + return 0; + } + + auto error = + Interop::Ks::Function::KsSynchronousDeviceControl( + this->_handle, + ioControlCode, + inBuffer, + inBufferSize, + outBuffer, + outBufferSize, + bytesReturned + ); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] error {1} pulBytesReturned {2}",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error), bytesReturned); + #endif + return error; + } + */ + + generic + System::UInt32 Irp::IOSync( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in, + System::IntPtr outBuffer, + System::UInt32 outBufferSize, + System::UInt32% bytesReturned + ) + { + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] in {1}",__FUNCTION__, in); + #endif + + auto inBufferSize = InteropServices::Marshal::SizeOf(IN::typeid); + auto inBuffer = InteropServices::Marshal::AllocHGlobal(inBufferSize); + //System::Console::WriteLine("[{0}] inBufferSize {1}",__FUNCTION__, inBufferSize); + + InteropServices::Marshal::StructureToPtr(in, inBuffer, false); + + try + { + return + this->IOSync( + ioControlCode, + inBuffer, + inBufferSize, + outBuffer, + outBufferSize, + bytesReturned + ); + } + finally + { + InteropServices::Marshal::FreeHGlobal(inBuffer); + } + } + + generic + System::UInt32 Irp::IOSync( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in, + OUT% out + ) + { + #ifdef _DEBUG + System::Console::WriteLine("========================================================="); + System::Console::WriteLine("[{0}] {1}",__FUNCTION__, in); + #endif + + auto outBufferSize = InteropServices::Marshal::SizeOf(OUT::typeid); + auto outBuffer = InteropServices::Marshal::AllocHGlobal(outBufferSize); + InteropServices::Marshal::StructureToPtr(out, outBuffer, false); + + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] outBufferSize {1}",__FUNCTION__, outBufferSize); + #endif + + System::UInt32 bytesReturned = 0; + + try + { + auto error = + this->IOSync( + ioControlCode, + in, + outBuffer, + outBufferSize, + bytesReturned + ); + + if (error != 0) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] error",__FUNCTION__); + System::Console::WriteLine("========================================================="); + #endif + return error; + } + + out = safe_cast(InteropServices::Marshal::PtrToStructure(outBuffer, OUT::typeid)); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] out {1}",__FUNCTION__, out); + // System::Console::WriteLine("========================================================="); + #endif + + return 0; + } + finally + { + InteropServices::Marshal::FreeHGlobal(outBuffer); + } + } + + generic + Irp::Tuple^ Irp::GetSingle( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in + ) + { + #ifdef _DEBUG + System::Console::WriteLine("========================================================="); + System::Console::WriteLine("[{0}] {1}",__FUNCTION__, in); + #endif + + auto outBufferSize = InteropServices::Marshal::SizeOf(OUT::typeid); + auto outBuffer = InteropServices::Marshal::AllocHGlobal(outBufferSize); + + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] outBufferSize {1}",__FUNCTION__, outBufferSize); + #endif + + System::UInt32 bytesReturned = 0; + + try + { + auto error = + this->IOSync( + ioControlCode, + in, + outBuffer, + outBufferSize, + bytesReturned + ); + + if (error != 0) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] null",__FUNCTION__); + System::Console::WriteLine("========================================================="); + #endif + return nullptr; + } + + OUT out = safe_cast(InteropServices::Marshal::PtrToStructure(outBuffer, OUT::typeid)); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] out {1}",__FUNCTION__, out); + System::Console::WriteLine("========================================================="); + #endif + + return gcnew Tuple(out); + } + finally + { + InteropServices::Marshal::FreeHGlobal(outBuffer); + } + } + + generic + System::UInt32 Irp::Put( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in, + System::UInt32% bytesReturned + ) + { + return + this->IOSync( + ioControlCode, + in, + System::IntPtr::Zero, + 0, + bytesReturned + ); + } + + generic + array^ Irp::GetMultiple( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in + ) + { + #ifdef _DEBUG + System::Console::WriteLine("========================================================="); + System::Console::WriteLine("[{0}] {1}",__FUNCTION__, in); + #endif + + System::UInt32 bytesReturned = 0; + + auto error = + this->Put( + ioControlCode, + in, + bytesReturned + ); + + if (error != 0x800700EA)//ERROR_MORE_DATA + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] null",__FUNCTION__); + System::Console::WriteLine("========================================================="); + #endif + return nullptr; + } + + auto outBufferSize = bytesReturned; + auto outBuffer = InteropServices::Marshal::AllocHGlobal(outBufferSize); + + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] outBufferSize {1}",__FUNCTION__, outBufferSize); + #endif + + try + { + auto error = + this->IOSync( + ioControlCode, + in, + outBuffer, + outBufferSize, + bytesReturned + ); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] outBufferSize {1}",__FUNCTION__, bytesReturned); + #endif + InteropServices::Marshal::ThrowExceptionForHR(error); + + auto items = safe_cast(InteropServices::Marshal::PtrToStructure(outBuffer, Interop::Ks::KsMultipleItem::typeid)); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] items {1} ",__FUNCTION__, items); + #endif + + System::Collections::Generic::List^ result = gcnew System::Collections::Generic::List; + + auto ptr = outBuffer + InteropServices::Marshal::SizeOf(Interop::Ks::KsMultipleItem::typeid); + for (System::UInt32 idx = 0; idx < items->Count; idx++) + { + OUT out = safe_cast(InteropServices::Marshal::PtrToStructure(ptr, OUT::typeid)); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] item {2} ",__FUNCTION__, idx, out); + #endif + result->Add(out); + + if (Interop::Ks::KsDataFormat::typeid == OUT::typeid) + { + Interop::Ks::KsDataFormat^ dataFormat = safe_cast(out); + + if (dataFormat->FormatSize >= safe_cast(InteropServices::Marshal::SizeOf(Interop::Ks::KsDataRangeAudio::typeid))) + { + auto w = safe_cast(InteropServices::Marshal::PtrToStructure(ptr, Interop::Ks::KsDataRangeAudio::typeid)); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}]",__FUNCTION__, w); + #endif + } + /*else if (dataFormat->FormatSize != safe_cast(InteropServices::Marshal::SizeOf(Interop::Ks::KsDataFormat::typeid))) + { + auto ptr2 = ptr + safe_cast(InteropServices::Marshal::SizeOf(Interop::Ks::KsDataFormat::typeid)); + auto w = safe_cast(InteropServices::Marshal::PtrToStructure(ptr2, Interop::Winmm::WaveFormat::typeid)); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}]",__FUNCTION__, w); + #endif + }*/ + + ptr += dataFormat->FormatSize; + } + else + { + ptr += InteropServices::Marshal::SizeOf(OUT::typeid); + } + } + + #ifdef _DEBUG + System::Console::WriteLine("========================================================="); + #endif + return result->ToArray(); + } + finally + { + InteropServices::Marshal::FreeHGlobal(outBuffer); + } + } + + + generic + array^ Irp::GetArray( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in + ) + { + #ifdef _DEBUG + System::Console::WriteLine("========================================================="); + System::Console::WriteLine("[{0}] {1}",__FUNCTION__, in); + #endif + + System::UInt32 bytesReturned = 0; + + auto error = + this->Put( + ioControlCode, + in, + bytesReturned + ); + + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] bytesReturned {1}",__FUNCTION__, bytesReturned); + #endif + + if (error != 0x800700EA)//ERROR_MORE_DATA + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] {1}",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + System::Console::WriteLine("========================================================="); + #endif + return nullptr; + } + + if (bytesReturned == 0) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] bytesReturned == 0",__FUNCTION__); + System::Console::WriteLine("========================================================="); + #endif + return nullptr; + } + + auto itemSize = InteropServices::Marshal::SizeOf(OUT::typeid); + if ((bytesReturned % itemSize) != 0) + { + //割り切れないのでNG + #ifdef _DEBUG + System::Console::WriteLine("[{0}] 割り切れない bytesReturned[{1}] typeid size[{2}]",__FUNCTION__, bytesReturned, itemSize); + System::Console::WriteLine("========================================================="); + #endif + return nullptr; + } + + auto itemCount = (bytesReturned / itemSize); + + auto outBufferSize = bytesReturned; + auto outBuffer = InteropServices::Marshal::AllocHGlobal(outBufferSize); + + try + { + auto error = + this->IOSync( + ioControlCode, + in, + outBuffer, + outBufferSize, + bytesReturned + ); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] bytesReturned {1}",__FUNCTION__, bytesReturned); + #endif + + InteropServices::Marshal::ThrowExceptionForHR(error); + + System::Collections::Generic::List^ result = gcnew System::Collections::Generic::List; + + auto ptr = outBuffer; + for (System::UInt32 idx = 0; idx < itemCount; idx++) + { + OUT out = safe_cast(InteropServices::Marshal::PtrToStructure(ptr, OUT::typeid)); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] item {2} ",__FUNCTION__, idx, out); + #endif + result->Add(out); + ptr += itemSize; + } + + #ifdef _DEBUG + System::Console::WriteLine("========================================================="); + #endif + return result->ToArray(); + } + finally + { + InteropServices::Marshal::FreeHGlobal(outBuffer); + } + } + + +} +} +} diff --git a/Core/Momiji.Core.Ks.h b/Core/Momiji.Core.Ks.h new file mode 100644 index 0000000..7ba7be3 --- /dev/null +++ b/Core/Momiji.Core.Ks.h @@ -0,0 +1,156 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Ks.h + kernel streaming +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +#include "Momiji.Interop.Guiddef.h" +#include "Momiji.Interop.Ks.h" +#include "Momiji.Core.Buffer.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Ks { + + ref class Overlapped + { + private: + System::Threading::EventWaitHandle^ _waitHandle; + System::Threading::NativeOverlapped _overlapped; + InteropServices::GCHandle _overlappedHandle; + + public: + Overlapped(); + virtual ~Overlapped(); + protected: + !Overlapped(); + + public: + void Reset(); + + public: + property System::Threading::NativeOverlapped% overlapped + { + System::Threading::NativeOverlapped% get() { return this->_overlapped; } + } + + property System::Boolean pendding + { + System::Boolean get() { return !this->_waitHandle->WaitOne(0); } + } + }; + + + ref class Irp abstract + { + private: + initonly Interop::Kernel32::Function::File^ _handle; + + public: + Irp(); + virtual ~Irp(); + protected: + !Irp(); + + protected: + virtual Interop::Kernel32::Function::File^ Open() abstract; + + public: + property Interop::Kernel32::Function::File^ handle + { + Interop::Kernel32::Function::File^ get() { return this->_handle; } + } + + private: + void Close(); + + public: + System::UInt32 IOSync( + Interop::Ks::IOCTL_KS ioControlCode, + System::IntPtr inBuffer, + System::UInt32 inBufferSize, + System::IntPtr outBuffer, + System::UInt32 outBufferSize, + System::UInt32% bytesReturned + ); + + generic + System::UInt32 IOSync( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in, + System::IntPtr outBuffer, + System::UInt32 outBufferSize, + System::UInt32% bytesReturned + ); + + generic + System::UInt32 IOSync( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in, + OUT% out + ); + + //System::Tupleを使うとコンパイルエラー(C2440)が出るので、仕方なく定義 + generic + ref class Tuple + { + public: + T value; + Tuple(T v): value(v) {}; + }; + + generic + Tuple^ GetSingle( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in + ); + + generic + System::UInt32 Put( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in, + System::UInt32% bytesReturned + ); + + generic + array^ GetMultiple( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in + ); + + generic + array^ GetArray( + Interop::Ks::IOCTL_KS ioControlCode, + IN% in + ); + }; + + + + + +} +} +} diff --git a/Core/Momiji.Core.MMDeviceAPI.cpp b/Core/Momiji.Core.MMDeviceAPI.cpp new file mode 100644 index 0000000..1cc3943 --- /dev/null +++ b/Core/Momiji.Core.MMDeviceAPI.cpp @@ -0,0 +1,479 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Midi.Out.cpp + midi output component. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Interop.MMDeviceAPI.h" +#include "Momiji.Core.MMDeviceAPI.h" + +namespace Momiji { +namespace Core { +namespace MMDeviceAPI { + + Devices::Devices( + Interop::MMDeviceAPI::EDataFlow dataFlow + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}][dataFlow:{1}]",__FUNCTION__, dataFlow); + #endif + + #ifdef _DEBUG + System::Console::WriteLine("[{0}][dataFlow:{1}]",__FUNCTION__, Interop::MMDeviceAPI::FunctionDiscoveryKeys_devpkey::PKEY_Device); + #endif + + + + Interop::MMDeviceAPI::IMMDeviceEnumerator^ a = gcnew Interop::MMDeviceAPI::MMDeviceEnumeratorClass(); + Interop::MMDeviceAPI::IMMDeviceCollection^ b; + + a->EnumAudioEndpoints(dataFlow, 1, b); + + System::UInt32 c; + b->GetCount(c); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}][IMMDeviceCollection.GetCount:{1}]",__FUNCTION__, c); + #endif + + for (auto i = 0; i < c; i++) { + Interop::MMDeviceAPI::IMMDevice^ d; + + b->Item(i, d); + + System::String^ e; + d->GetId(e); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}][IMMDevice.GetId:{1}]",__FUNCTION__, e); + #endif + + Interop::MMDeviceAPI::DEVICE_STATE f; + d->GetState(f); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}][IMMDevice.GetState:{1:F}]",__FUNCTION__, f); + #endif + + Interop::PropIdl::IPropertyStore^ g; + d->OpenPropertyStore(Interop::MMDeviceAPI::STGM::READ, g); + + System::UInt32 h; + g->GetCount(h); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}][IPropertyStore.GetCount:{1}]",__FUNCTION__, h); + #endif + + for (auto j = 0; j < h; j++) { + auto x = gcnew Interop::PropIdl::PROPERTYKEY(); + g->GetAt(j, x); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}][IPropertyStore.GetAt:{1}]",__FUNCTION__, x); + #endif + auto y = gcnew Interop::PropIdl::PROPVARIANT(); + auto marshaler = Interop::PropIdl::PROPVARIANTMarshaler::GetInstance(""); + auto z = marshaler->MarshalManagedToNative(y); + try + { + g->GetValue(x, z); + y = safe_cast(marshaler->MarshalNativeToManaged(z)); + } + finally + { + marshaler->CleanUpNativeData(z); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}][IPropertyStore.GetValue:{1}]",__FUNCTION__, y); + #endif + } + + delete g; + delete d; + } + + delete b; + delete a; + + } + + Devices::~Devices() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Devices(); + } + + Devices::!Devices() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + // this->_handle->Close(); + } + + Devices::Detail::Detail( + Devices^ devices, + System::UInt32 index + )//: + // _devices(devices) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + +// this->GetDetail(index); + } + + Devices::Detail::~Detail() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Detail(); + } + + Devices::Detail::!Detail() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } +/* + void Devices::Detail::GetDetail( + System::UInt32 index + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}][index: {1}]",__FUNCTION__, index); + #endif + + auto data = Interop::Setupapi::SpDeviceInterfaceData(); + data.cbSize = safe_cast(InteropServices::Marshal::SizeOf(data)); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] data->cbSize {1}",__FUNCTION__, data.cbSize); + #endif + if ( + !Interop::Setupapi::Function::SetupDiEnumDeviceInterfaces( + this->_devices->_handle, + nullptr, + this->_devices->_category, + index, + data + ) + ) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] error [{1}]",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + if (error == 0x80070103) //ERROR_NO_MORE_ITEMS + { + this->_noMoreItems = true; + return; + } + else + { + InteropServices::Marshal::ThrowExceptionForHR(error); + } + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] data [{1}]", __FUNCTION__, data); + #endif + + this->_data = data; + + //ƒf[ƒ^ƒTƒCƒYŠm”F + System::UInt32 reqired = 0; + + if ( + !Interop::Setupapi::Function::SetupDiGetDeviceInterfaceDetail( + this->_devices->_handle, + this->_data, + System::IntPtr::Zero, + 0, + reqired, + System::IntPtr::Zero + ) + ) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] error [{1}]",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + if (error != 0x8007007A)//ERROR_INSUFFICIENT_BUFFER + { + InteropServices::Marshal::ThrowExceptionForHR(error); + } + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] reqired {1}",__FUNCTION__, reqired); + #endif + + //EEE‚Í‚µ‚Ä‚é‚à‚̂́AŒ‹‹Ç¡‚́A1024byteŒÅ’è‚œǂݍž‚ñ‚Å‚¢‚é + auto detail = Interop::Setupapi::SpDeviceInterfaceDetailData(); + detail.cbSize = safe_cast(InteropServices::Marshal::SizeOf(detail.cbSize) + InteropServices::Marshal::SystemDefaultCharSize); + + auto info = Interop::Setupapi::SpDevinfoData(); + info.cbSize = safe_cast(InteropServices::Marshal::SizeOf(info)); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] detail->cbSize {1}",__FUNCTION__, detail.cbSize); + #endif + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] info->cbSize {1}",__FUNCTION__, info.cbSize); + #endif + + if ( + !Interop::Setupapi::Function::SetupDiGetDeviceInterfaceDetail( + this->_devices->_handle, + this->_data, + detail, + reqired, + reqired, + info + ) + ) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + InteropServices::Marshal::ThrowExceptionForHR(error); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] detail [{1}]",__FUNCTION__, detail); + System::Console::WriteLine("[{0}] info [{1}]", __FUNCTION__, info); + #endif + + this->_devicePath = detail.DevicePath; + this->_info = info; + } + + Interop::Setupapi::SpDeviceInterfaceData^ Devices::Detail::GetAlias( + Interop::Guiddef::Guid subCategory + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}][{1}]",__FUNCTION__, subCategory); + #endif + auto data = Interop::Setupapi::SpDeviceInterfaceData(); + data.cbSize = safe_cast(InteropServices::Marshal::SizeOf(data)); + + if ( + !Interop::Setupapi::Function::SetupDiGetDeviceInterfaceAlias( + this->_devices->_handle, + this->_data, + subCategory, + data + ) + ) + { + #ifdef _DEBUG + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + System::Console::WriteLine("[{0}] error [{1}]",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + return nullptr; + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] alias [{1}]", __FUNCTION__, data); + #endif + return data; + } + + System::String^ Devices::Detail::GetDeviceRegistryProperty( + Interop::Setupapi::SPDRP spdrp + ) + { + #ifdef _DEBUG + // System::Console::WriteLine("[{0}][{1}]",__FUNCTION__, spdrp); + #endif + System::UInt32 regDataType = 0; + System::UInt32 reqired = 0; + if ( + !Interop::Setupapi::Function::SetupDiGetDeviceRegistryProperty( + this->_devices->_handle, + this->_info, + spdrp, + regDataType, + nullptr, + 0, + reqired + ) + ) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] error {1:X}",__FUNCTION__, error); + #endif + if (error != 0x8007007A)//ERROR_INSUFFICIENT_BUFFER + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] {1} [{2}]",__FUNCTION__, spdrp, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + return nullptr; + } + } + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] reqired {1}",__FUNCTION__, reqired); + #endif + auto buf = gcnew System::Text::StringBuilder(safe_cast(reqired)); + + if ( + !Interop::Setupapi::Function::SetupDiGetDeviceRegistryProperty( + this->_devices->_handle, + this->_info, + spdrp, + regDataType, + buf, + reqired, + reqired + ) + ) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] error {1:X}",__FUNCTION__, error); + #endif + InteropServices::Marshal::ThrowExceptionForHR(error); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] {1} [{2}]",__FUNCTION__, spdrp, buf->ToString()); + #endif + return buf->ToString(); + } + + System::String^ Devices::Detail::GetDeviceRegistryProperty( + System::String^ name + ) + { + #ifdef _DEBUG + // System::Console::WriteLine("[{0}][{1}]",__FUNCTION__, name); + #endif + Interop::Setupapi::Function::RegKey^ regKey; + + { + regKey = + Interop::Setupapi::Function::SetupDiOpenDeviceInterfaceRegKey( + this->_devices->_handle, + this->_data, + 0, + Interop::Kernel32::ACCESS_TYPES::KEY_READ + ); + if (regKey->IsInvalid) + { + #ifdef _DEBUG + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + System::Console::WriteLine("[{0}] error {1:X}",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + return nullptr; + } + } + + try + { + System::UInt32 type = 0; + System::UInt32 size = 1024; + auto data = InteropServices::Marshal::AllocHGlobal(size); + try + { + System::UInt32 error = + Interop::Setupapi::Function::RegQueryValueEx( + regKey, + name, + System::IntPtr::Zero, + type, + data, + size + ); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] error {1:X}",__FUNCTION__, error); + #endif + if (error != 0) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] msg {1}",__FUNCTION__, InteropServices::Marshal::GetExceptionForHR(error)->ToString()); + #endif + return nullptr; + } + + auto result = InteropServices::Marshal::PtrToStringAuto(data); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] {1} [{2}]",__FUNCTION__, name, result); + #endif + return result; + } + finally + { + InteropServices::Marshal::FreeHGlobal(data); + } + } + finally + { + delete regKey; + } + } + + + + Devices::DetailEnum::DetailEnum( + Devices^ devices + ): + _devices(devices), + _index(0) //ˆê”Ê“I‚È—p–@‚©‚ç‚ÍŠO‚µ‚āAMoveNextŒã‚É+1‚µ‚Ä‚¢‚é + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + System::Boolean Devices::DetailEnum::MoveNext() + { + auto detail = + gcnew Detail( + this->_devices, + this->_index++ + ); + + this->_detail = + (detail->IsNoMoreItems) + ? nullptr + : detail + ; + return !detail->IsNoMoreItems; + } + + void Devices::DetailEnum::Reset() + { + this->_detail = nullptr; + this->_index = 0; + } + */ +} +} +} diff --git a/Core/Momiji.Core.MMDeviceAPI.h b/Core/Momiji.Core.MMDeviceAPI.h new file mode 100644 index 0000000..9e1e705 --- /dev/null +++ b/Core/Momiji.Core.MMDeviceAPI.h @@ -0,0 +1,68 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Ks.h + kernel streaming +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +#include "Momiji.Interop.Guiddef.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace MMDeviceAPI { + + public ref class Devices + { + public: + ref class Detail + { + private: + Interop::MMDeviceAPI::IMMDevice^ _mmDevice; + + + public: + Detail( + Devices^ devices, + System::UInt32 index + ); + ~Detail(); + + protected: + !Detail(); + + }; + + public: + Devices( + Interop::MMDeviceAPI::EDataFlow dataFlow + ); + + ~Devices(); + protected: + !Devices(); + }; + +} +} +} diff --git a/Core/Momiji.Core.Midi.Data.h b/Core/Momiji.Core.Midi.Data.h new file mode 100644 index 0000000..ef0d188 --- /dev/null +++ b/Core/Momiji.Core.Midi.Data.h @@ -0,0 +1,118 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Midi.Data.h + midi data. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +#include "Momiji.Interop.Winmm.h" +#include "Momiji.Core.Interface.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Midi { + + public ref class MidiData abstract + : public Core::IData + { + private: + initonly System::UInt16 _port; + + protected: + MidiData( + System::UInt16 port + ): _port(port){} + + public: + enum class TYPE: System::Byte + { + NOTE_OFF = 0x80, // {8x 128..143 | nn vv | n:note num; v:velocity} + NOTE_ON = 0x90, // {9x 144..159 | nn vv | n:note num; v:velocity} + POLYHONIC_KEY_PRESSURE = 0xA0, // {Ax 160..176 | nn vv | n:note num; v:velocity} + CONTROL_CHANGE = 0xB0, // {Bx 176..191 | cc vv | n:ctrl num; v:value} + PROGRAM_CHANGE = 0xC0, // {Cx 192..207 | pp | p:prog num} + CNANNEL_PRESSURE = 0xD0, // {Dx 208..223 | cc | c:chan num} + PITCH_WHILE_CHANGE = 0xE0, // {Ex 224..239 | ll mm | l:least sig; m:most sig} + //{center 2000H} + SYSTEM_MESSAGE = 0xF0, + SYSTEM_EXCLUSIVE = 0xF0, + META = 0xFF, + }; + + property System::UInt16 port { System::UInt16 get() {return this->_port;} } + }; + + public ref class ShortData + : public MidiData + { + private: + initonly System::Byte _param1; + initonly System::Byte _param2; + initonly System::Byte _status; + + public: + ShortData( + System::UInt16 port, + System::Byte status, + System::Byte param1, + System::Byte param2 + ): MidiData(port), _status(status), _param1(param1), _param2(param2) {} + + property System::Byte status { System::Byte get() {return this->_status;} } + property System::Byte param1 { System::Byte get() {return this->_param1;} } + property System::Byte param2 { System::Byte get() {return this->_param2;} } + property System::UInt32 shortData + { + System::UInt32 get() + { + return ( + this->status | + (this->param1 << 8) | + (this->param2 << 16) + ); + } + } + }; + + public ref class LongData + : public MidiData + { + private: + initonly array^ _longData; + initonly System::UInt32 _useSize; + + public: + LongData( + System::UInt16 port, + array^ longData, + System::UInt32 useSize + ): MidiData(port), _longData(longData), _useSize(useSize) {} + + property array^ longData { array^ get() {return this->_longData;} } + property System::UInt32 useSize { System::UInt32 get() { return this->_useSize; } } + }; + +} +} +} diff --git a/Core/Momiji.Core.Midi.In.cpp b/Core/Momiji.Core.Midi.In.cpp new file mode 100644 index 0000000..dec114f --- /dev/null +++ b/Core/Momiji.Core.Midi.In.cpp @@ -0,0 +1,524 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Midi.In.cpp + midi input component. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Interop.Winmm.h" +#include "Momiji.Core.Midi.In.h" +#include "Momiji.Core.Midi.Data.h" + +namespace Momiji { +namespace Core { +namespace Midi { +namespace In { + + void Device::OnEventHandler( + System::Object^ sender, + Interop::Winmm::DriverCallBack::DriverEventArgs^ args + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] start", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + + switch (args->uMsg) + { + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_OPEN: + { + this->DoOpen(args->dw1, args->dw2); + break; + } + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_CLOSE: + { + this->DoClose(args->dw1, args->dw2); + break; + } + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_DATA: + { + this->DoData(args->dw1, args->dw2); + break; + } + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_LONGDATA: + { + this->DoLongData(args->dw1, args->dw2); + break; + } + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_ERROR: + { + this->DoError(args->dw1, args->dw2); + break; + } + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_LONGERROR: + { + this->DoLongError(args->dw1, args->dw2); + break; + } + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_MOREDATA: + { + this->DoMoreData(args->dw1, args->dw2); + break; + } + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] end", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + } + + void Device::DoOpen(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + this->OnOpen(this, System::EventArgs::Empty); + } + + void Device::DoClose(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + this->OnClose(this, System::EventArgs::Empty); + } + + ///~ + ///~ + ///~ + /// + void Device::DoData(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + auto data = dwParam1.ToInt32(); + auto time = dwParam2.ToInt32(); + this->OnData(data, time); + } + + void Device::DoLongData(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + + this->Unprepare(dwParam1); + + auto header = safe_cast(InteropServices::Marshal::PtrToStructure(dwParam1, Interop::Winmm::MidiHeader::typeid)); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] bytesRecorded {1}", __FUNCTION__, header->bytesRecorded); + #endif + + if (header->bytesRecorded == 0) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] resetされたと判断して、再準備はしない", __FUNCTION__); + #endif + } + else + { + auto data = gcnew array(header->bytesRecorded); + + #ifdef _DEBUG + System::Console::Write("[{0}] ", __FUNCTION__); + for (System::UInt32 i = 0; i < header->bytesRecorded; i++) + { + System::Console::Write("[{0,2:X}]", InteropServices::Marshal::ReadByte(header->data,i)); + } + System::Console::WriteLine(); + #endif + + InteropServices::Marshal::Copy( header->data, data, 0, data->Length ); + auto time = dwParam2.ToInt32(); + this->OnLongData(data, time); + this->Prepare(); + } + } + + void Device::DoError(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + } + + void Device::DoLongError(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + + this->Unprepare(dwParam1); + } + + void Device::DoMoreData(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + + this->Unprepare(dwParam1); + + auto header = safe_cast(InteropServices::Marshal::PtrToStructure(dwParam1, Interop::Winmm::MidiHeader::typeid)); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] bytesRecorded {1}", __FUNCTION__, header->bytesRecorded); + #endif + + auto data = gcnew array(header->bytesRecorded); + + #ifdef _DEBUG + System::Console::Write("[{0}] ", __FUNCTION__); + for (System::UInt32 i = 0; i < header->bytesRecorded; i++) + { + System::Console::Write("[{0,2:X}]", InteropServices::Marshal::ReadByte(header->data,i)); + } + System::Console::WriteLine(); + #endif + + InteropServices::Marshal::Copy( header->data, data, 0, data->Length ); + + auto time = dwParam2.ToInt32(); + this->OnMoreData(data, time); + this->Prepare(); + } + + System::UInt32 Device::GetNumDevices() + { + return Interop::Winmm::Function::midiInGetNumDevs(); + } + + Interop::Winmm::MidiInCapabilities^ Device::GetCapabilities( + const System::UInt32 deviceID + ) + { + auto caps = gcnew Interop::Winmm::MidiInCapabilities(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] caps size {1}",__FUNCTION__, InteropServices::Marshal::SizeOf(caps)); + #endif + auto mmResult = + Interop::Winmm::Function::midiInGetDevCaps( + deviceID, + caps, + InteropServices::Marshal::SizeOf(caps) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew MidiInException(mmResult); + } + return caps; + } + + Device::Device( + const System::UInt32 deviceID + ): _deviceID(deviceID) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] deviceID {1}",__FUNCTION__, this->_deviceID); + #endif + this->Open(); + } + + Device::~Device() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Device(); + } + + Device::!Device() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->Close(); + } + + Interop::Winmm::MidiInCapabilities^ Device::GetCapabilities() + { + return Device::GetCapabilities(this->_deviceID); + } + + void Device::Open() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_callBack = gcnew Core::Winmm::DriverCallBack(false); //イベントは同期で動かす + this->_callBack->OnEvent += gcnew System::EventHandler(this, &Device::OnEventHandler); + + this->_headerPool = + gcnew Core::Buffer::BufferPool( + 2, //2回分のバッファを用意 + gcnew Core::Buffer::BufferPool::Allocator(this, &Device::AllocateHeader) + ); + + this->_bufferPool = + gcnew Core::Buffer::BufferPool^>( + 2, //2回分のバッファを用意 + gcnew Core::Buffer::BufferPool^>::Allocator(this, &Device::AllocateBuffer) + ); + + { + auto mmResult = + Interop::Winmm::Function::midiInOpen( + this->_handle, + this->_deviceID, + this->_callBack->GetDriverCallBackProc(), + System::IntPtr::Zero, + Interop::Winmm::DriverCallBack::TYPE::FUNCTION + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) { + throw gcnew MidiInException(mmResult); + } + } + + this->Prepare(); + + { + auto mmResult = Interop::Winmm::Function::midiInStart(this->_handle); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew MidiInException(mmResult); + } + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed); + #endif + } + + void Device::Close() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed); + #endif + if ( + !this->_handle->IsInvalid + && !this->_handle->IsClosed + ) + { + { + auto mmResult = Interop::Winmm::Function::midiInStop(this->_handle); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew MidiInException(mmResult); + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] midiInStop OK",__FUNCTION__); + #endif + } + + { + auto mmResult = Interop::Winmm::Function::midiInReset(this->_handle); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew MidiInException(mmResult); + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] midiInReset OK",__FUNCTION__); + #endif + } + + //バッファの開放待ち + while(this->_headerPool->IsBusy()) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] wait for unprepare headers ...",__FUNCTION__); + #endif + System::Threading::Thread::Sleep(5); + } + + this->_handle->Close(); + } + else + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] openしていない状態なので、無視します。", __FUNCTION__); + #endif + } + + if (this->_callBack != nullptr) + { + this->_callBack->OnEvent -= gcnew System::EventHandler(this, &Device::OnEventHandler); + delete this->_callBack; + } + + if (this->_headerPool != nullptr) + { + delete this->_headerPool; + } + + if (this->_bufferPool != nullptr) + { + delete this->_bufferPool; + } + } + + System::IntPtr Device::Prepare() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto header = this->_headerPool->Get(); + auto buffer = this->_bufferPool->Get(); + + { + auto midiHeader = header->GetBuffer(); + midiHeader->bufferLength = buffer->GetBuffer()->Length; + midiHeader->data = buffer->GetBufferIntPtr(); + + #ifdef _DEBUG + { + System::Console::WriteLine("[{0}] midiInPrepareHeader before", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader); + } + #endif + } + + { + auto mmResult = + Interop::Winmm::Function::midiInPrepareHeader( + this->_handle, + header->GetBufferIntPtr(), + InteropServices::Marshal::SizeOf(Interop::Winmm::MidiHeader::typeid) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + this->_headerPool->Release(header); + this->_bufferPool->Release(buffer); + + throw gcnew MidiInException(mmResult); + } + } + #ifdef _DEBUG + { + auto midiHeader = header->GetBuffer(); + System::Console::WriteLine("[{0}] midiInPrepareHeader after", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader); + } + #endif + + { + auto mmResult = + Interop::Winmm::Function::midiInAddBuffer( + this->_handle, + header->GetBufferIntPtr(), + InteropServices::Marshal::SizeOf(Interop::Winmm::MidiHeader::typeid) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + System::Console::WriteLine((gcnew MidiInException(mmResult))->ToString()); + } + } + #ifdef _DEBUG + { + auto midiHeader = header->GetBuffer(); + System::Console::WriteLine("[{0}] midiInAddBuffer after", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader); + } + #endif + + return header->GetBufferIntPtr(); + } + + void Device::Unprepare(System::IntPtr headerPtr) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto header = this->_headerPool->GetBusy(headerPtr); + + #ifdef _DEBUG + { + auto midiHeader = header->GetBuffer(); + System::Console::WriteLine("[{0}] midiInUnprepareHeader before", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader); + } + #endif + + auto mmResult = + Interop::Winmm::Function::midiInUnprepareHeader( + this->_handle, + headerPtr, + InteropServices::Marshal::SizeOf(Interop::Winmm::MidiHeader::typeid) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew MidiInException(mmResult); + } + + auto bufferPtr = header->GetBuffer()->data; + this->_headerPool->Release(header); + + auto buffer = this->_bufferPool->GetBusy(bufferPtr); + this->_bufferPool->Release(buffer); + + #ifdef _DEBUG + { + auto midiHeader = header->GetBuffer(); + System::Console::WriteLine("[{0}] midiInUnprepareHeader after", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader); + } + #endif + } + + Interop::Winmm::MidiHeader^ Device::AllocateHeader() + { + return gcnew Interop::Winmm::MidiHeader(); + } + + array^ Device::AllocateBuffer() + { + return gcnew array(256); //SMFとして最大長 + 1 + } + + System::String^ MidiInException::Initialize() + { + auto errorMessage = System::String::Empty; + auto buf = gcnew System::Text::StringBuilder(256); + + auto r = + Interop::Winmm::Function::midiInGetErrorText( + this->_mmResult, + buf, + buf->Capacity + ); + if (r == Interop::Winmm::MMRESULT::NOERROR) + { + errorMessage = buf->ToString(); + } + else + { + errorMessage = "不明なエラー"; + } + + return errorMessage + "[" + this->_mmResult.ToString("D") + "]"; + } + +} +} +} +} diff --git a/Core/Momiji.Core.Midi.In.h b/Core/Momiji.Core.Midi.In.h new file mode 100644 index 0000000..eb81894 --- /dev/null +++ b/Core/Momiji.Core.Midi.In.h @@ -0,0 +1,110 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Midi.In.h + midi input component. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Core.Winmm.h" +#include "Momiji.Core.Buffer.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Midi { +namespace In { + + public ref class Device + { + private: + initonly System::UInt32 _deviceID; + Interop::Winmm::Function::MidiIn^ _handle; + Core::Winmm::DriverCallBack^ _callBack; + Core::Buffer::BufferPool^ _headerPool; + Core::Buffer::BufferPool^>^ _bufferPool; + + public: + Device(const System::UInt32 deviceID); + virtual ~Device(); + protected: + !Device(); + + private: + System::IntPtr Prepare(); + void Unprepare(System::IntPtr headerPtr); + + Interop::Winmm::MidiHeader^ AllocateHeader(); + array^ AllocateBuffer(); + + public: + static System::UInt32 GetNumDevices(); + static Interop::Winmm::MidiInCapabilities^ GetCapabilities(const System::UInt32 uDeviceID); + Interop::Winmm::MidiInCapabilities^ GetCapabilities(); + + private: + void Open(); + void Close(); + + public: + event System::EventHandler^ OnOpen; + event System::EventHandler^ OnClose; + + delegate void ShortEvent(System::UInt32 data, System::UInt32 time); + event ShortEvent^ OnData; + + delegate void LongEvent(array^ data, System::UInt32 time); + event LongEvent^ OnLongData; + event LongEvent^ OnMoreData; + + private: + void OnEventHandler(System::Object^ sender, Interop::Winmm::DriverCallBack::DriverEventArgs^ args); + void DoOpen(System::IntPtr dwParam1, System::IntPtr dwParam2); + void DoClose(System::IntPtr dwParam1, System::IntPtr dwParam2); + + void DoData(System::IntPtr dwParam1, System::IntPtr dwParam2); + void DoError(System::IntPtr dwParam1, System::IntPtr dwParam2); + + void DoLongData(System::IntPtr dwParam1, System::IntPtr dwParam2); + void DoLongError(System::IntPtr dwParam1, System::IntPtr dwParam2); + void DoMoreData(System::IntPtr dwParam1, System::IntPtr dwParam2); + }; + + public ref class MidiInException: System::Exception + { + private: + initonly Interop::Winmm::MMRESULT _mmResult; + System::String^ Initialize(); + + public: + MidiInException(Interop::Winmm::MMRESULT v): _mmResult(v), System::Exception(Initialize()){}; + MidiInException(System::String^ v): System::Exception(v){}; + virtual ~MidiInException(void){}; + + property Interop::Winmm::MMRESULT mmResult + { + Interop::Winmm::MMRESULT get(void) {return this->_mmResult;}; + } + }; +} +} +} +} diff --git a/Core/Momiji.Core.Midi.Out.cpp b/Core/Momiji.Core.Midi.Out.cpp new file mode 100644 index 0000000..bd5a6a5 --- /dev/null +++ b/Core/Momiji.Core.Midi.Out.cpp @@ -0,0 +1,524 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Midi.Out.cpp + midi output component. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Interop.Winmm.h" +#include "Momiji.Core.Midi.Out.h" +#include "Momiji.Core.Midi.Data.h" + +namespace Momiji { +namespace Core { +namespace Midi { +namespace Out { + + void Device::OnEventHandler( + System::Object^ sender, + Interop::Winmm::DriverCallBack::DriverEventArgs^ args + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] start", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + + switch (args->uMsg) + { + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MOM_OPEN : + { + this->DoOpen(args->dw1, args->dw2); + break; + } + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MOM_CLOSE: + { + this->DoClose(args->dw1, args->dw2); + break; + } + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MOM_DONE : + {//Param1 = MIDIHDR + this->DoDone(args->dw1, args->dw2); + break; + } + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] end", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + } + + void Device::DoOpen(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + this->OnOpen(this, System::EventArgs::Empty); + } + + void Device::DoClose(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + this->OnClose(this, System::EventArgs::Empty); + } + + void Device::DoDone(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + + auto midiHeader = + safe_cast(InteropServices::Marshal::PtrToStructure(dwParam1, Interop::Winmm::MidiHeader::typeid)); + + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader); + System::Console::Write("[{0}] ", __FUNCTION__); + for (System::UInt32 i = 0; i < midiHeader->bufferLength; i++) + { + System::Console::Write("[{0,2:X}]", InteropServices::Marshal::ReadByte(midiHeader->data,i)); + } + System::Console::WriteLine(); + #endif + + this->Unprepare(dwParam1); + } + + System::UInt32 Device::GetNumDevices() + { + return Interop::Winmm::Function::midiOutGetNumDevs(); + } + + Interop::Winmm::MidiOutCapabilities^ Device::GetCapabilities( + const System::UInt32 deviceID + ) + { + auto caps = gcnew Interop::Winmm::MidiOutCapabilities(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] caps size {1}",__FUNCTION__, InteropServices::Marshal::SizeOf(caps)); + #endif + auto mmResult = + Interop::Winmm::Function::midiOutGetDevCaps( + deviceID, + caps, + InteropServices::Marshal::SizeOf(caps) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew MidiOutException(mmResult); + } + return caps; + } + + Device::Device( + const System::UInt32 deviceID + ): _deviceID(deviceID) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] deviceID {1}",__FUNCTION__, this->_deviceID); + #endif + + this->Open(); + } + + Device::~Device() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Device(); + } + + Device::!Device() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->Close(); + } + + Interop::Winmm::MidiOutCapabilities^ Device::GetCapabilities() + { + return Device::GetCapabilities(this->_deviceID); + } + + void Device::Open() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_callBack = gcnew Core::Winmm::DriverCallBack(true); //イベントは非同期で動かす + this->_callBack->OnEvent += gcnew System::EventHandler(this, &Device::OnEventHandler); + + this->_headerPool = + gcnew Core::Buffer::BufferPool( + 2, //2回分のバッファを用意 + gcnew Core::Buffer::BufferPool::Allocator(this, &Device::AllocateHeader) + ); + + this->_bufferPool = + gcnew Core::Buffer::BufferPool^>( + 2, //2回分のバッファを用意 + gcnew Core::Buffer::BufferPool^>::Allocator(this, &Device::AllocateBuffer) + ); + + auto mmResult = + Interop::Winmm::Function::midiOutOpen( + this->_handle, + this->_deviceID, + this->_callBack->GetDriverCallBackProc(), + System::IntPtr::Zero, + Interop::Winmm::DriverCallBack::TYPE::FUNCTION + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) { + throw gcnew MidiOutException(mmResult); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed); + #endif + } + + void Device::Close() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed); + #endif + if ( + !this->_handle->IsInvalid + && !this->_handle->IsClosed + ) + { + { + auto mmResult = Interop::Winmm::Function::midiOutReset(this->_handle); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew MidiOutException(mmResult); + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] midiOutReset OK",__FUNCTION__); + #endif + } + + //バッファの開放待ち + while(this->_headerPool->IsBusy()) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] wait for unprepare headers ...",__FUNCTION__); + #endif + System::Threading::Thread::Sleep(5); + } + + this->_handle->Close(); + } + else + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] openしていない状態なので、無視します。", __FUNCTION__); + #endif + } + + if (this->_callBack != nullptr) + { + this->_callBack->OnEvent -= gcnew System::EventHandler(this, &Device::OnEventHandler); + delete this->_callBack; + } + + if (this->_headerPool != nullptr) + { + delete this->_headerPool; + } + } + + void Device::SendShort( + const System::UInt32 dwMsg + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] dwMsg {1,4:X}", __FUNCTION__, dwMsg); + #endif + if ( + this->_handle->IsInvalid + || this->_handle->IsClosed + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] openしていない状態なので、無視します。", __FUNCTION__); + #endif + return; + } + + auto mmResult = + Interop::Winmm::Function::midiOutShortMsg( + this->_handle, + dwMsg + ); + + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew MidiOutException(mmResult); + } + } + + void Device::SendLong( + array^ data, System::UInt32 useSize + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + #ifdef _DEBUG + System::Console::Write("[{0}] ", __FUNCTION__); + for (auto i = 0; i < data->Length; i++) + { + System::Console::Write("[{0,2:X}]", data[i]); + } + System::Console::WriteLine(); + #endif + + if ( + this->_handle->IsInvalid + || this->_handle->IsClosed + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] openしていない状態なので、無視します。", __FUNCTION__); + #endif + return; + } + + System::IntPtr headerPtr = this->Prepare(data, useSize); + + auto mmResult = + Interop::Winmm::Function::midiOutLongMsg( + this->_handle, + headerPtr, + InteropServices::Marshal::SizeOf(Interop::Winmm::MidiHeader::typeid) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + this->Unprepare(headerPtr); + throw gcnew MidiOutException(mmResult); + } + } + + System::IntPtr Device::Prepare(array^ data, System::UInt32 useSize) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto header = this->_headerPool->Get(); + auto buffer = this->_bufferPool->Get(); + + { + System::Array::Copy(data, buffer->GetBuffer(), static_cast(useSize)); + + auto midiHeader = header->GetBuffer(); + midiHeader->bufferLength = useSize; + midiHeader->data = buffer->GetBufferIntPtr(); + + #ifdef _DEBUG + { + System::Console::WriteLine("[{0}] midiInPrepareHeader before", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader); + } + #endif + } + + auto mmResult = + Interop::Winmm::Function::midiOutPrepareHeader( + this->_handle, + header->GetBufferIntPtr(), + InteropServices::Marshal::SizeOf(Interop::Winmm::MidiHeader::typeid) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + this->_headerPool->Release(header); + this->_bufferPool->Release(buffer); + throw gcnew MidiOutException(mmResult); + } + #ifdef _DEBUG + { + auto midiHeader = header->GetBuffer(); + System::Console::WriteLine("[{0}] midiOutPrepareHeader OK", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader); + } + #endif + + return header->GetBufferIntPtr(); + } + + void Device::Unprepare(System::IntPtr headerPtr) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto header = this->_headerPool->GetBusy(headerPtr); + + #ifdef _DEBUG + { + auto midiHeader = header->GetBuffer(); + System::Console::WriteLine("[{0}] midiOutUnprepareHeader before", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader); + } + #endif + + auto mmResult = + Interop::Winmm::Function::midiOutUnprepareHeader( + this->_handle, + headerPtr, + InteropServices::Marshal::SizeOf(Interop::Winmm::MidiHeader::typeid) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew MidiOutException(mmResult); + } + + auto bufferPtr = header->GetBuffer()->data; + this->_headerPool->Release(header); + + auto buffer = this->_bufferPool->GetBusy(bufferPtr); + this->_bufferPool->Release(buffer); + + #ifdef _DEBUG + { + auto midiHeader = header->GetBuffer(); + System::Console::WriteLine("[{0}] midiOutUnprepareHeader after", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader); + } + #endif + } + + Interop::Winmm::MidiHeader^ Device::AllocateHeader() + { + return gcnew Interop::Winmm::MidiHeader(); + } + + array^ Device::AllocateBuffer() + { + return gcnew array(256); //SMFとして最大長 + 1 + } + + System::String^ MidiOutException::Initialize() + { + auto errorMessage = System::String::Empty; + auto buf = gcnew System::Text::StringBuilder(256); + + auto r = + Interop::Winmm::Function::midiOutGetErrorText( + this->_mmResult, + buf, + buf->Capacity + ); + if (r == Interop::Winmm::MMRESULT::NOERROR) + { + errorMessage = buf->ToString(); + } + else + { + errorMessage = "不明なエラー"; + } + + return errorMessage + "[" + this->_mmResult.ToString("D") + "]"; + } + + + + + + + + + Devices::Devices() + : _outs(gcnew System::Collections::Generic::List) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + Devices::~Devices() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Devices(); + } + + Devices::!Devices() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + for each (Device^ d in this->_outs) + { + delete d; + } + this->_outs->Clear(); + } + + void Devices::AddPort(System::UInt32 deviceID) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->_outs->Add(gcnew Device(deviceID)); + } + + void Devices::Send(Core::IData^ data) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + Core::Midi::MidiData^ midiData = dynamic_cast(data); + if (midiData == nullptr) + { + return; + } + + System::UInt16 p = midiData->port; + if (p >= this->_outs->Count) + { + p = 0; + } + + Device^ d = this->_outs[p]; + + Core::Midi::ShortData^ shortData = dynamic_cast(midiData); + if (shortData != nullptr) + { + d->SendShort(shortData->shortData); + return; + } + + Core::Midi::LongData^ longData = dynamic_cast(midiData); + if (longData != nullptr) + { + d->SendLong(longData->longData, longData->longData->Length); + return; + } + + } +} +} +} +} diff --git a/Core/Momiji.Core.Midi.Out.h b/Core/Momiji.Core.Midi.Out.h new file mode 100644 index 0000000..59cb8a3 --- /dev/null +++ b/Core/Momiji.Core.Midi.Out.h @@ -0,0 +1,123 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Midi.Out.h + midi output component. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Core.Interface.h" +#include "Momiji.Core.Winmm.h" +#include "Momiji.Core.Buffer.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Midi { +namespace Out { + + public ref class Device + { + private: + initonly System::UInt32 _deviceID; + Interop::Winmm::Function::MidiOut^ _handle; + Core::Winmm::DriverCallBack^ _callBack; + Core::Buffer::BufferPool^ _headerPool; + Core::Buffer::BufferPool^>^ _bufferPool; //TODO: バッファは後で外部で持つようにする + + public: + Device(System::UInt32 deviceID); + virtual ~Device(); + protected: + !Device(); + + private: + System::IntPtr Prepare(array^ data, System::UInt32 useSize); + void Unprepare(System::IntPtr headerPtr); + + Interop::Winmm::MidiHeader^ AllocateHeader(); + array^ AllocateBuffer(); + + public: + static System::UInt32 GetNumDevices(); + static Interop::Winmm::MidiOutCapabilities^ GetCapabilities(System::UInt32 uDeviceID); + Interop::Winmm::MidiOutCapabilities^ GetCapabilities(); + + private: + void Open(); + void Close(); + + public: + void SendShort(System::UInt32 dwMsg); + void SendLong(array^ data, System::UInt32 useSize); + + public: + //TODO: このイベントは使い道が無い。。。 + event System::EventHandler^ OnOpen; + event System::EventHandler^ OnClose; + + private: + void OnEventHandler(System::Object^ sender, Interop::Winmm::DriverCallBack::DriverEventArgs^ args); + void DoOpen(System::IntPtr dwParam1, System::IntPtr dwParam2); + void DoClose(System::IntPtr dwParam1, System::IntPtr dwParam2); + void DoDone(System::IntPtr dwParam1, System::IntPtr dwParam2); + }; + + public ref class MidiOutException + : public System::Exception + { + private: + initonly Interop::Winmm::MMRESULT _mmResult; + System::String^ Initialize(); + + public: + MidiOutException(Interop::Winmm::MMRESULT v): _mmResult(v), System::Exception(Initialize()){}; + MidiOutException(System::String^ v): System::Exception(v){}; + virtual ~MidiOutException(void){}; + + property Interop::Winmm::MMRESULT mmResult + { + Interop::Winmm::MMRESULT get(void) {return this->_mmResult;}; + } + }; + + public ref class Devices + : public Core::IOut + { + private: + System::Collections::Generic::List^ _outs; + + public: + Devices(); + virtual ~Devices(); + + void AddPort(System::UInt32 deviceID); + protected: + !Devices(); + + public: + virtual void Send(Core::IData^ data); + }; + +} +} +} +} diff --git a/Core/Momiji.Core.SafeBuffer.h b/Core/Momiji.Core.SafeBuffer.h new file mode 100644 index 0000000..2ea5cdf --- /dev/null +++ b/Core/Momiji.Core.SafeBuffer.h @@ -0,0 +1,57 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.SafeBuffer.h + safe buffer. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { + + //TODO ぜんぜんできてない + + public ref class SafeBuffer: + public InteropServices::SafeBuffer + { + public: + SafeBuffer(System::UInt32 size): + InteropServices::SafeBuffer(true) + { + this->Initialize(size); + }; + + protected: + [ConstrainedExecution::ReliabilityContract(ConstrainedExecution::Consistency::WillNotCorruptState, ConstrainedExecution::Cer::MayFail)] + virtual System::Boolean ReleaseHandle() override + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + return true; + }; + }; + +} +} diff --git a/Core/Momiji.Core.Timer.MMTimer.cpp b/Core/Momiji.Core.Timer.MMTimer.cpp new file mode 100644 index 0000000..861cd43 --- /dev/null +++ b/Core/Momiji.Core.Timer.MMTimer.cpp @@ -0,0 +1,230 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Timer.MMTimer.cpp + timer component. multi media timer version. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Interop.Winmm.h" +#include "Momiji.Core.Timer.MMTimer.h" + +namespace Momiji { +namespace Core { +namespace Timer { + + void MMTimer::OnEventHandler( + System::Object^ sender, + Interop::Winmm::TimerCallBack::TimerEventArgs^ args + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] start", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + + this->DoInterval(args->dw1, args->dw2); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] end", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + }; + + void MMTimer::DoInterval(System::IntPtr dw1, System::IntPtr dw2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + System::Double deltaTime = + (1000.0 * safe_cast(this->_stopWatch->ElapsedTicks)) / safe_cast(this->_stopWatch->Frequency); + this->_stopWatch->Restart(); + this->OnInterval(deltaTime); + + /* + System::UInt32 nowTime = Interop::Winmm::Function::timeGetTime(); + System::UInt32 deltaTime = (nowTime - this->_beforeTime); + + if (this->_beforeTime > nowTime) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] オーバーフロー分を調整",__FUNCTION__); + #endif + deltaTime = nowTime + (System::UInt32::MaxValue - this->_beforeTime); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] deltaTime {1}", __FUNCTION__, deltaTime); + #endif + + if (deltaTime == 0) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] 時差が0なのでスキップ",__FUNCTION__); + #endif + // NOP + } + else + { + this->OnInterval(nowTime - this->_beforeTime); + } + + this->_beforeTime = nowTime; + */ + } + + Interop::Winmm::TimeCapabilities^ MMTimer::getCapabilities() + { + auto caps = gcnew Interop::Winmm::TimeCapabilities(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] caps size {1}",__FUNCTION__, InteropServices::Marshal::SizeOf(caps)); + #endif + auto mmResult = + Interop::Winmm::Function::timeGetDevCaps( + caps, + InteropServices::Marshal::SizeOf(caps) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew MMTimerException(mmResult); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] min {1}, max {2}",__FUNCTION__, caps->periodMin, caps->periodMax); + #endif + + return caps; + } + + MMTimer::MMTimer(): _timerID(0) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + MMTimer::~MMTimer() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!MMTimer(); + } + + MMTimer::!MMTimer() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->Stop(); + } + + void MMTimer::Start( + System::UInt32 period + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto caps = getCapabilities(); + if (period < caps->periodMin) period = caps->periodMin; + if (period > caps->periodMax) period = caps->periodMax; + /* + { + Winmm::MMRESULT mmResult = Winmm::Function::timeBeginPeriod(period); + if (mmResult != Winmm::MMRESULT::NOERROR) { + throw gcnew Exception(mmResult); + } + } + */ + + { + //イベントは同期で動かす + //非同期にすると、 + //・タイマー間隔が短い場合、順序性が保証できない + //・コンテキストスイッチが重くなる + this->_callBack = gcnew Core::Winmm::TimerCallBack(false); + this->_callBack->OnEvent += gcnew System::EventHandler(this, &MMTimer::OnEventHandler); + + //this->_beforeTime = Interop::Winmm::Function::timeGetTime(); + this->_stopWatch = System::Diagnostics::Stopwatch::StartNew(); + + this->_timerID = + Interop::Winmm::Function::timeSetEvent( + period, + caps->periodMin, + this->_callBack->GetTimerCallBackProc(), + System::IntPtr::Zero, + ( + Interop::Winmm::TimerCallBack::TYPE::PERIODIC + // Interop::Winmm::TimerCallBack::TYPE::ONESHOT + | Interop::Winmm::TimerCallBack::TYPE::CALLBACK_FUNCTION + | Interop::Winmm::TimerCallBack::TYPE::KILL_SYNCHRONOUS + ) + ); + if (this->_timerID == 0) + { + this->Stop(); + } + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] timerID {1:X}",__FUNCTION__, this->_timerID); + #endif + } + + void MMTimer::Stop() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] timerID {1:X}",__FUNCTION__, this->_timerID); + #endif + + if (this->_timerID != 0) + { + auto mmResult = Interop::Winmm::Function::timeKillEvent(this->_timerID); + if ( + (mmResult != Interop::Winmm::MMRESULT::NOERROR) + && (mmResult != Interop::Winmm::MMRESULT::TIMERR_NOCANDO) //タイマが起動されていない状態も無視する + ) + { + throw gcnew MMTimerException(mmResult); + } + this->_timerID = 0; + } + else + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] startしていない状態なので、無視します。",__FUNCTION__); + #endif + } + + if (this->_callBack != nullptr) + { + delete this->_callBack; + } + } + + System::String^ MMTimerException::Initialize() + { + return "エラーコード[" + this->_mmResult.ToString("D") + "]"; + } + +} +} +} diff --git a/Core/Momiji.Core.Timer.MMTimer.h b/Core/Momiji.Core.Timer.MMTimer.h new file mode 100644 index 0000000..56383c6 --- /dev/null +++ b/Core/Momiji.Core.Timer.MMTimer.h @@ -0,0 +1,83 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Timer.MMTimer.h + timer component. multi media timer version. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Core.Interface.h" +#include "Momiji.Core.Winmm.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Timer { + + public ref class MMTimer + : public Core::ITimer + { + private: + System::UInt32 _timerID; + Core::Winmm::TimerCallBack^ _callBack; + + System::Diagnostics::Stopwatch^ _stopWatch; + public: + MMTimer(); + virtual ~MMTimer(); + protected: + !MMTimer(); + + public: + static Interop::Winmm::TimeCapabilities^ getCapabilities(); + + public: + virtual void Start(System::UInt32 period); + virtual void Stop(); + + public: + virtual event Core::ITimer::Event^ OnInterval; + + private: + void OnEventHandler(System::Object^ sender, Interop::Winmm::TimerCallBack::TimerEventArgs^ args); + void DoInterval(System::IntPtr dw1, System::IntPtr dw2); + }; + + public ref class MMTimerException: System::Exception + { + private: + initonly Interop::Winmm::MMRESULT _mmResult; + System::String^ Initialize(); + + public: + MMTimerException(Interop::Winmm::MMRESULT v): _mmResult(v), System::Exception(Initialize()){}; + MMTimerException(System::String^ v): System::Exception(v){}; + virtual ~MMTimerException(){}; + + property Interop::Winmm::MMRESULT mmResult + { + Interop::Winmm::MMRESULT get() {return this->_mmResult;}; + } + }; + +} +} +} diff --git a/Core/Momiji.Core.Vst.Buffer.cpp b/Core/Momiji.Core.Vst.Buffer.cpp new file mode 100644 index 0000000..bca6a3a --- /dev/null +++ b/Core/Momiji.Core.Vst.Buffer.cpp @@ -0,0 +1,118 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Vst.Buffer.cpp + buffer for VST. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Core.Vst.Buffer.h" + +namespace Momiji{ +namespace Core { +namespace Vst { +namespace Buffer { + + generic + VstBuffer::VstBuffer( + System::Int32 channel, + System::Int32 size + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->Alloc(channel, size); + } + + generic + VstBuffer::~VstBuffer() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!VstBuffer(); + } + + generic + VstBuffer::!VstBuffer() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->Free(); + } + + generic + void VstBuffer::Alloc( + System::Int32 channel, + System::Int32 size + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_buffer = gcnew array^>(channel); + this->_channelBufferHandles = gcnew array(channel); + + auto channelBufferPtrs = gcnew array(channel); + this->_bufferHandle = InteropServices::GCHandle::Alloc(channelBufferPtrs, InteropServices::GCHandleType::Pinned); + + for (auto idx = 0; idx < channel; idx++) + { + this->_buffer[idx] = gcnew array(size); + this->_channelBufferHandles[idx] = + InteropServices::GCHandle::Alloc(this->_buffer[idx], InteropServices::GCHandleType::Pinned); + channelBufferPtrs[idx] = this->_channelBufferHandles[idx].AddrOfPinnedObject(); + } + } + + generic + void VstBuffer::Free() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + for (auto idx = 0; idx < this->_channelBufferHandles->Length; idx++) + { + this->_channelBufferHandles[idx].Free(); + } + this->_bufferHandle.Free(); + } + + generic + void VstBuffer::Reset(array^>^ data) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + for (auto idx = 0; idx < data->Length; idx++) + { + System::Array::Copy(data[idx], this->_buffer[idx], data[idx]->Length); + } + } + +} +} +} +} diff --git a/Core/Momiji.Core.Vst.Buffer.h b/Core/Momiji.Core.Vst.Buffer.h new file mode 100644 index 0000000..c5be202 --- /dev/null +++ b/Core/Momiji.Core.Vst.Buffer.h @@ -0,0 +1,76 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Vst.Buffer.h + buffer for VST. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Vst { +namespace Buffer { + + /// + /// + /// + /// + generic + public ref class VstBuffer { + private: + array^>^ _buffer; + array^ _channelBufferHandles; + InteropServices::GCHandle _bufferHandle; + + public: + VstBuffer(System::Int32 channel, System::Int32 size); + virtual ~VstBuffer(); + + protected: + !VstBuffer(); + + private: + void Alloc(System::Int32 channel, System::Int32 size); + void Free(); + + public: + System::IntPtr AddrOfPinnedObject() + { + return _bufferHandle.AddrOfPinnedObject(); + } + + System::Int32 Length() + { + return this->_buffer[0]->Length; + } + + array^>^ GetBuffer() + { + return this->_buffer; + } + + void Reset(array^>^ data); + }; +} +} +} +} diff --git a/Core/Momiji.Core.Vst.Host.Master.cpp b/Core/Momiji.Core.Vst.Host.Master.cpp new file mode 100644 index 0000000..5b5e4e5 --- /dev/null +++ b/Core/Momiji.Core.Vst.Host.Master.cpp @@ -0,0 +1,951 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Vst.Host.h + vst host component. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Core.Vst.Host.Master.h" + +namespace Momiji{ +namespace Core { +namespace Vst { +namespace Host { + + Master::AudioMasterCallBack::AudioMasterCallBack() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_callBack = InteropServices::GCHandle::Alloc(gcnew Interop::Vst::AudioMasterCallBack::Delegate(this, &AudioMasterCallBack::AudioMasterCallBackProc)); + } + + Master::AudioMasterCallBack::~AudioMasterCallBack() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!AudioMasterCallBack(); + } + + Master::AudioMasterCallBack::!AudioMasterCallBack() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + if (this->_callBack.IsAllocated) + { + this->_callBack.Free(); + } + } + + Interop::Vst::AudioMasterCallBack::Delegate^ Master::AudioMasterCallBack::GetAudioMasterCallBackProc() + { + return safe_cast(this->_callBack.Target); + } + + System::IntPtr Master::AudioMasterCallBack::AudioMasterCallBackProc( + System::IntPtr/*AEffect^*/ effect, + Interop::Vst::AudioMasterOpcodes opcode, + System::Int32 index, + System::IntPtr value, + System::IntPtr ptr, + System::Single opt + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2:f}][{3,8:X}][{4,8:X}][{5,8:X}][{6}]", __FUNCTION__, effect, opcode, index, value, ptr, opt); + #endif + auto params = gcnew Interop::Vst::AudioMasterCallBack::AudioMasterEventArgs(); + try + { + params->effect = effect; + params->opcode = opcode; + params->index = index; + params->value = value; + params->ptr = ptr; + params->opt = opt; + + this->DoEvent(params); + } + catch(System::Exception^ e) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] コールバック中のエラー[{1}]", __FUNCTION__, e->ToString()); + #endif + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] OUT", __FUNCTION__); + #endif + + return params->returnValue; + } + + void Master::AudioMasterCallBack::DoEvent( + System::Object^ stateInfo + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] start", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + + auto params = safe_cast(stateInfo); + try + { + this->OnEvent(this, params); + } + catch(System::Exception^ e) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] コールバック中のエラー[{1}]", __FUNCTION__, e->ToString()); + #endif + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] end", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + } + + void Master::OnEventHandler( + System::Object^ sender, + Interop::Vst::AudioMasterCallBack::AudioMasterEventArgs^ args + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] start", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + + switch(args->opcode) + { + case Interop::Vst::AudioMasterOpcodes::audioMasterVersion: + { + args->returnValue = System::IntPtr(2400); + break; + } + case Interop::Vst::AudioMasterOpcodes::audioMasterGetTime: + { + args->returnValue = this->GetTimeInfo(0); + break; + } + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] end", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + } + + + Master::Master( + System::String^ library + ): _library(library) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] library {1}",__FUNCTION__, this->_library); + #endif + + this->_timeInfo = gcnew Interop::Vst::VstTimeInfo(); + this->_timeInfoHandle = InteropServices::GCHandle::Alloc(this->_timeInfo, InteropServices::GCHandleType::Pinned); + + this->_timeInfo->samplePos = 0.0; + this->_timeInfo->sampleRate = 0; + this->_timeInfo->nanoSeconds = 0.0; + this->_timeInfo->ppqPos = 0.0; + this->_timeInfo->tempo = 240.0; + this->_timeInfo->barStartPos = 0.0; + this->_timeInfo->cycleStartPos = 0.0; + this->_timeInfo->cycleEndPos = 0.0; + this->_timeInfo->timeSigNumerator = 4; + this->_timeInfo->timeSigDenominator = 4; + this->_timeInfo->smpteOffset = 0; + this->_timeInfo->smpteFrameRate = 1; + this->_timeInfo->samplesToNextClock = 0; + this->_timeInfo->flags = Interop::Vst::VstTimeInfo::VstTimeInfoFlags::kVstTempoValid; + + this->Open(); + } + + Master::~Master() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!Master(); + } + + Master::!Master() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->Suspend(); + this->Close(); + + if (this->_timeInfoHandle.IsAllocated) + { + this->_timeInfoHandle.Free(); + delete this->_timeInfo; + } + } + + void Master::Open() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_callBack = gcnew AudioMasterCallBack(); + this->_callBack->OnEvent += gcnew System::EventHandler(this, &Master::OnEventHandler); + + this->_dll = Interop::Kernel32::Function::LoadLibrary(this->_library); + if (this->_dll->IsInvalid) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + System::Console::WriteLine("[{0}] error {1}",__FUNCTION__, error); + InteropServices::Marshal::ThrowExceptionForHR(error); + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_dll->IsInvalid, this->_dll->IsClosed); + #endif + + auto proc = Interop::Kernel32::Function::GetProcAddress(this->_dll, "VSTPluginMain"); + if (proc == System::IntPtr::Zero) + { + proc = Interop::Kernel32::Function::GetProcAddress(this->_dll, "main"); + } + + if (proc == System::IntPtr::Zero) + { + auto error = InteropServices::Marshal::GetHRForLastWin32Error(); + System::Console::WriteLine("[{0}] error {1}",__FUNCTION__, error); + InteropServices::Marshal::ThrowExceptionForHR(error); + } + + auto vstPluginMain = + safe_cast(InteropServices::Marshal::GetDelegateForFunctionPointer(proc, Interop::Vst::VSTPluginMain::typeid)); + + this->_aeffectPtr = vstPluginMain(this->_callBack->GetAudioMasterCallBackProc()); + this->_aeffect = + safe_cast(InteropServices::Marshal::PtrToStructure(this->_aeffectPtr, Interop::Vst::AEffect::typeid)); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] magic:{1} ",__FUNCTION__, this->_aeffect->magic); + System::Console::WriteLine("[{0}] dispatcher:{1} ",__FUNCTION__, this->_aeffect->dispatcher); + System::Console::WriteLine("[{0}] processDeprecated:{1} ",__FUNCTION__, this->_aeffect->processDeprecated); + System::Console::WriteLine("[{0}] setParameter:{1} ",__FUNCTION__, this->_aeffect->setParameter); + System::Console::WriteLine("[{0}] getParameter:{1} ",__FUNCTION__, this->_aeffect->getParameter); + + System::Console::WriteLine("[{0}] numPrograms:{1} ",__FUNCTION__, this->_aeffect->numPrograms); + System::Console::WriteLine("[{0}] numParams:{1} ",__FUNCTION__, this->_aeffect->numParams); + System::Console::WriteLine("[{0}] numInputs:{1} ",__FUNCTION__, this->_aeffect->numInputs); + System::Console::WriteLine("[{0}] numOutputs:{1} ",__FUNCTION__, this->_aeffect->numOutputs); + System::Console::WriteLine("[{0}] flags:{1:f} ",__FUNCTION__, this->_aeffect->flags); + + System::Console::WriteLine("[{0}] resvd1:{1} ",__FUNCTION__, this->_aeffect->resvd1); + System::Console::WriteLine("[{0}] resvd2:{1} ",__FUNCTION__, this->_aeffect->resvd2); + + System::Console::WriteLine("[{0}] initialDelay:{1} ",__FUNCTION__, this->_aeffect->initialDelay); + + System::Console::WriteLine("[{0}] realQualitiesDeprecated:{1} ",__FUNCTION__, this->_aeffect->realQualitiesDeprecated); + System::Console::WriteLine("[{0}] offQualitiesDeprecated:{1} ",__FUNCTION__, this->_aeffect->offQualitiesDeprecated); + System::Console::WriteLine("[{0}] ioRatioDeprecated:{1} ",__FUNCTION__, this->_aeffect->ioRatioDeprecated); + System::Console::WriteLine("[{0}] object:{1} ",__FUNCTION__, this->_aeffect->object); + System::Console::WriteLine("[{0}] user:{1} ",__FUNCTION__, this->_aeffect->user); + + System::Console::WriteLine("[{0}] uniqueID:{1} ",__FUNCTION__, this->_aeffect->uniqueID); + System::Console::WriteLine("[{0}] version:{1} ",__FUNCTION__, this->_aeffect->version); + + System::Console::WriteLine("[{0}] processReplacing:{1} ",__FUNCTION__, this->_aeffect->processReplacing); + System::Console::WriteLine("[{0}] processDoubleReplacing:{1} ",__FUNCTION__, this->_aeffect->processDoubleReplacing); + System::Console::WriteLine("[{0}] future:{1} ",__FUNCTION__, this->_aeffect->future); + #endif + + if (this->_aeffect->dispatcher != System::IntPtr::Zero) + { + this->_dispatcher = + safe_cast(InteropServices::Marshal::GetDelegateForFunctionPointer(this->_aeffect->dispatcher, Interop::Vst::AEffectDispatcherProc::typeid)); + } + + if (this->_aeffect->setParameter != System::IntPtr::Zero) + { + this->_setParameter = + safe_cast(InteropServices::Marshal::GetDelegateForFunctionPointer(this->_aeffect->setParameter, Interop::Vst::AEffectSetParameterProc::typeid)); + } + + if (this->_aeffect->getParameter != System::IntPtr::Zero) + { + this->_getParameter = + safe_cast(InteropServices::Marshal::GetDelegateForFunctionPointer(this->_aeffect->getParameter, Interop::Vst::AEffectGetParameterProc::typeid)); + } + + if (this->_aeffect->processReplacing != System::IntPtr::Zero) + { + this->_processReplacing = + safe_cast(InteropServices::Marshal::GetDelegateForFunctionPointer(this->_aeffect->processReplacing, Interop::Vst::AEffectProcessProc::typeid)); + } + + if (this->_aeffect->processDoubleReplacing != System::IntPtr::Zero) + { + this->_processDoubleReplacing = + safe_cast(InteropServices::Marshal::GetDelegateForFunctionPointer(this->_aeffect->processDoubleReplacing, Interop::Vst::AEffectProcessDoubleProc::typeid)); + } + + {//effOpenに戻り値の定義は無い + auto result = + this->Dispatcher( + Interop::Vst::AEffectOpcodes::effOpen, + 0, + System::IntPtr::Zero, + System::IntPtr::Zero, + 0 + ); + } + + } + + void Master::Close() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_dll->IsInvalid, this->_dll->IsClosed); + #endif + if ( + !this->_dll->IsInvalid + && !this->_dll->IsClosed + ) + { + if (this->_aeffect != nullptr) + {//effCloseに戻り値の定義は無い + auto result = + this->Dispatcher( + Interop::Vst::AEffectOpcodes::effClose, + 0, + System::IntPtr::Zero, + System::IntPtr::Zero, + 0 + ); + } + + this->_dll->Close(); + } + else + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] openしていない状態なので、無視します。", __FUNCTION__); + #endif + } + + if (this->_callBack != nullptr) + { + this->_callBack->OnEvent -= gcnew System::EventHandler(this, &Master::OnEventHandler); + delete this->_callBack; + } + + } + + System::IntPtr Master::Dispatcher( + Interop::Vst::AEffectOpcodes opcode, + System::Int32 index, + System::IntPtr value, + System::IntPtr ptr, + System::Single opt + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_dll->IsInvalid, this->_dll->IsClosed); + #endif + + if (this->_dispatcher == nullptr) + { + throw gcnew VstException("dispatcherが無い"); + } + + auto result = + this->_dispatcher( + this->_aeffectPtr, + opcode, + index, + value, + ptr, + opt + ); + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] {1} result:{2}",__FUNCTION__, opcode, result); + #endif + + if (opcode == Interop::Vst::AEffectOpcodes::effClose) + { + this->_aeffectPtr = System::IntPtr::Zero; + + this->_aeffect = nullptr; + this->_dispatcher = nullptr; + this->_processReplacing = nullptr; + this->_processDoubleReplacing = nullptr; + this->_setParameter = nullptr; + this->_getParameter = nullptr; + } + + return result; + } + + void Master::Process( + Buffer::VstBuffer^ inputs, + Buffer::VstBuffer^ outputs, + System::Int32 sampleFrames + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2} sampleFrames:{3}",__FUNCTION__, this->_dll->IsInvalid, this->_dll->IsClosed, sampleFrames); + #endif + + if (this->_processReplacing == nullptr) + { + throw gcnew VstException("processReplacingが無い"); + } + + this->_processReplacing( + this->_aeffectPtr, + inputs->AddrOfPinnedObject(), + outputs->AddrOfPinnedObject(), + sampleFrames + ); + } + + void Master::Process( + Buffer::VstBuffer^ inputs, + Buffer::VstBuffer^ outputs, + System::Int32 sampleFrames + ) + { + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_dll->IsInvalid, this->_dll->IsClosed); + #endif + + if (this->_processDoubleReplacing == nullptr) + { + throw gcnew VstException("processDoubleReplacingが無い"); + } + + this->_processDoubleReplacing( + this->_aeffectPtr, + inputs->AddrOfPinnedObject(), + outputs->AddrOfPinnedObject(), + sampleFrames + ); + } + + void Master::SetParameter( + System::Int32 index, + System::Single parameter + ) + { + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_dll->IsInvalid, this->_dll->IsClosed); + #endif + + if (this->_setParameter == nullptr) + { + throw gcnew VstException("setParameterが無い"); + } + + this->_setParameter( + this->_aeffectPtr, + index, + parameter + ); + } + + System::Single Master::GetParameter( + System::Int32 index + ) + { + #ifdef _DEBUG + // System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_dll->IsInvalid, this->_dll->IsClosed); + #endif + + if (this->_getParameter == nullptr) + { + throw gcnew VstException("getParameterが無い"); + } + + return + this->_getParameter( + this->_aeffectPtr, + index + ); + } + + bool Master::String2Parameter(System::Int32 index, System::String^ value) + { + auto ptr = InteropServices::Marshal::StringToHGlobalAnsi(value); + try + { + return + (this->Dispatcher( + Interop::Vst::AEffectOpcodes::effString2Parameter, + index, + System::IntPtr::Zero, + ptr, + 0 + ) != System::IntPtr::Zero); + } + finally + { + InteropServices::Marshal::FreeHGlobal(ptr); + } + } + + + + + + + + + System::String^ Master::GetString(Interop::Vst::AEffectOpcodes opcode, System::Int32 index, System::Int32 length) + { + //文字長制限に従っていないプラグインがあるので、バッファを多めに取っておく + auto ptr = InteropServices::Marshal::AllocHGlobal(length+1); + InteropServices::Marshal::WriteByte(ptr, 0, 0); //先頭をnullクリア + try + { + if (this->Dispatcher( + opcode, + index, + System::IntPtr::Zero, + ptr, + 0 + ) == System::IntPtr::Zero) + {//失敗しているかどうかの判断は、1バイト目がゼロのままだったら、ということにする。 + if (InteropServices::Marshal::ReadByte(ptr, 0) == 0) + { + return "(failed)"; + } + } + InteropServices::Marshal::WriteByte(ptr, length, 0); //念のため終端を設定 + return InteropServices::Marshal::PtrToStringAnsi(ptr); + } + finally + { + InteropServices::Marshal::FreeHGlobal(ptr); + } + } + + //State Transitions + void Master::Suspend() + { + this->Dispatcher( + Interop::Vst::AEffectOpcodes::effMainsChanged, + 0, + System::IntPtr(0), + System::IntPtr::Zero, + 0 + ); + } + + void Master::Resume() + { + this->Dispatcher( + Interop::Vst::AEffectOpcodes::effMainsChanged, + 0, + System::IntPtr(1), + System::IntPtr::Zero, + 0 + ); + } + + //Processing + void Master::SetSampleRate(System::Single sampleRate) + { + if (this->_timeInfo->sampleRate == sampleRate) + { + //変わっていないので何もしない + return; + } + + this->_timeInfo->sampleRate = sampleRate; + + this->Dispatcher( + Interop::Vst::AEffectOpcodes::effSetSampleRate, + 0, + System::IntPtr::Zero, + System::IntPtr::Zero, + sampleRate + ); + } + + void Master::SetBlockSize(System::Int32 blockSize) + { + this->Dispatcher( + Interop::Vst::AEffectOpcodes::effSetBlockSize, + 0, + System::IntPtr(blockSize), + System::IntPtr::Zero, + 0 + ); + } + + bool Master::CanParameterBeAutomated (System::Int32 index) + { + return + (this->Dispatcher( + Interop::Vst::AEffectOpcodes::effCanBeAutomated, + index, + System::IntPtr::Zero, + System::IntPtr::Zero, + 0 + ) != System::IntPtr::Zero); + } + + Interop::Vst::VstParameterProperties^ Master::GetParameterProperties(System::Int32 index) + { + auto ptr = InteropServices::Marshal::AllocHGlobal(InteropServices::Marshal::SizeOf(Interop::Vst::VstParameterProperties::typeid)); + try + { + if (this->Dispatcher( + Interop::Vst::AEffectOpcodes::effGetParameterProperties, + index, + System::IntPtr::Zero, + ptr, + 0 + ) == System::IntPtr::Zero) + { + throw gcnew VstException("effGetParameterProperties失敗"); + } + + return safe_cast(InteropServices::Marshal::PtrToStructure(ptr, Interop::Vst::VstParameterProperties::typeid)); + } + finally + { + InteropServices::Marshal::FreeHGlobal(ptr); + } + } + + System::Int32 Master::GetProgram() + { + auto result = + this->Dispatcher( + Interop::Vst::AEffectOpcodes::effGetProgram, + 0, + System::IntPtr::Zero, + System::IntPtr::Zero, + 0 + ); + + return result.ToInt32(); + } + + void Master::SetProgram(System::Int32 program) + { + if (this->Dispatcher( + Interop::Vst::AEffectOpcodes::effSetProgram, + 0, + System::IntPtr(program), + System::IntPtr::Zero, + 0 + ) == System::IntPtr::Zero) + { + throw gcnew VstException("effSetProgram失敗"); + } + } + + void Master::SetProgramName(System::String^ name) + { + auto ptr = InteropServices::Marshal::StringToHGlobalAnsi(name); + try + { + if (this->Dispatcher( + Interop::Vst::AEffectOpcodes::effSetProgramName, + 0, + System::IntPtr::Zero, + ptr, + 0 + ) == System::IntPtr::Zero) + { + throw gcnew VstException("effSetProgramName失敗"); + } + } + finally + { + InteropServices::Marshal::FreeHGlobal(ptr); + } + } + + System::String^ Master::GetProgramName() + { + return + this->GetString( + Interop::Vst::AEffectOpcodes::effGetProgramName, + 0, + 255//Interop::Vst::VstStringConstants::kVstMaxProgNameLen + ); + } + + System::String^ Master::GetParameterLabel(System::Int32 index) + { + return + this->GetString( + Interop::Vst::AEffectOpcodes::effGetParamLabel, + index, + 255//Interop::Vst::VstStringConstants::kVstMaxParamStrLen + ); + } + + System::String^ Master::GetParameterDisplay(System::Int32 index) + { + return + this->GetString( + Interop::Vst::AEffectOpcodes::effGetParamDisplay, + index, + 255//Interop::Vst::VstStringConstants::kVstMaxParamStrLen + ); + } + + System::String^ Master::GetParameterName(System::Int32 index) + { + return + this->GetString( + Interop::Vst::AEffectOpcodes::effGetParamName, + index, + 255//Interop::Vst::VstStringConstants::kVstMaxParamStrLen + ); + } + + System::String^ Master::GetProgramNameIndexed(System::Int32 index) + { + return + this->GetString( + Interop::Vst::AEffectOpcodes::effGetProgramNameIndexed, + index, + 255//Interop::Vst::VstStringConstants::kVstMaxProgNameLen + ); + } + + bool Master::BeginSetProgram () + { + return + (this->Dispatcher( + Interop::Vst::AEffectOpcodes::effBeginSetProgram, + 0, + System::IntPtr::Zero, + System::IntPtr::Zero, + 0 + ) != System::IntPtr::Zero); + } + + bool Master::EndSetProgram () + { + return + (this->Dispatcher( + Interop::Vst::AEffectOpcodes::effEndSetProgram, + 0, + System::IntPtr::Zero, + System::IntPtr::Zero, + 0 + ) != System::IntPtr::Zero); + } + + + Interop::Vst::VstPinProperties^ Master::GetInputProperties(System::Int32 index) + { + auto ptr = InteropServices::Marshal::AllocHGlobal(InteropServices::Marshal::SizeOf(Interop::Vst::VstPinProperties::typeid)); + try + { + if (this->Dispatcher( + Interop::Vst::AEffectOpcodes::effGetInputProperties, + index, + System::IntPtr::Zero, + ptr, + 0 + ) == System::IntPtr::Zero) + { + throw gcnew VstException("effGetInputProperties失敗"); + } + + return safe_cast(InteropServices::Marshal::PtrToStructure(ptr, Interop::Vst::VstPinProperties::typeid)); + } + finally + { + InteropServices::Marshal::FreeHGlobal(ptr); + } + } + + Interop::Vst::VstPinProperties^ Master::GetOutputProperties(System::Int32 index) + { + auto ptr = InteropServices::Marshal::AllocHGlobal(InteropServices::Marshal::SizeOf(Interop::Vst::VstPinProperties::typeid)); + try + { + if (this->Dispatcher( + Interop::Vst::AEffectOpcodes::effGetOutputProperties, + index, + System::IntPtr::Zero, + ptr, + 0 + ) == System::IntPtr::Zero) + { + throw gcnew VstException("effGetOutputProperties失敗"); + } + + return safe_cast(InteropServices::Marshal::PtrToStructure(ptr, Interop::Vst::VstPinProperties::typeid)); + } + finally + { + InteropServices::Marshal::FreeHGlobal(ptr); + } + } + + + System::String^ Master::GetEffectName() + { + return + this->GetString( + Interop::Vst::AEffectOpcodes::effGetEffectName, + 0, + 255//Interop::Vst::VstStringConstants::kVstMaxEffectNameLen + ); + } + + System::String^ Master::GetVendorString() + { + return + this->GetString( + Interop::Vst::AEffectOpcodes::effGetVendorString, + 0, + 255//Interop::Vst::VstStringConstants::kVstMaxVendorStrLen + ); + } + + System::String^ Master::GetProductString() + { + return + this->GetString( + Interop::Vst::AEffectOpcodes::effGetProductString, + 0, + 255//Interop::Vst::VstStringConstants::kVstMaxProductStrLen + ); + } + + System::Int32 Master::ProcessEvents(array^ events) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] start",__FUNCTION__); + #endif + + auto e = gcnew Interop::Vst::VstEvents(); + e->numEvents = events->Length; + + //VstEventの転機先ポインタを保持する + auto eventPtrs = gcnew array(e->numEvents); + + auto ptr = + InteropServices::Marshal::AllocHGlobal( + InteropServices::Marshal::SizeOf(Interop::Vst::VstEvents::typeid) + + (InteropServices::Marshal::SizeOf(System::IntPtr::typeid) * e->numEvents) + ); + + try + { + auto cursor = ptr; + + InteropServices::Marshal::StructureToPtr(e, cursor, false); + cursor += InteropServices::Marshal::SizeOf(Interop::Vst::VstEvents::typeid); + + for (int idx = 0; idx < e->numEvents; idx++) + { + auto ev = events[idx]; + ev.byteSize = + InteropServices::Marshal::SizeOf(Interop::Vst::VstEvents::typeid) + -(InteropServices::Marshal::SizeOf(System::Int32::typeid) + InteropServices::Marshal::SizeOf(System::Int32::typeid)) //VSTの仕様だとこの分はサイズから除くことになっている + ; + + auto eventPtr = InteropServices::Marshal::AllocHGlobal(InteropServices::Marshal::SizeOf(Interop::Vst::VstEvent::typeid)); + eventPtrs[idx] = eventPtr; + + InteropServices::Marshal::StructureToPtr(ev, eventPtr, false); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] {1}",__FUNCTION__, ev.ToString()); + #endif + } + InteropServices::Marshal::Copy(eventPtrs, 0, cursor, e->numEvents); + + auto result = + this->Dispatcher( + Interop::Vst::AEffectOpcodes::effProcessEvents, + 0, + System::IntPtr::Zero, + ptr, + 0 + ); + + return result.ToInt32(); + } + finally + { + for (int idx = 0; idx < e->numEvents; idx++) + { + auto eventPtr = eventPtrs[idx]; + if (eventPtr == System::IntPtr::Zero) + { + continue; + } + InteropServices::Marshal::FreeHGlobal(eventPtr); + } + InteropServices::Marshal::FreeHGlobal(ptr); + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] end",__FUNCTION__); + #endif + } + + System::Int32 Master::StartProcess() + { + auto result = + this->Dispatcher( + Interop::Vst::AEffectOpcodes::effStartProcess, + 0, + System::IntPtr::Zero, + System::IntPtr::Zero, + 0 + ); + return result.ToInt32(); + } + + System::Int32 Master::StopProcess() + { + auto result = + this->Dispatcher( + Interop::Vst::AEffectOpcodes::effStopProcess, + 0, + System::IntPtr::Zero, + System::IntPtr::Zero, + 0 + ); + return result.ToInt32(); + } + + + System::IntPtr Master::GetTimeInfo(System::Int32 filter) + { + return this->_timeInfoHandle.AddrOfPinnedObject(); + } +} +} +} +} diff --git a/Core/Momiji.Core.Vst.Host.Master.h b/Core/Momiji.Core.Vst.Host.Master.h new file mode 100644 index 0000000..b258a28 --- /dev/null +++ b/Core/Momiji.Core.Vst.Host.Master.h @@ -0,0 +1,260 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Vst.Host.h + vst host component. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +#include "Momiji.Interop.Kernel32.h" +#include "Momiji.Interop.Vst.h" +#include "Momiji.Core.Vst.Buffer.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Vst { +namespace Host { + + public ref class Master + { + private: + ref class AudioMasterCallBack + { + private: + InteropServices::GCHandle _callBack; + + public: + AudioMasterCallBack(); + virtual ~AudioMasterCallBack(); + protected: + !AudioMasterCallBack(); + + private: + System::IntPtr AudioMasterCallBackProc( + System::IntPtr/*AEffect^*/ effect, + Interop::Vst::AudioMasterOpcodes opcode, + System::Int32 index, + System::IntPtr value, + System::IntPtr ptr, + System::Single opt + ); + void DoEvent(System::Object^ args); + + public: + Interop::Vst::AudioMasterCallBack::Delegate^ GetAudioMasterCallBackProc(); + + event System::EventHandler^ OnEvent; + }; + + System::String^ _library; + Interop::Kernel32::Function::DynamicLinkLibrary^ _dll; + + AudioMasterCallBack^ _callBack; + + System::IntPtr _aeffectPtr; + Interop::Vst::AEffect^ _aeffect; + Interop::Vst::AEffectDispatcherProc^ _dispatcher; + Interop::Vst::AEffectSetParameterProc^ _setParameter; + Interop::Vst::AEffectGetParameterProc^ _getParameter; + Interop::Vst::AEffectProcessProc^ _processReplacing; + Interop::Vst::AEffectProcessDoubleProc^ _processDoubleReplacing; + + Interop::Vst::VstTimeInfo^ _timeInfo; + InteropServices::GCHandle _timeInfoHandle; + + public: + Master(System::String^ library); + virtual ~Master(); + protected: + !Master(); + + private: + void Open(); + void Close(); + public: + + System::Int32 GetNumPrograms() { return this->_aeffect->numPrograms; }; + System::Int32 GetNumParams() { return this->_aeffect->numParams; }; + System::Int32 GetNumInputs() { return this->_aeffect->numInputs; }; + System::Int32 GetNumOutputs() { return this->_aeffect->numOutputs; }; + Interop::Vst::VstAEffectFlags GetFlags() { return this->_aeffect->flags; }; + System::Int32 GetInitialDelay() { return this->_aeffect->initialDelay; }; + System::Int32 GetUniqueID() { return this->_aeffect->uniqueID; }; + System::Int32 GetVersion() { return this->_aeffect->version; }; + + private: + System::String^ GetString(Interop::Vst::AEffectOpcodes, System::Int32 index, System::Int32 length); + + public: + //State Transitions + void Suspend(); //< Called when plug-in is switched to off + void Resume(); //< Called when plug-in is switched to on + + //Processing + void SetSampleRate(System::Single sampleRate); //< Called when the sample rate changes (always in a suspend state) + void SetBlockSize(System::Int32 blockSize); //< Called when the Maximun block size changes (always in a suspend state). Note that the sampleFrames in Process Calls could be smaller than this block size, but NOT bigger. + + //Parameters + void SetParameter(System::Int32 index, System::Single value); //< Called when a parameter changed + System::Single GetParameter(System::Int32 index); //< Return the value of the parameter with \e index + bool CanParameterBeAutomated (System::Int32 index); //< Indicates if a parameter can be automated + bool String2Parameter(System::Int32 index, System::String^ value); //< Convert a string representation to a parameter value + Interop::Vst::VstParameterProperties^ GetParameterProperties(System::Int32 index); //< Return parameter properties + + //Programs and Persistence + System::Int32 GetProgram(); //< Return the index to the current program + void SetProgram(System::Int32 program); //< Set the current program to \e program + void SetProgramName(System::String^ name); //< Stuff the name field of the current program with \e name. Limited to #kVstMaxProgNameLen. + System::String^ GetProgramName(); //< Stuff \e name with the name of the current program. Limited to #kVstMaxProgNameLen. + System::String^ GetParameterLabel(System::Int32 index); //< Stuff \e label with the units in which parameter \e index is displayed (i.e. "sec", "dB", "type", etc...). Limited to #kVstMaxParamStrLen. + System::String^ GetParameterDisplay(System::Int32 index); //< Stuff \e text with a string representation ("0.5", "-3", "PLATE", etc...) of the value of parameter \e index. Limited to #kVstMaxParamStrLen. + System::String^ GetParameterName(System::Int32 index); //< Stuff \e text with the name ("Time", "Gain", "RoomType", etc...) of parameter \e index. Limited to #kVstMaxParamStrLen. +/* + System::Int32 GetChunk(void** data, bool isPreset); //< Host stores plug-in state. Returns the size in bytes of the chunk (plug-in allocates the data array) + System::Int32 SetChunk(void* data, System::Int32 byteSize, bool isPreset); //< Host restores plug-in state +*/ + System::String^ GetProgramNameIndexed(System::Int32 index); //< Fill \e text with name of program \e index (\e category deprecated in VST 2.4) + bool BeginSetProgram (); //< Called before a program is loaded + bool EndSetProgram (); //< Called after a program was loaded +/* + System::Int32 BeginLoadBank (VstPatchChunkInfo* ptr); //< Called before a Bank is loaded. + System::Int32 BeginLoadProgram (VstPatchChunkInfo* ptr); //< Called before a Program is loaded. (called before #beginSetProgram). +*/ + //Connections and Configuration + Interop::Vst::VstPinProperties^ GetInputProperties(System::Int32 index); //< Return the \e properties of output \e index + Interop::Vst::VstPinProperties^ GetOutputProperties(System::Int32 index);//< Return the \e properties of input \e index +/* + bool SetSpeakerArrangement (VstSpeakerArrangement* pluginInput, VstSpeakerArrangement* pluginOutput); //< Set the plug-in's speaker arrangements + bool GetSpeakerArrangement (VstSpeakerArrangement** pluginInput, VstSpeakerArrangement** pluginOutput); //< Return the plug-in's speaker arrangements + bool SetBypass (bool onOff);//< For 'soft-bypass' (this could be automated (in Audio Thread) that why you could NOT call iochanged (if needed) in this function, do it in fxidle). + bool SetPanLaw (System::Int32 type, System::Single val);//< Set the Panning Law used by the Host @see VstPanLawType. + bool SetProcessPrecision (System::Int32 precision);//< Set System::Singleing-point precision used for processing (32 or 64 bit) + System::Int32 GetNumMidiInputChannels();//< Returns number of MIDI input channels used [0, 16] + System::Int32 GetNumMidiOutputChannels();//< Returns number of MIDI output channels used [0, 16] +*/ + + //Realtime + System::IntPtr GetTimeInfo(System::Int32 filter); //< Get time information from Host + //System::Int32 GetCurrentProcessLevel(); //< Returns the Host's process level + //System::Int32 GetAutomationState(); //< Returns the Host's automation state + System::Int32 ProcessEvents(array^ events); //< Called when new MIDI events come in + System::Int32 StartProcess(); //< Called one time before the start of process call. This indicates that the process call will be interrupted (due to Host reconfiguration or bypass state when the plug-in doesn't support softBypass) + System::Int32 StopProcess(); //< Called after the stop of process call +/* + //Variable I/O (Offline) + bool ProcessVariableIo (VstVariableIo* varIo); //< Used for variable I/O processing (offline processing like timestreching) + System::Int32 SetTotalSampleToProcess (System::Int32 value); //< Called in offline mode before process() or processVariableIo () + + //Host Properties + bool GetHostVendorString (System::String^ text); //< Fills \e text with a string identifying the vendor + bool GetHostProductString (System::String^ text); //< Fills \e text with a string with product name + System::Int32 GetHostVendorVersion (); //< Returns vendor-specific version (for example 3200 for Nuendo 3.2) + System::IntPtr HostVendorSpecific (System::Int32 lArg1, System::IntPtr lArg2, void* ptrArg, System::Single System::SingleArg); //< No specific definition + System::Int32 CanHostDo (System::String^ text); //< Reports what the Host is able to do (#hostCanDos in audioeffectx.cpp) + System::Int32 GetHostLanguage (); //< Returns the Host's language (#VstHostLanguage) + + //Plug-in Properties + void IsSynth (bool state); //< Set if plug-in is a synth + void NoTail (bool state); //< Plug-in won't produce output signals while there is no input + System::Int32 GetGetTailSize () ; //< Returns tail size; 0 is default (return 1 for 'no tail'), used in offline processing too + void* GetDirectory (); //< Returns the plug-in's directory +*/ + System::String^ GetEffectName(); //< Fill \e text with a string identifying the effect + System::String^ GetVendorString(); //< Fill \e text with a string identifying the vendor + System::String^ GetProductString(); //< Fill \e text with a string identifying the product name +/* System::Int32 GetVendorVersion (); //< Return vendor-specific version + System::IntPtr VendorSpecific (System::Int32 lArg, System::IntPtr lArg2, void* ptrArg, System::Single System::SingleArg); //< No definition, vendor specific handling + System::Int32 CanDo (System::String^ text); //< Reports what the plug-in is able to do (#plugCanDos in audioeffectx.cpp) + System::Int32 GetVstVersion (); //< Returns the current VST Version (#kVstVersion) + VstPlugCategory GetPlugCategory (); //< Specify a category that fits the plug (#VstPlugCategory) + + //MIDI Channel Programs + System::Int32 GetMidiProgramName (System::Int32 channel, MidiProgramName* midiProgramName); //< Fill \e midiProgramName with information for 'thisProgramIndex'. + System::Int32 GetCurrentMidiProgram (System::Int32 channel, MidiProgramName* currentProgram); //< Fill \e currentProgram with information for the current MIDI program. + System::Int32 GetMidiProgramCategory (System::Int32 channel, MidiProgramCategory* category); //< Fill \e category with information for 'thisCategoryIndex'. + bool HasMidiProgramsChanged (System::Int32 channel); //< Return true if the #MidiProgramNames, #MidiKeyNames or #MidiControllerNames had changed on this MIDI channel. + bool GetMidiKeyName (System::Int32 channel, MidiKeyName* keyName); //< Fill \e keyName with information for 'thisProgramIndex' and 'thisKeyNumber' + + //Others + bool UpdateDisplay (); //< Something has changed in plug-in, request an update display like program (MIDI too) and parameters list in Host + bool SizeWindow (System::Int32 width, System::Int32 height); //< Requests to resize the editor window + bool OpenFileSelector (VstFileSelect* ptr); //< Open a Host File selector (see aeffectx.h for #VstFileSelect definition) + bool CloseFileSelector (VstFileSelect* ptr); //< Close the Host File selector which was opened by #openFileSelector + System::Int32 GetNextShellPlugin (System::String^ name); //< This opcode is only called, if the plug-in is of type #kPlugCategShell, in order to extract all included sub-plugin・エs names. + + //Tools + bool AllocateArrangement (VstSpeakerArrangement** arrangement, System::Int32 nbChannels);//< Allocate memory for a #VstSpeakerArrangement + bool DeallocateArrangement (VstSpeakerArrangement** arrangement); //< Delete/free memory for an allocated speaker arrangement + bool CopySpeaker (VstSpeakerProperties* to, VstSpeakerProperties* from); //< Copy properties \e from to \e to + bool MatchArrangement (VstSpeakerArrangement** to, VstSpeakerArrangement* from); //< "to" is deleted, then created and initialized with the same values as "from" ones ("from" must exist). + + // Offline + bool OfflineRead (VstOfflineTask* offline, VstOfflineOption option, bool readSource = true); + bool OfflineWrite (VstOfflineTask* offline, VstOfflineOption option); + bool OfflineStart (VstAudioFile* ptr, System::Int32 numAudioFiles, System::Int32 numNewAudioFiles); + System::Int32 OfflineGetCurrentPass (); + System::Int32 OfflineGetCurrentMetaPass (); + bool OfflineNotify (VstAudioFile* ptr, System::Int32 numAudioFiles, bool start); + bool OfflinePrepare (VstOfflineTask* offline, System::Int32 count); + bool OfflineRun (VstOfflineTask* offline, System::Int32 count); + System::Int32 OfflineGetNumPasses (); + System::Int32 OfflineGetNumMetaPasses (); +*/ + + public: + System::IntPtr Dispatcher( + Interop::Vst::AEffectOpcodes opcode, + System::Int32 index, + System::IntPtr value, + System::IntPtr ptr, + System::Single opt + ); + + void Process( + Buffer::VstBuffer^ inputs, + Buffer::VstBuffer^ outputs, + System::Int32 sampleFrames + ); + + void Process( + Buffer::VstBuffer^ inputs, + Buffer::VstBuffer^ outputs, + System::Int32 sampleFrames + ); + + private: + void OnEventHandler(System::Object^ sender, Interop::Vst::AudioMasterCallBack::AudioMasterEventArgs^ args); + + }; + + public ref class VstException + : public System::Exception + { + public: + VstException(System::String^ v): System::Exception(v){}; + }; + +} +} +} +} diff --git a/Core/Momiji.Core.Wave.Data.h b/Core/Momiji.Core.Wave.Data.h new file mode 100644 index 0000000..5bfadec --- /dev/null +++ b/Core/Momiji.Core.Wave.Data.h @@ -0,0 +1,61 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Wave.Data.h + wave data. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +#include "Momiji.Interop.Winmm.h" +#include "Momiji.Core.Interface.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Wave { + + generic + public ref class WaveData + : public Core::IData + { + private: + initonly System::UInt16 _port; + initonly array^ _data; + initonly System::UInt32 _useSize; + + public: + WaveData( + System::UInt16 port, + array^ data, + System::UInt32 useSize + ): _port(port), _data(data), _useSize(useSize) {} + + public: + property System::UInt16 port { System::UInt16 get() {return this->_port;} } + property array^ data { array^ get() {return this->_data;} } + property System::UInt32 useSize { System::UInt32 get() { return this->_useSize; } } + }; + + +} +} +} diff --git a/Core/Momiji.Core.Wave.Out.cpp b/Core/Momiji.Core.Wave.Out.cpp new file mode 100644 index 0000000..b00cb2b --- /dev/null +++ b/Core/Momiji.Core.Wave.Out.cpp @@ -0,0 +1,470 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Wave.Out.cpp + wave output component. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Interop.Winmm.h" +#include "Momiji.Core.Wave.Out.h" +#include "Momiji.Core.Wave.Data.h" + +namespace Momiji { +namespace Core { +namespace Wave { +namespace Out { + + void Device::OnEventHandler( + System::Object^ sender, + Interop::Winmm::DriverCallBack::DriverEventArgs^ args + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] start", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + + switch (args->uMsg) + { + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::WOM_OPEN : + { + this->DoOpen(args->dw1, args->dw2); + break; + } + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::WOM_CLOSE: + { + this->DoClose(args->dw1, args->dw2); + break; + } + case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::WOM_DONE : + { + this->DoDone(args->dw1, args->dw2); + break; + } + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] end", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + } + + void Device::DoOpen(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + this->OnOpen(this, System::EventArgs::Empty); + } + + void Device::DoClose(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + #endif + this->OnClose(this, System::EventArgs::Empty); + } + + void Device::DoDone(System::IntPtr dwParam1, System::IntPtr dwParam2) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2); + + auto waveHeader = safe_cast(InteropServices::Marshal::PtrToStructure(dwParam1, Interop::Winmm::WaveHeader::typeid)); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, waveHeader); + #endif + + UnpreparedEventArgs^ eventArgs = gcnew UnpreparedEventArgs(); + eventArgs->bufferPtr = this->Unprepare(dwParam1); + + this->OnDone(this, eventArgs); + } + + System::UInt32 Device::GetNumDevices() + { + return Interop::Winmm::Function::waveOutGetNumDevs(); + } + + Interop::Winmm::WaveOutCapabilities^ Device::GetCapabilities( + const System::UInt32 deviceID + ) + { + auto caps = gcnew Interop::Winmm::WaveOutCapabilities(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] caps size {1}",__FUNCTION__, InteropServices::Marshal::SizeOf(caps)); + #endif + auto mmResult = + Interop::Winmm::Function::waveOutGetDevCaps( + deviceID, + caps, + InteropServices::Marshal::SizeOf(caps) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew WaveOutException(mmResult); + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] caps productName {1}",__FUNCTION__, caps->productName); + #endif + + return caps; + } + + Device::Device( + System::UInt32 deviceID, + System::UInt16 channels, + System::UInt32 samplesPerSecond, + System::UInt16 bitsPerSample, + Interop::Winmm::WaveFormatExtensiblePart::SPEAKER channelMask, + Interop::Guiddef::Guid formatSubType, + System::UInt32 samplesPerBuffer + ): + _deviceID(deviceID), + _channels(channels), + _samplesPerSecond(samplesPerSecond), + _bitsPerSample(bitsPerSample), + _channelMask(channelMask), + _formatSubType(formatSubType), + _samplesPerBuffer(samplesPerBuffer) + { + #ifdef _DEBUG + System::Diagnostics::Trace::WriteLine(System::String::Format("[{0}] deviceID {1} start",__FUNCTION__, this->_deviceID)); + System::Console::WriteLine("[{0}] deviceID {1} start",__FUNCTION__, this->_deviceID); + #endif + + this->Open(); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] end",__FUNCTION__); + #endif + } + + Device::~Device() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] start",__FUNCTION__); + #endif + this->!Device(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] end",__FUNCTION__); + #endif + } + + Device::!Device() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] start",__FUNCTION__); + #endif + this->Close(); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] end",__FUNCTION__); + #endif + } + + Interop::Winmm::WaveOutCapabilities^ Device::GetCapabilities() + { + return Device::GetCapabilities(this->_deviceID); + } + + void Device::Open() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_callBack = gcnew Core::Winmm::DriverCallBack(true); //イベントは非同期で動かす + this->_callBack->OnEvent += gcnew System::EventHandler(this, &Device::OnEventHandler); + + auto format = Interop::Winmm::WaveFormatExtensible(); + format.wfe.formatType = Interop::Winmm::WaveFormatEx::FORMAT::EXTENSIBLE; + format.wfe.channels = this->_channels; + format.wfe.samplesPerSecond = this->_samplesPerSecond; + format.wfe.bitsPerSample = this->_bitsPerSample; + format.wfe.blockAlign = format.wfe.channels * format.wfe.bitsPerSample / 8; + format.wfe.averageBytesPerSecond = format.wfe.samplesPerSecond * format.wfe.blockAlign; + format.wfe.size = safe_cast(InteropServices::Marshal::SizeOf(Interop::Winmm::WaveFormatExtensiblePart::typeid)); + + format.exp.validBitsPerSample = format.wfe.bitsPerSample; //TODO: 実際にハードウェアでサポートしている限界に揃える + format.exp.channelMask = this->_channelMask; + format.exp.subFormat = this->_formatSubType; + + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] format [{1}]",__FUNCTION__, format); + #endif + + this->_headerPool = + gcnew Core::Buffer::BufferPool( + ((this->_samplesPerSecond / (this->_samplesPerBuffer * format.wfe.blockAlign)) + 2), //1秒分+2回 + gcnew Core::Buffer::BufferPool::Allocator(this, &Device::AllocateHeader) + ); + + auto mmResult = + Interop::Winmm::Function::waveOutOpen( + this->_handle, + this->_deviceID, + format, + this->_callBack->GetDriverCallBackProc(), + System::IntPtr::Zero, + ( + Interop::Winmm::DriverCallBack::TYPE::FUNCTION + | Interop::Winmm::DriverCallBack::TYPE::WAVE_FORMAT_DIRECT + // | Interop::Winmm::DriverCallBack::TYPE::WAVE_ALLOWSYNC + ) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew WaveOutException(mmResult); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed); + #endif + } + + void Device::Close() + { + if (this->_handle != nullptr) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed); + #endif + if ( + !this->_handle->IsInvalid + && !this->_handle->IsClosed + ) + { + this->Reset(); + + //バッファの開放待ち + while(this->_headerPool->IsBusy()) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] wait for unprepare headers ...",__FUNCTION__); + #endif + System::Threading::Thread::Sleep(5); + } + + this->_handle->Close(); + } + else + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] openしていない状態なので、無視します。", __FUNCTION__); + #endif + } + } + + if (this->_callBack != nullptr) + { + this->_callBack->OnEvent -= gcnew System::EventHandler(this, &Device::OnEventHandler); + delete this->_callBack; + } + + if (this->_headerPool != nullptr) + { + delete this->_headerPool; + } + } + + void Device::Reset() + { + if ( + this->_handle->IsInvalid + || this->_handle->IsClosed + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] openしていない状態なので、無視します。", __FUNCTION__); + #endif + return; + } + + auto mmResult = Interop::Winmm::Function::waveOutReset(this->_handle); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew WaveOutException(mmResult); + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] waveOutReset OK",__FUNCTION__); + #endif + } + + //TODO 要同期 + System::IntPtr Device::Prepare(System::IntPtr data, System::UInt32 useSize) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto header = this->_headerPool->Get(); + + { + auto waveHeader = header->GetBuffer(); + waveHeader->data = data; + waveHeader->bufferLength = useSize; + waveHeader->flags = (Interop::Winmm::WaveHeader::FLAG::BEGINLOOP | Interop::Winmm::WaveHeader::FLAG::ENDLOOP); + waveHeader->loops = 1; + + waveHeader->bytesRecorded = 0; + waveHeader->user = System::IntPtr::Zero; + waveHeader->next = System::IntPtr::Zero; + waveHeader->reserved = System::IntPtr::Zero; + + #ifdef _DEBUG + { + System::Console::WriteLine("[{0}] waveOutPrepareHeader before", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, waveHeader); + } + #endif + } + + auto mmResult = + Interop::Winmm::Function::waveOutPrepareHeader( + this->_handle, + header->GetBufferIntPtr(), + InteropServices::Marshal::SizeOf(Interop::Winmm::WaveHeader::typeid) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + this->_headerPool->Release(header); + + throw gcnew WaveOutException(mmResult); + } + #ifdef _DEBUG + { + auto waveHeader = header->GetBuffer(); + System::Console::WriteLine("[{0}] waveOutPrepareHeader after", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, waveHeader); + } + #endif + + return header->GetBufferIntPtr(); + } + + //TODO 要同期 + System::IntPtr Device::Unprepare(System::IntPtr headerPtr) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + Core::Buffer::BufferPool::Buffer^ header = this->_headerPool->GetBusy(headerPtr); + + #ifdef _DEBUG + { + auto waveHeader = header->GetBuffer(); + System::Console::WriteLine("[{0}] waveOutUnprepareHeader before", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, waveHeader); + } + #endif + + auto mmResult = + Interop::Winmm::Function::waveOutUnprepareHeader( + this->_handle, + headerPtr, + InteropServices::Marshal::SizeOf(Interop::Winmm::WaveHeader::typeid) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + throw gcnew WaveOutException(mmResult); + } + + auto result = header->GetBuffer()->data; + + this->_headerPool->Release(header); + + #ifdef _DEBUG + { + auto waveHeader = header->GetBuffer(); + System::Console::WriteLine("[{0}] waveOutUnprepareHeader after", __FUNCTION__); + System::Console::WriteLine("[{0}] {1}", __FUNCTION__, waveHeader); + } + #endif + + return result; + } + + void Device::Send( + System::IntPtr data, System::UInt32 useSize + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + if ( + this->_handle->IsInvalid + || this->_handle->IsClosed + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] openしていない状態なので、無視します。", __FUNCTION__); + #endif + return; + } + + System::IntPtr headerPtr = this->Prepare(data, useSize); + + auto mmResult = + Interop::Winmm::Function::waveOutWrite( + this->_handle, + headerPtr, + InteropServices::Marshal::SizeOf(Interop::Winmm::WaveHeader::typeid) + ); + if (mmResult != Interop::Winmm::MMRESULT::NOERROR) + { + this->Unprepare(headerPtr); + throw gcnew WaveOutException(mmResult); + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] waveOutWrite OK",__FUNCTION__); + #endif + } + + Interop::Winmm::WaveHeader^ Device::AllocateHeader() + { + return gcnew Interop::Winmm::WaveHeader(); + } + + System::String^ WaveOutException::Initialize() + { + auto errorMessage = System::String::Empty; + auto buf = gcnew System::Text::StringBuilder(256); + + auto r = + Interop::Winmm::Function::waveOutGetErrorText( + this->_mmResult, + buf, + buf->Capacity + ); + if (r == Interop::Winmm::MMRESULT::NOERROR) + { + errorMessage = buf->ToString(); + } + else + { + errorMessage = "不明なエラー"; + } + + return errorMessage + "[" + this->_mmResult.ToString("D") + "]"; + } + +} +} +} +} diff --git a/Core/Momiji.Core.Wave.Out.h b/Core/Momiji.Core.Wave.Out.h new file mode 100644 index 0000000..2c097a0 --- /dev/null +++ b/Core/Momiji.Core.Wave.Out.h @@ -0,0 +1,128 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Wave.Out.h + wave output component. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Core.Interface.h" +#include "Momiji.Core.Winmm.h" +#include "Momiji.Core.Buffer.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Wave { +namespace Out { + + public ref class Device + { + private: + initonly System::UInt32 _deviceID; + + initonly System::UInt16 _channels; + initonly System::UInt32 _samplesPerSecond; + initonly System::UInt16 _bitsPerSample; + initonly Interop::Winmm::WaveFormatExtensiblePart::SPEAKER _channelMask; + initonly Interop::Guiddef::Guid _formatSubType; + initonly System::UInt32 _samplesPerBuffer; + + Interop::Winmm::Function::WaveOut^ _handle; + Core::Winmm::DriverCallBack^ _callBack; + Core::Buffer::BufferPool^ _headerPool; + + public: + ref class UnpreparedEventArgs: System::EventArgs + { + public: + System::IntPtr bufferPtr; + }; + + public: + Device( + System::UInt32 deviceID, + System::UInt16 channels, + System::UInt32 samplesPerSecond, + System::UInt16 bitsPerSample, + Interop::Winmm::WaveFormatExtensiblePart::SPEAKER channelMask, + Interop::Guiddef::Guid formatSubType, + System::UInt32 samplesPerBuffer + ); + virtual ~Device(); + protected: + !Device(); + + private: + System::IntPtr Prepare(System::IntPtr data, System::UInt32 useSize); + System::IntPtr Unprepare(System::IntPtr headerPtr); + + Interop::Winmm::WaveHeader^ AllocateHeader(); + + public: + static System::UInt32 GetNumDevices(); + static Interop::Winmm::WaveOutCapabilities^ GetCapabilities(System::UInt32 uDeviceID); + Interop::Winmm::WaveOutCapabilities^ GetCapabilities(); + + private: + void Open(); + void Close(); + + public: + //TODO: これのインタフェースは何かのBuffer情報の塊にしたい + void Send(System::IntPtr data, System::UInt32 useSize); + void Reset(); + + public: + event System::EventHandler^ OnOpen; + event System::EventHandler^ OnClose; + event System::EventHandler^ OnDone; + + private: + void OnEventHandler(System::Object^ sender, Interop::Winmm::DriverCallBack::DriverEventArgs^ args); + + void DoOpen(System::IntPtr dwParam1, System::IntPtr dwParam2); + void DoClose(System::IntPtr dwParam1, System::IntPtr dwParam2); + void DoDone(System::IntPtr dwParam1, System::IntPtr dwParam2); + }; + + public ref class WaveOutException + : public System::Exception + { + private: + initonly Interop::Winmm::MMRESULT _mmResult; + System::String^ Initialize(); + + public: + WaveOutException(Interop::Winmm::MMRESULT v): _mmResult(v), System::Exception(Initialize()){}; + WaveOutException(System::String^ v): System::Exception(v){}; + virtual ~WaveOutException(void){}; + + property Interop::Winmm::MMRESULT mmResult + { + Interop::Winmm::MMRESULT get(void) {return this->_mmResult;}; + } + }; + +} +} +} +} diff --git a/Core/Momiji.Core.Winmm.cpp b/Core/Momiji.Core.Winmm.cpp new file mode 100644 index 0000000..0abdf61 --- /dev/null +++ b/Core/Momiji.Core.Winmm.cpp @@ -0,0 +1,239 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Winmm.cpp + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Interop.Winmm.h" +#include "Momiji.Core.Winmm.h" + +namespace Momiji { +namespace Core { +namespace Winmm { + + DriverCallBack::DriverCallBack(System::Boolean async): + _async(async) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_callBack = InteropServices::GCHandle::Alloc(gcnew Interop::Winmm::DriverCallBack::Delegate(this, &DriverCallBack::DriverCallBackProc)); + } + + DriverCallBack::~DriverCallBack() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!DriverCallBack(); + } + + DriverCallBack::!DriverCallBack() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + if (this->_callBack.IsAllocated) + { + this->_callBack.Free(); + } + } + + Interop::Winmm::DriverCallBack::Delegate^ DriverCallBack::GetDriverCallBackProc() + { + return safe_cast(this->_callBack.Target); + } + + void DriverCallBack::DriverCallBackProc( + System::IntPtr hdrvr, + Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE uMsg, + System::IntPtr dwUser, + System::IntPtr dw1, + System::IntPtr dw2 + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}][{3,8:X}][{4,8:X}][{5,8:X}]", __FUNCTION__, hdrvr, uMsg, dwUser, dw1, dw2); + #endif + try + { + auto params = gcnew Interop::Winmm::DriverCallBack::DriverEventArgs(); + params->hdrvr = hdrvr; + params->uMsg = uMsg; + params->dwUser = dwUser; + params->dw1 = dw1; + params->dw2 = dw2; + + if (this->_async) + { + System::Threading::ThreadPool::QueueUserWorkItem( + gcnew System::Threading::WaitCallback(this, &DriverCallBack::DoEvent), + params + ); + } + else + { + this->DoEvent(params); + } + } + catch(System::Exception^ e) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] コールバック中のエラー[{1}]", __FUNCTION__, e->ToString()); + #endif + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] OUT", __FUNCTION__); + #endif + } + + void DriverCallBack::DoEvent( + System::Object^ stateInfo + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] start", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + + auto params = safe_cast(stateInfo); + try + { + this->OnEvent(this, params); + } + catch(System::Exception^ e) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] コールバック中のエラー[{1}]", __FUNCTION__, e->ToString()); + #endif + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] end", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + } + + + + + + TimerCallBack::TimerCallBack(System::Boolean async): + _async(async) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_callBack = InteropServices::GCHandle::Alloc(gcnew Interop::Winmm::TimerCallBack::Delegate(this, &TimerCallBack::TimerCallBackProc)); + } + + TimerCallBack::~TimerCallBack() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!TimerCallBack(); + } + + TimerCallBack::!TimerCallBack() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + if (this->_callBack.IsAllocated) + { + this->_callBack.Free(); + } + } + + Interop::Winmm::TimerCallBack::Delegate^ TimerCallBack::GetTimerCallBackProc() + { + return safe_cast(this->_callBack.Target); + } + + void TimerCallBack::TimerCallBackProc( + System::UInt32 uTimerID, + System::UInt32 uMsg, + System::IntPtr dwUser, + System::IntPtr dw1, + System::IntPtr dw2 + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}][{3,8:X}][{4,8:X}][{5,8:X}]", __FUNCTION__, uTimerID, uMsg, dwUser, dw1, dw2); + #endif + try + { + auto params = gcnew Interop::Winmm::TimerCallBack::TimerEventArgs(); + params->uTimerID = uTimerID; + params->uMsg = uMsg; + params->dwUser = dwUser; + params->dw1 = dw1; + params->dw2 = dw2; + + if (this->_async) + { + System::Threading::ThreadPool::QueueUserWorkItem( + gcnew System::Threading::WaitCallback(this, &TimerCallBack::DoEvent), + params + ); + } + else + { + this->DoEvent(params); + } + } + catch(System::Exception^ e) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] コールバック中のエラー[{1}]", __FUNCTION__, e->ToString()); + #endif + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] OUT", __FUNCTION__); + #endif + } + + void TimerCallBack::DoEvent( + System::Object^ stateInfo + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] start", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + + auto params = safe_cast(stateInfo); + try + { + this->OnEvent(this, params); + } + catch(System::Exception^ e) + { + System::Console::WriteLine("[{0}] コールバック中のエラー[{1}]", __FUNCTION__, e->ToString()); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}] end", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode()); + #endif + } +} +} +} diff --git a/Core/Momiji.Core.Winmm.h b/Core/Momiji.Core.Winmm.h new file mode 100644 index 0000000..9ccc7a2 --- /dev/null +++ b/Core/Momiji.Core.Winmm.h @@ -0,0 +1,93 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Winmm.h + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Core.Interface.h" +#include "Momiji.Interop.Winmm.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Core { +namespace Winmm { + + ref class DriverCallBack + { + private: + InteropServices::GCHandle _callBack; + System::Boolean _async; + + public: + DriverCallBack(System::Boolean async); + virtual ~DriverCallBack(); + protected: + !DriverCallBack(); + + private: + void DriverCallBackProc( + System::IntPtr hdrvr, + Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE uMsg, + System::IntPtr dwUser, + System::IntPtr dw1, + System::IntPtr dw2 + ); + void DoEvent(System::Object^ args); + + public: + Interop::Winmm::DriverCallBack::Delegate^ GetDriverCallBackProc(); + + event System::EventHandler^ OnEvent; + }; + + ref class TimerCallBack + { + private: + InteropServices::GCHandle _callBack; + System::Boolean _async; + + public: + TimerCallBack(System::Boolean async); + virtual ~TimerCallBack(); + protected: + !TimerCallBack(); + + private: + void TimerCallBackProc( + System::UInt32 uTimerID, + System::UInt32 uMsg, + System::IntPtr dwUser, + System::IntPtr dw1, + System::IntPtr dw2 + ); + void DoEvent(System::Object^ args); + + public: + Interop::Winmm::TimerCallBack::Delegate^ GetTimerCallBackProc(); + + event System::EventHandler^ OnEvent; + }; + +} +} +} diff --git a/Core/Momiji.Core.vcxproj b/Core/Momiji.Core.vcxproj new file mode 100644 index 0000000..da1d88e --- /dev/null +++ b/Core/Momiji.Core.vcxproj @@ -0,0 +1,176 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {5895C214-5905-4C4F-9115-4BE323657AFC} + v4.5 + ManagedCProj + XXMIDICLR + + + + DynamicLibrary + true + Safe + Unicode + true + v110 + + + DynamicLibrary + false + Safe + Unicode + true + Windows7.1SDK + + + + + + + + + + + + + true + false + false + + + false + + + + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + true + All + false + Level4 + MultiThreadedDebugDLL + ..\Debug;%(AdditionalUsingDirectories) + true + + + true + + + LinkVerbose + MTAThreadingAttribute + true + true + Default + + + 0x0411 + + + + + WIN32;NDEBUG;%(PreprocessorDefinitions) + true + All + NotUsing + Level4 + MultiThreadedDLL + ..\Release;%(AdditionalUsingDirectories) + + + false + + + LinkVerbose + true + MTAThreadingAttribute + true + true + true + Default + + + 0x0411 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Core/Momiji.Core.vcxproj.filters b/Core/Momiji.Core.vcxproj.filters new file mode 100644 index 0000000..0bf7796 --- /dev/null +++ b/Core/Momiji.Core.vcxproj.filters @@ -0,0 +1,190 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + リソース ファイル + + + + + リソース ファイル + + + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + \ No newline at end of file diff --git a/Core/Momiji.Core.vcxproj.user b/Core/Momiji.Core.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/Core/Momiji.Core.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Core/Momiji.Interop.DirectShow.h b/Core/Momiji.Interop.DirectShow.h new file mode 100644 index 0000000..25d4dee --- /dev/null +++ b/Core/Momiji.Interop.DirectShow.h @@ -0,0 +1,48 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Interop.DirectShow.h + windows multi media dll importer. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +using namespace System::Runtime; + +namespace Momiji{ +namespace Interop { +namespace DirectShow { + + [ComImport, System.Security.SuppressUnmanagedCodeSecurity, + Guid("29840822-5B84-11D0-BD3B-00A0C911CE86"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface ICreateDevEnum + { + [PreserveSig] + System::UInt32 CreateClassEnumerator( + [InteropServices::In] Guiddef::Guid clsidDeviceClass, + [InteropServices::Out] System::Runtime::InteropServices::ComTypes::IEnumMoniker^ ppEnumMoniker, + [InteropServices::In] CDef dwFlags + ); + } + +} +} +} diff --git a/Core/Momiji.Interop.Guiddef.cpp b/Core/Momiji.Interop.Guiddef.cpp new file mode 100644 index 0000000..96eccd9 --- /dev/null +++ b/Core/Momiji.Interop.Guiddef.cpp @@ -0,0 +1,109 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Interop.Guiddef.cpp + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Interop.Guiddef.h" + + +namespace Momiji{ +namespace Interop { +namespace Guiddef { + + value struct GuidInfo { + Guid _guid; + System::String^ _name; + + }; + + ref class GuidMap { + private: + static GuidMap^ _instance; + static System::Object^ _lock = gcnew System::Object(); + + System::Collections::Generic::Dictionary^ _guidMap; + + GuidMap() + : _guidMap(gcnew System::Collections::Generic::Dictionary()) + { + }; + + static property GuidMap^ Instance { + GuidMap^ get() { + if (_instance == nullptr) { + System::Threading::Monitor::Enter(_lock); + try { + if (_instance == nullptr) { _instance = gcnew GuidMap(); } + } finally { + System::Threading::Monitor::Exit(_lock); + } + } + return _instance; + }; + }; + + public: + static Guid Regist(System::String^ guid, System::String^ name) { + GuidMap^ map = GuidMap::Instance; + System::String^ upperGuid = guid->ToUpper(); + GuidInfo info; + if (map->_guidMap->TryGetValue(upperGuid, info)) { + return info._guid; + } + //info = gcnew GuidInfo(); + info._guid = Guid(upperGuid); + info._name = name; + map->_guidMap->Add(upperGuid, info); + return info._guid; + }; + + static System::String^ Name(System::String^ guid) { + GuidMap^ map = GuidMap::Instance; + System::String^ upperGuid = guid->ToUpper(); + GuidInfo info; + if (!map->_guidMap->TryGetValue(upperGuid, info)) { + return "unknown"; + } + return info._name; + }; + }; + + + +// Guid::Guid(){} + Guid::Guid(System::String^ guid): data(System::Guid(guid)) {} + + Guid Guid::Regist(System::String^ guid, System::String^ name) { + return GuidMap::Regist(guid, name); + } + + System::String^ Guid::ToString() + { + System::String^ guid = this->data.ToString(); + return guid + "(" + GuidMap::Name(guid) +")"; + } + + + +} +} +} diff --git a/Core/Momiji.Interop.Guiddef.h b/Core/Momiji.Interop.Guiddef.h new file mode 100644 index 0000000..1cb2855 --- /dev/null +++ b/Core/Momiji.Interop.Guiddef.h @@ -0,0 +1,47 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Interop.Guiddef.h + windows multi media dll importer. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +using namespace System::Runtime; + +namespace Momiji{ +namespace Interop { +namespace Guiddef { + + WIN32_DLL_STRUCTLAYOUT public value class Guid + { + private: + System::Guid data; + + public: + //Guid(); + Guid(System::String^ guid); + + virtual System::String^ ToString() override; + + static Guid Regist(System::String^ guid, System::String^ name); + }; + +} +} +} diff --git a/Core/Momiji.Interop.Kernel32.h b/Core/Momiji.Interop.Kernel32.h new file mode 100644 index 0000000..5f66e50 --- /dev/null +++ b/Core/Momiji.Interop.Kernel32.h @@ -0,0 +1,244 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Interop.Kernel32.h + windows kernel dll importer. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +//#include "Momiji.Interop.Ks.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Interop { +namespace Kernel32 { + +#define KERNEL32_DLLIMPORT WIN32_DLL_IMPORT("kernel32") +#define KERNEL32_DLLIMPORT_ANSI WIN32_DLL_IMPORT_ANSI("kernel32") + + public enum class ACCESS_TYPES: System::UInt32 + { + // The following are masks for the predefined standard access types + DELETE = 0x00010000, + READ_CONTROL = 0x00020000, + WRITE_DAC = 0x00040000, + WRITE_OWNER = 0x00080000, + SYNCHRONIZE = 0x00100000, + STANDARD_RIGHTS_REQUIRED = 0x000F0000, + STANDARD_RIGHTS_READ = READ_CONTROL, + STANDARD_RIGHTS_WRITE = READ_CONTROL, + STANDARD_RIGHTS_EXECUTE = READ_CONTROL, + STANDARD_RIGHTS_ALL = 0x001F0000, + SPECIFIC_RIGHTS_ALL = 0x0000FFFF, + // AccessSystemAcl access type + ACCESS_SYSTEM_SECURITY = 0x01000000, + // MaximumAllowed access type + MAXIMUM_ALLOWED = 0x02000000, + // These are the generic rights. + GENERIC_READ = 0x80000000, + GENERIC_WRITE = 0x40000000, + GENERIC_EXECUTE = 0x20000000, + GENERIC_ALL = 0x10000000, + + + KEY_QUERY_VALUE = 0x0001, + KEY_SET_VALUE = 0x0002, + KEY_CREATE_SUB_KEY = 0x0004, + KEY_ENUMERATE_SUB_KEYS = 0x0008, + KEY_NOTIFY = 0x0010, + KEY_CREATE_LINK = 0x0020, + KEY_WOW64_32KEY = 0x0200, + KEY_WOW64_64KEY = 0x0100, + KEY_WOW64_RES = 0x0300, + + KEY_READ = (( STANDARD_RIGHTS_READ + | KEY_QUERY_VALUE + | KEY_ENUMERATE_SUB_KEYS + | KEY_NOTIFY) + & ~SYNCHRONIZE), + + + KEY_WRITE = (( STANDARD_RIGHTS_WRITE + | KEY_SET_VALUE + | KEY_CREATE_SUB_KEY) + & ~SYNCHRONIZE), + + KEY_EXECUTE = (KEY_READ & ~SYNCHRONIZE), + + KEY_ALL_ACCESS = (( STANDARD_RIGHTS_ALL + | KEY_QUERY_VALUE + | KEY_SET_VALUE + | KEY_CREATE_SUB_KEY + | KEY_ENUMERATE_SUB_KEYS + | KEY_NOTIFY + | KEY_CREATE_LINK) + & ~SYNCHRONIZE), + + }; + + public enum class SHARE_MODE: System::UInt32 + { + FILE_SHARE_NONE = 0x00000000, + FILE_SHARE_READ = 0x00000001, + FILE_SHARE_WRITE = 0x00000002, + FILE_SHARE_DELETE = 0x00000004, + }; + + public enum class CREATION_DISPOSITION: System::UInt32 + { + CREATE_NEW = 1, + CREATE_ALWAYS = 2, + OPEN_EXISTING = 3, + OPEN_ALWAYS = 4, + TRUNCATE_EXISTING = 5, + }; + + public enum class FLAG_AND_ATTRIBUTE: System::UInt32 + { + FILE_ATTRIBUTE_READONLY = 0x00000001, + FILE_ATTRIBUTE_HIDDEN = 0x00000002, + FILE_ATTRIBUTE_SYSTEM = 0x00000004, + FILE_ATTRIBUTE_DIRECTORY = 0x00000010, + FILE_ATTRIBUTE_ARCHIVE = 0x00000020, + FILE_ATTRIBUTE_DEVICE = 0x00000040, + FILE_ATTRIBUTE_NORMAL = 0x00000080, + FILE_ATTRIBUTE_TEMPORARY = 0x00000100, + FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200, + FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400, + FILE_ATTRIBUTE_COMPRESSED = 0x00000800, + FILE_ATTRIBUTE_OFFLINE = 0x00001000, + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000, + FILE_ATTRIBUTE_ENCRYPTED = 0x00004000, + FILE_ATTRIBUTE_VIRTUAL = 0x00010000, + + FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000, + FILE_FLAG_OPEN_NO_RECALL = 0x00100000, + FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000, + FILE_FLAG_POSIX_SEMANTICS = 0x01000000, + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000, + FILE_FLAG_DELETE_ON_CLOSE = 0x04000000, + FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000, + FILE_FLAG_RANDOM_ACCESS = 0x10000000, + FILE_FLAG_NO_BUFFERING = 0x20000000, + FILE_FLAG_OVERLAPPED = 0x40000000, + FILE_FLAG_WRITE_THROUGH = 0x80000000, + }; + + public value class Function { + + public: + [System::Security::Permissions::SecurityPermissionAttribute(System::Security::Permissions::SecurityAction::InheritanceDemand, UnmanagedCode = true)] + ref class DynamicLinkLibrary + : public Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid + { + public: + DynamicLinkLibrary() + : Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid(true) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + }; + + protected: + [ConstrainedExecution::ReliabilityContract(ConstrainedExecution::Consistency::WillNotCorruptState, ConstrainedExecution::Cer::MayFail)] + virtual System::Boolean ReleaseHandle() override + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + System::Boolean result = FreeLibrary(this->handle); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] FreeLibrary result {1}",__FUNCTION__, result); + #endif + return result; + }; + }; + + KERNEL32_DLLIMPORT static DynamicLinkLibrary^ LoadLibrary( + [InteropServices::In] System::String^ lpFileName + ); + private: + KERNEL32_DLLIMPORT static System::Boolean FreeLibrary( + [InteropServices::In] System::IntPtr hModule + ); + + public: + KERNEL32_DLLIMPORT_ANSI static System::IntPtr GetProcAddress( + [InteropServices::In] DynamicLinkLibrary^ hModule, + [InteropServices::In] System::String^ lpProcName + ); + + + + [System::Security::Permissions::SecurityPermissionAttribute(System::Security::Permissions::SecurityAction::InheritanceDemand, UnmanagedCode = true)] + ref class File + : public Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid + { + public: + File() + : Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid(true) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + }; + + protected: + [ConstrainedExecution::ReliabilityContract(ConstrainedExecution::Consistency::WillNotCorruptState, ConstrainedExecution::Cer::MayFail)] + virtual System::Boolean ReleaseHandle() override + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + System::Boolean result = CloseHandle(this->handle); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] CloseHandle result {1}",__FUNCTION__, result); + #endif + return result; + }; + }; + + KERNEL32_DLLIMPORT static File^ CreateFile( + [InteropServices::In] System::String^ lpFileName, + [InteropServices::In] ACCESS_TYPES dwDesiredAccess, + [InteropServices::In] SHARE_MODE dwShareMode, + [InteropServices::In] System::IntPtr lpSecurityAttributes, + [InteropServices::In] CREATION_DISPOSITION dwCreationDisposition, + [InteropServices::In] FLAG_AND_ATTRIBUTE dwFlagsAndAttributes, + [InteropServices::In] System::IntPtr hTemplateFile + ); + + private: + KERNEL32_DLLIMPORT static System::Boolean CloseHandle( + [InteropServices::In] System::IntPtr hObject + ); + + }; + +} +} +} diff --git a/Core/Momiji.Interop.Ks.h b/Core/Momiji.Interop.Ks.h new file mode 100644 index 0000000..f41569c --- /dev/null +++ b/Core/Momiji.Interop.Ks.h @@ -0,0 +1,882 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Interop.Ks.h + windows multi media dll importer. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Interop.Kernel32.h" +#include "Momiji.Interop.Winmm.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Interop { +namespace Ks { + +#define KSPROXY_API_DLLIMPORT WIN32_DLL_IMPORT("Ksproxy.ax") +#define KSUSER_API_DLLIMPORT WIN32_DLL_IMPORT("ksuser") + + public enum class IOCTL_KS: System::UInt32 + { + #define FILE_DEVICE_KS 0x0000002f + + #define METHOD_BUFFERED 0 + #define METHOD_IN_DIRECT 1 + #define METHOD_OUT_DIRECT 2 + #define METHOD_NEITHER 3 + + #define FILE_ANY_ACCESS 0 + #define FILE_READ_ACCESS ( 0x0001 ) // file & pipe + #define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe + + #define CTL_CODE( DeviceType, Function, Method, Access ) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) + + PROPERTY = CTL_CODE(FILE_DEVICE_KS, 0x000, METHOD_NEITHER, FILE_ANY_ACCESS), + ENABLE_EVENT = CTL_CODE(FILE_DEVICE_KS, 0x001, METHOD_NEITHER, FILE_ANY_ACCESS), + DISABLE_EVENT = CTL_CODE(FILE_DEVICE_KS, 0x002, METHOD_NEITHER, FILE_ANY_ACCESS), + METHOD = CTL_CODE(FILE_DEVICE_KS, 0x003, METHOD_NEITHER, FILE_ANY_ACCESS), + WRITE_STREAM = CTL_CODE(FILE_DEVICE_KS, 0x004, METHOD_NEITHER, FILE_WRITE_ACCESS), + READ_STREAM = CTL_CODE(FILE_DEVICE_KS, 0x005, METHOD_NEITHER, FILE_READ_ACCESS), + RESET_STATE = CTL_CODE(FILE_DEVICE_KS, 0x006, METHOD_NEITHER, FILE_ANY_ACCESS), + HANDSHAKE = CTL_CODE(FILE_DEVICE_KS, 0x007, METHOD_NEITHER, FILE_ANY_ACCESS), + + }; + + + WIN32_DLL_STRUCTLAYOUT public value struct KsReset + { + enum class ENUM: System::UInt32 + { + BEGIN, + END + }; + + ENUM Value; + + virtual System::String^ ToString() override + { + return + "value["+Value.ToString("F")+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsState + { + enum class ENUM: System::UInt32 + { + STOP, + ACQUIRE, + PAUSE, + RUN + }; + + ENUM Value; + + virtual System::String^ ToString() override + { + return + "value["+Value.ToString("F")+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPriority + { + enum class CLASS: System::UInt32 + { + NONE = 0x00000000, + LOW = 0x00000001, + NORMAL = 0x40000000, + HIGH = 0x80000000, + EXCLUSIVE = 0xFFFFFFFF, + }; + + CLASS PriorityClass; + System::UInt32 PrioritySubClass; + + virtual System::String^ ToString() override + { + return "priorityClass["+PriorityClass.ToString("F")+"] prioritySubClass["+PrioritySubClass+"]"; + } + }; + + template + WIN32_DLL_STRUCTLAYOUT public value struct KsIdentifier + { + Guiddef::Guid Set; + ID Id; + TYPE Flags; + + virtual System::String^ ToString() override + { + return + System::String::Format( + "guid[{0}] id[{1:F}] flags[{2:F}]", + Set, + Id, + Flags + ); + } + }; + + public enum class EVENT_TYPE: System::UInt32 + { + NONE = 0x00000000, + ENABLE = 0x00000001, + ONESHOT = 0x00000002, + ENABLEBUFFERED = 0x00000004, + SETSUPPORT = 0x00000100, + BASICSUPPORT = 0x00000200, + QUERYBUFFER = 0x00000400, + + TOPOLOGY = 0x10000000, + }; + + public enum class METHOD_TYPE: System::UInt32 + { + NONE = 0x00000000, + READ = 0x00000001, + WRITE = 0x00000002, + MODIFY = 0x00000003, + SOURCE = 0x00000004, + + SEND = 0x00000001, + SETSUPPORT = 0x00000100, + BASICSUPPORT = 0x00000200, + + TOPOLOGY = 0x10000000, + }; + + public enum class PROPERTY_ID: System::UInt32 + { + CINSTANCES = 0, + CTYPES, + DATAFLOW, + DATARANGES, + DATAINTERSECTION, + INTERFACES, + MEDIUMS, + COMMUNICATION, + GLOBALCINSTANCES, + NECESSARYINSTANCES, + PHYSICALCONNECTION, + CATEGORY, + NAME, + CONSTRAINEDDATARANGES, + PROPOSEDATAFORMAT, + }; + + public enum class PROPERTY_TYPE: System::UInt32 + { + NONE = 0x00000000, + GET = 0x00000001, + SET = 0x00000002, + SETSUPPORT = 0x00000100, + BASICSUPPORT = 0x00000200, + RELATIONS = 0x00000400, + SERIALIZESET = 0x00000800, + UNSERIALIZESET = 0x00001000, + SERIALIZERAW = 0x00002000, + UNSERIALIZERAW = 0x00004000, + SERIALIZESIZE = 0x00008000, + DEFAULTVALUES = 0x00010000, + + TOPOLOGY = 0x10000000, + }; + + public enum class PROPERTY_ID_CONNECTION: System::UInt32 + { + STATE = 0, + PRIORITY, + DATAFORMAT, + ALLOCATORFRAMING, + PROPOSEDATAFORMAT, + ACQUIREORDERING, + ALLOCATORFRAMING_EX, + STARTAT, + }; + + public enum class PROPERTY_ID_AUDIO: System::UInt32 + { + NONE = 0x00000000, + LATENCY = 1, + COPY_PROTECTION, + CHANNEL_CONFIG, + VOLUMELEVEL, + POSITION, + DYNAMIC_RANGE, + QUALITY, + SAMPLING_RATE, + DYNAMIC_SAMPLING_RATE, + MIX_LEVEL_TABLE, + MIX_LEVEL_CAPS, + MUX_SOURCE, + MUTE, + BASS, + MID, + TREBLE, + BASS_BOOST, + EQ_LEVEL, + NUM_EQ_BANDS, + EQ_BANDS, + AGC, + DELAY, + LOUDNESS, + WIDE_MODE, //Reserved for system use + WIDENESS, + REVERB_LEVEL, + CHORUS_LEVEL, + DEV_SPECIFIC, + DEMUX_DEST, + STEREO_ENHANCE, //Reserved for system use + MANUFACTURE_GUID, //Reserved for system use + PRODUCT_GUID, //Reserved for system use + CPU_RESOURCES, + STEREO_SPEAKER_GEOMETRY, + SURROUND_ENCODE, + _3D_INTERFACE, + PEAKMETER, + ALGORITHM_INSTANCE, + FILTER_STATE, + PREFERRED_STATUS, + PEQ_MAX_BANDS, + PEQ_NUM_BANDS, + PEQ_BAND_CENTER_FREQ, + PEQ_BAND_Q_FACTOR, + PEQ_BAND_LEVEL, + CHORUS_MODULATION_RATE, + CHORUS_MODULATION_DEPTH, + REVERB_TIME, + REVERB_DELAY_FEEDBACK, + POSITIONEX, + MIC_ARRAY_GEOMETRY, + + }; + + public enum class PROPERTY_ID_WAVE: System::UInt32 + { + COMPATIBLE_CAPABILITIES, + INPUT_CAPABILITIES, + OUTPUT_CAPABILITIES, + BUFFER, + FREQUENCY, + VOLUME, + PAN + }; + + public enum class PROPERTY_ID_TOPOLOGY: System::UInt32 + { + CATEGORIES, + NODES, + CONNECTIONS, + NAME + }; + + template + WIN32_DLL_STRUCTLAYOUT public value struct KsBasicSupport + { + TYPE Value; + + virtual System::String^ ToString() override + { + return + System::String::Format( + "value[{0:F}]", + Value + ); + } + }; + + template + WIN32_DLL_STRUCTLAYOUT public value struct KsNode + { + KsIdentifier Property; + System::UInt32 NodeId; + System::UInt32 Reserved; + + virtual System::String^ ToString() override + { + return "property["+Property.ToString()+"] nodeId["+NodeId+"]"; + } + }; + + template + WIN32_DLL_STRUCTLAYOUT public value struct KsPropertyPin + { + KsIdentifier Property; + System::UInt32 PinId; + System::UInt32 Reserved; + + virtual System::String^ ToString() override + { + return "property["+Property.ToString()+"] pinId["+PinId+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsMultipleItem + { + System::UInt32 Size; + System::UInt32 Count; + + virtual System::String^ ToString() override + { + return "size["+Size+"] count["+Count+"]"; + } + }; + + template + WIN32_DLL_STRUCTLAYOUT public value struct KsPropertyPinAndMultipleItem + { + KsPropertyPin PropertyPin; + KsMultipleItem MultipleItem; + + virtual System::String^ ToString() override + { + return "propertyPin["+PropertyPin.ToString()+"] multipleItem["+MultipleItem.ToString()+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsCInstances + { + System::UInt32 PossibleCount; + System::UInt32 CurrentCount; + + virtual System::String^ ToString() override + { + return "possibleCount["+PossibleCount+"] currentCount["+CurrentCount+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPinDataFlow + { + enum class ENUM: System::UInt32 + { + NONE, + IN, + OUT + }; + + ENUM Value; + + virtual System::String^ ToString() override + { + return + "value["+Value.ToString("F")+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsDataFormat + { + System::UInt32 FormatSize; + System::UInt32 Flags; + System::UInt32 SampleSize; + System::UInt32 Reserved; + Guiddef::Guid MajorFormat; + Guiddef::Guid SubFormat; + Guiddef::Guid Specifier; + + virtual System::String^ ToString() override + { + return + "formatSize["+FormatSize+"] flags["+Flags+"] sampleSize["+SampleSize+"] majorFormat["+MajorFormat+"] subFormat["+SubFormat+"] specifier["+Specifier+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPinCommunication + { + enum class ENUM: System::UInt32 + { + NONE, + SINK, + SOURCE, + BOTH, + BRIDGE, + }; + + ENUM Value; + + virtual System::String^ ToString() override + { + return + "value["+Value.ToString("F")+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPinInterface + { + enum class ID: System::UInt32 + { + STANDARD_STREAMING, + STANDARD_LOOPED_STREAMING, + STANDARD_CONTROL, //Reserved for system use + + }; + + Guiddef::Guid Set; + ID Id; + System::UInt32 Flags; + + virtual System::String^ ToString() override + { + return "guid["+Set+"] id["+Id.ToString("F")+"] flags["+Flags+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPinInterfaceMedia + { + enum class ID: System::UInt32 + { + MEDIA_MUSIC, //Reserved for system use + MEDIA_WAVE_BUFFERED, //Reserved for system use + MEDIA_WAVE_QUEUED, + }; + + Guiddef::Guid Set; + ID Id; + System::UInt32 Flags; + + virtual System::String^ ToString() override + { + return "guid["+Set+"] id["+Id.ToString("F")+"] flags["+Flags+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPinMedium + { + enum class ID: System::UInt32 + { + STANDARD_ANYINSTANCE, + //STANDARD_DEVIO = STANDARD_ANYINSTANCE, + + }; + + Guiddef::Guid Set; + ID Id; + System::UInt32 Flags; + + virtual System::String^ ToString() override + { + return "guid["+Set+"] id["+Id.ToString("F")+"] flags["+Flags+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsDataFormatWaveFormatEx + { + KsDataFormat DataFormat; + Interop::Winmm::WaveFormatEx^ wfe; + + virtual System::String^ ToString() override + { + return + "dataFormat["+DataFormat.ToString()+"] wfe["+wfe->ToString()+"]"; + } + }; + + + // DirectSound buffer description + WIN32_DLL_STRUCTLAYOUT public value struct KsDSoundBufferDesc + { + System::UInt32 Flags; + System::UInt32 Control; + Interop::Winmm::WaveFormatEx^ wfe; + }; + + // DirectSound format + WIN32_DLL_STRUCTLAYOUT public value struct KsDataFormatDSound + { + KsDataFormat DataFormat; + KsDSoundBufferDesc BufferDesc; + + virtual System::String^ ToString() override + { + return + "dataFormat["+DataFormat.ToString()+"] bufferDesc["+BufferDesc.ToString()+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsDataRangeAudio + { + KsDataFormat DataRange; + System::UInt32 MaximumChannels; + System::UInt32 MinimumBitsPerSample; + System::UInt32 MaximumBitsPerSample; + System::UInt32 MinimumSampleFrequency; + System::UInt32 MaximumSampleFrequency; + + virtual System::String^ ToString() override + { + return + "dataRange["+DataRange.ToString()+"] maximumChannels["+MaximumChannels+"] minimumBitsPerSample["+MinimumBitsPerSample+"] maximumBitsPerSample["+MaximumBitsPerSample+"] MinimumSampleFrequency["+MinimumSampleFrequency+"] MaximumSampleFrequency["+MaximumSampleFrequency+"]"; + } + }; + + template + WIN32_DLL_STRUCTLAYOUT public value struct KsPropertyDesctiption + { + System::UInt32 AccessFlags; + System::UInt32 DescriptionSize; + KsIdentifier PropTypeSet; + System::UInt32 MembersListCount; + System::UInt32 Reserved; + }; + + + WIN32_DLL_STRUCTLAYOUT public value struct KsPropertyMembersHeader + { + enum class MEMBERS_FLAGS: System::UInt32 + { + NONE = 0x00000000, + RANGES = 0x00000001, + STEPPEDRANGES = 0x00000002, + VALUES = 0x00000003, + }; + + enum class FLAGS: System::UInt32 + { + NONE = 0x00000000, + DEFAULT = 0x00000001, + BASICSUPPORT_MULTICHANNEL = 0x00000002, + BASICSUPPORT_UNIFORM = 0x00000004, + }; + + MEMBERS_FLAGS MembersFlags; + System::UInt32 MembersSize; + System::UInt32 MembersCount; + FLAGS Flags; + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPropertyBoundsLong + { + System::Int32 Minimum; + System::Int32 Maximum; + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPropertyBoundsLongLong + { + System::Int64 Minimum; + System::Int64 Maximum; + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPropertySteppingLong + { + System::UInt32 SteppingDelta; + System::UInt32 Reserved; + KsPropertyBoundsLong Bounds; + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPropertySteppingLongLong + { + System::UInt64 SteppingDelta; + KsPropertyBoundsLongLong Bounds; + }; + + + //この状態で一度に取得する手段は無い?? + /*WIN32_DLL_STRUCTLAYOUT */public value struct KsPinDescriptor + { + array^ Interfaces; + array^ Mediums; + array^ DataRanges; + KsPinDataFlow::ENUM DataFlow; + KsPinCommunication::ENUM Communication; + Guiddef::Guid Category; + Guiddef::Guid Name; + array^ ConstrainedDataRanges; + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsPinConnect + { + KsPinInterface Interface; + KsPinMedium Medium; + System::UInt32 PinId; + System::IntPtr PinToHandle; + KsPriority Priority; + KsDataFormat DataFormat; + Interop::Winmm::WaveFormatExtensible WaveFormat; + + virtual System::String^ ToString() override + { + return "interface["+Interface.ToString()+"] medium["+Medium.ToString()+"] pinId["+PinId+"] pinToHandle["+PinToHandle+"] priority["+Priority.ToString()+"] dataFormat["+DataFormat.ToString()+"] waveFormat["+WaveFormat.ToString()+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsName + { + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=1024)] + System::String^ Name; + + virtual System::String^ ToString() override + { + return + "name["+Name+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsTime + { + System::Int64 Time; + System::UInt32 Numerator; + System::UInt32 Denominator; + + virtual System::String^ ToString() override + { + return + "time["+Time+"] numerator["+Numerator+"] denominator["+Denominator+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsStreamHeader + { + System::UInt32 Size; + System::UInt32 TypeSpecificFlags; + KsTime PresentationTime; + System::Int64 Duration; + System::UInt32 FrameExtent; + System::UInt32 DataUsed; + System::IntPtr Data; + System::UInt32 OptionsFlags; + System::UInt32 Reserved; + + virtual System::String^ ToString() override + { + return + "size["+Size+"] typeSpecificFlags["+TypeSpecificFlags+"] presentationTime["+PresentationTime.ToString()+"] duration["+Duration+"] frameExtent["+FrameExtent+"] dataUsed["+DataUsed+"] data["+Data+"] optionsFlags["+OptionsFlags+"] reserved["+Reserved+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct KsTopologyConnection + { + System::UInt32 FromNode; + System::UInt32 FromNodePin; + System::UInt32 ToNode; + System::UInt32 ToNodePin; + + virtual System::String^ ToString() override + { + return + "fromNode["+FromNode+"] fromNodePin["+FromNodePin+"] toNode["+ToNode+"] toNodePin["+ToNodePin+"]"; + } + }; + + + + + + public value class Function + { + public: + /* + KSDDKAPI + HRESULT + WINAPI + KsResolveRequiredAttributes( + __in PKSDATARANGE DataRange, + __in_opt PKSMULTIPLE_ITEM Attributes + ); + + KSDDKAPI + HRESULT + WINAPI + KsOpenDefaultDevice( + __in REFGUID Category, + __in ACCESS_MASK Access, + __out PHANDLE DeviceHandle + ); + */ + + + KERNEL32_DLLIMPORT static System::Boolean DeviceIoControl( + [InteropServices::In] Interop::Kernel32::Function::File^ hDevice, + [InteropServices::In] IOCTL_KS dwIoControlCode, + [InteropServices::In] System::IntPtr lpInBuffer, + [InteropServices::In] System::UInt32 nInBufferSize, + [InteropServices::In] System::IntPtr lpOutBuffer, + [InteropServices::In] System::UInt32 nOutBufferSize, + [InteropServices::Out] System::UInt32% lpBytesReturned, + [InteropServices::In, InteropServices::Out] System::Threading::NativeOverlapped% lpOverlapped + ); + + KERNEL32_DLLIMPORT static System::Boolean GetOverlappedResult( + [InteropServices::In] Interop::Kernel32::Function::File^ hDevice, + [InteropServices::In, InteropServices::Out] System::Threading::NativeOverlapped% lpOverlapped, + [InteropServices::Out] System::UInt32% lpNumberOfBytesTransferred, + [InteropServices::In] System::Boolean bWait + ); + + KSPROXY_API_DLLIMPORT static System::UInt32 KsSynchronousDeviceControl( + [InteropServices::In] Interop::Kernel32::Function::File^ hDevice, + [InteropServices::In] IOCTL_KS dwIoControlCode, + [InteropServices::In] System::IntPtr lpInBuffer, + [InteropServices::In] System::UInt32 nInBufferSize, + [InteropServices::In] System::IntPtr lpOutBuffer, + [InteropServices::In] System::UInt32 nOutBufferSize, + [InteropServices::Out] System::UInt32% lpBytesReturned + ); + + KSUSER_API_DLLIMPORT static System::UInt32 KsCreatePin( + [InteropServices::In] Interop::Kernel32::Function::File^ FilterHandle, + [InteropServices::In] KsPinConnect% Connect, + [InteropServices::In] Interop::Kernel32::ACCESS_TYPES DesiredAccess, + [InteropServices::Out] Interop::Kernel32::Function::File^% ConnectionHandle + ); + + + + + + + /* + KSDDKAPI + HRESULT + WINAPI + KsGetMultiplePinFactoryItems( + __in HANDLE FilterHandle, + __in ULONG PinFactoryId, + __in ULONG PropertyId, + __deref_out PVOID* Items + ); + KSDDKAPI + HRESULT + WINAPI + KsGetMediaTypeCount( + __in HANDLE FilterHandle, + __in ULONG PinFactoryId, + __out ULONG* MediaTypeCount + ); + KSDDKAPI + HRESULT + WINAPI + KsGetMediaType( + __in int Position, + __out AM_MEDIA_TYPE* AmMediaType, + __in HANDLE FilterHandle, + __in ULONG PinFactoryId + ); + */ + }; + + + public ref class StaticKs sealed + { + public: + static initonly Guiddef::Guid CATEGORY_AUDIO = Guiddef::Guid::Regist("6994AD04-93EF-11D0-A3CC-00A0C9223196", "StaticKs::CATEGORY_AUDIO"); + static initonly Guiddef::Guid CATEGORY_CAPTURE = Guiddef::Guid::Regist("65E8773D-8F56-11D0-A3B9-00A0C9223196", "StaticKs::CATEGORY_CAPTURE"); + static initonly Guiddef::Guid CATEGORY_RENDER = Guiddef::Guid::Regist("65E8773E-8F56-11D0-A3B9-00A0C9223196", "StaticKs::CATEGORY_RENDER"); + + static initonly Guiddef::Guid MEDIATYPE_Audio = Guiddef::Guid::Regist("73647561-0000-0010-8000-00aa00389b71", "StaticKs::MEDIATYPE_Audio"); + + static initonly Guiddef::Guid SUBTYPE_WAVEFORMATEX = Guiddef::Guid::Regist("00000000-0000-0010-8000-00aa00389b71", "StaticKs::SUBTYPE_WAVEFORMATEX"); + static initonly Guiddef::Guid SUBTYPE_PCM = Guiddef::Guid::Regist("00000001-0000-0010-8000-00aa00389b71", "StaticKs::SUBTYPE_PCM"); + static initonly Guiddef::Guid SUBTYPE_IEEE_FLOAT = Guiddef::Guid::Regist("00000003-0000-0010-8000-00aa00389b71", "StaticKs::SUBTYPE_IEEE_FLOAT"); + static initonly Guiddef::Guid SUBTYPE_ANALOG = Guiddef::Guid::Regist("6dba3190-67bd-11cf-a0f7-0020afd156e4", "StaticKs::SUBTYPE_ANALOG"); + + static initonly Guiddef::Guid SPECIFIER_VC_ID = Guiddef::Guid::Regist("AD98D184-AAC3-11D0-A41C-00A0C9223196", "StaticKs::SPECIFIER_VC_ID"); + static initonly Guiddef::Guid SPECIFIER_WAVEFORMATEX = Guiddef::Guid::Regist("05589f81-c356-11ce-bf01-00aa0055595a", "StaticKs::SPECIFIER_WAVEFORMATEX"); + static initonly Guiddef::Guid SPECIFIER_DSOUND = Guiddef::Guid::Regist("518590a2-a184-11d0-8522-00c04fd9baf3", "StaticKs::SPECIFIER_DSOUND"); + + static initonly Guiddef::Guid INTERFACESETID_Standard = Guiddef::Guid::Regist("1A8766A0-62CE-11CF-A5D6-28DB04C10000", "StaticKs::INTERFACESETID_Standard"); + static initonly Guiddef::Guid INTERFACESETID_FileIo = Guiddef::Guid::Regist("8C6F932C-E771-11D0-B8FF-00A0C9223196", "StaticKs::INTERFACESETID_FileIo"); + static initonly Guiddef::Guid INTERFACESETID_Media = Guiddef::Guid::Regist("3A13EB40-30A7-11D0-A5D6-28DB04C10000", "StaticKs::INTERFACESETID_Media"); + + static initonly Guiddef::Guid MEDIUMSETID_Standard = Guiddef::Guid::Regist("4747B320-62CE-11CF-A5D6-28DB04C10000", "StaticKs::MEDIUMSETID_Standard"); + + static initonly Guiddef::Guid PROPSETID_Topology = Guiddef::Guid::Regist("720D4AC0-7533-11D0-A5D6-28DB04C10000", "StaticKs::PROPSETID_Topology"); + static initonly Guiddef::Guid PROPSETID_Pin = Guiddef::Guid::Regist("8C134960-51AD-11CF-878A-94F801C10000", "StaticKs::PROPSETID_Pin"); + static initonly Guiddef::Guid PROPSETID_Connection = Guiddef::Guid::Regist("1D58C920-AC9B-11CF-A5D6-28DB04C10000", "StaticKs::PROPSETID_Connection"); + static initonly Guiddef::Guid PROPSETID_Audio = Guiddef::Guid::Regist("45FFAAA0-6E1B-11D0-BCF2-444553540000", "StaticKs::PROPSETID_Audio"); + static initonly Guiddef::Guid PROPSETID_Wave = Guiddef::Guid::Regist("924e54b0-630f-11cf-ada7-08003e30494a", "StaticKs::PROPSETID_Wave"); + + + }; + +/* +typedef enum { + KSPROPERTY_WAVE_COMPATIBLE_CAPABILITIES, + KSPROPERTY_WAVE_INPUT_CAPABILITIES, + KSPROPERTY_WAVE_OUTPUT_CAPABILITIES, + KSPROPERTY_WAVE_BUFFER, + KSPROPERTY_WAVE_FREQUENCY, + KSPROPERTY_WAVE_VOLUME, + KSPROPERTY_WAVE_PAN +} KSPROPERTY_WAVE; + +typedef struct { + ULONG ulDeviceType; +} KSWAVE_COMPATCAPS, *PKSWAVE_COMPATCAPS; + +#define KSWAVE_COMPATCAPS_INPUT 0x00000000 +#define KSWAVE_COMPATCAPS_OUTPUT 0x00000001 + +typedef struct { + ULONG MaximumChannelsPerConnection; + ULONG MinimumBitsPerSample; + ULONG MaximumBitsPerSample; + ULONG MinimumSampleFrequency; + ULONG MaximumSampleFrequency; + ULONG TotalConnections; + ULONG ActiveConnections; +} KSWAVE_INPUT_CAPABILITIES, *PKSWAVE_INPUT_CAPABILITIES; + +typedef struct { + ULONG MaximumChannelsPerConnection; + ULONG MinimumBitsPerSample; + ULONG MaximumBitsPerSample; + ULONG MinimumSampleFrequency; + ULONG MaximumSampleFrequency; + ULONG TotalConnections; + ULONG StaticConnections; + ULONG StreamingConnections; + ULONG ActiveConnections; + ULONG ActiveStaticConnections; + ULONG ActiveStreamingConnections; + ULONG Total3DConnections; + ULONG Static3DConnections; + ULONG Streaming3DConnections; + ULONG Active3DConnections; + ULONG ActiveStatic3DConnections; + ULONG ActiveStreaming3DConnections; + ULONG TotalSampleMemory; + ULONG FreeSampleMemory; + ULONG LargestFreeContiguousSampleMemory; +} KSWAVE_OUTPUT_CAPABILITIES, *PKSWAVE_OUTPUT_CAPABILITIES; + +typedef struct { + LONG LeftAttenuation; + LONG RightAttenuation; +} KSWAVE_VOLUME, *PKSWAVE_VOLUME; + +#define KSWAVE_BUFFER_ATTRIBUTEF_LOOPING 0x00000001 +#define KSWAVE_BUFFER_ATTRIBUTEF_STATIC 0x00000002 + +typedef struct { + ULONG Attributes; + ULONG BufferSize; + PVOID BufferAddress; +} KSWAVE_BUFFER, *PKSWAVE_BUFFER; + + + +*/ + + +} +} +} diff --git a/Core/Momiji.Interop.MMDeviceAPI.h b/Core/Momiji.Interop.MMDeviceAPI.h new file mode 100644 index 0000000..c31c52f --- /dev/null +++ b/Core/Momiji.Interop.MMDeviceAPI.h @@ -0,0 +1,424 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Interop.MMDeviceAPI.h + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Interop.Guiddef.h" +#include "Momiji.Interop.PropIdl.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Interop { +namespace MMDeviceAPI { + + //FunctionDiscoveryKeys_devpkey.h + public ref class FunctionDiscoveryKeys_devpkey sealed + { + public: + static initonly Guiddef::Guid PKEY_Device = Guiddef::Guid::Regist("a45c254e-df1c-4efd-8020-67d146a850e0", "FunctionDiscoveryKeys_devpkey::PKEY_Device"); + + }; + /* +// +// Device properties +// These PKEYs correspond to the old setupapi SPDRP_XXX properties +// +DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_HardwareIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_CompatibleIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 4); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_Service, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 6); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_Class, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 9); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_ClassGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 10); // DEVPROP_TYPE_GUID +DEFINE_PROPERTYKEY(PKEY_Device_Driver, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 11); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_ConfigFlags, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 12); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_Manufacturer, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_LocationInfo, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 15); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_PDOName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 16); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_Capabilities, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 17); // DEVPROP_TYPE_UNINT32 +DEFINE_PROPERTYKEY(PKEY_Device_UINumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 18); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_UpperFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 19); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_LowerFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 20); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_BusTypeGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 21); // DEVPROP_TYPE_GUID +DEFINE_PROPERTYKEY(PKEY_Device_LegacyBusType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 22); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_BusNumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 23); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_EnumeratorName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 24); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_Security, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR +DEFINE_PROPERTYKEY(PKEY_Device_SecuritySDS, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING +DEFINE_PROPERTYKEY(PKEY_Device_DevType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 27); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_Exclusive, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 28); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_Characteristics, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 29); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_Address, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 30); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_UINumberDescFormat, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 31); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_PowerData, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 32); // DEVPROP_TYPE_BINARY +DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicy, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 33); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyDefault, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 34); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyOverride, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 35); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_InstallState, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 36); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_LocationPaths, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 37); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_BaseContainerId, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 38); // DEVPROP_TYPE_GUID + +// +// Device properties +// These PKEYs correspond to a device's status and problem code +// +DEFINE_PROPERTYKEY(PKEY_Device_DevNodeStatus, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 2); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_ProblemCode, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 3); // DEVPROP_TYPE_UINT32 + +// +// Device properties +// These PKEYs correspond to device relations +// +DEFINE_PROPERTYKEY(PKEY_Device_EjectionRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 4); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_RemovalRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 5); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_PowerRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 6); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_BusRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 7); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_Parent, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_Children, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 9); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_Siblings, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 10); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_TransportRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 11); // DEVPROP_TYPE_STRING_LIST + +// +// Other Device properties +// +DEFINE_PROPERTYKEY(PKEY_Device_Reported, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 2); // DEVPROP_TYPE_BOOLEAN +DEFINE_PROPERTYKEY(PKEY_Device_Legacy, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 3); // DEVPROP_TYPE_BOOLEAN +DEFINE_PROPERTYKEY(PKEY_Device_InstanceId, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 256); // DEVPROP_TYPE_STRING + +DEFINE_PROPERTYKEY(PKEY_Device_ContainerId, 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2); // DEVPROP_TYPE_GUID + +DEFINE_PROPERTYKEY(PKEY_Device_ModelId, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 2); // DEVPROP_TYPE_GUID + +DEFINE_PROPERTYKEY(PKEY_Device_FriendlyNameAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 3); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_ManufacturerAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 4); // DEVPROP_TYPE_UINT32 + +DEFINE_PROPERTYKEY(PKEY_Device_PresenceNotForDevice, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 5); // DEVPROP_TYPE_BOOLEAN + + +DEFINE_PROPERTYKEY(PKEY_Numa_Proximity_Domain, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 1); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_DHP_Rebalance_Policy, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 2); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_Numa_Node, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 3); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING + +DEFINE_PROPERTYKEY(PKEY_Device_InstallInProgress, 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 9); // DEVPROP_TYPE_BOOLEAN + +// +// Device driver properties +// +DEFINE_PROPERTYKEY(PKEY_Device_DriverDate, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 2); // DEVPROP_TYPE_FILETIME +DEFINE_PROPERTYKEY(PKEY_Device_DriverVersion, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_DriverDesc, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 4); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_DriverInfPath, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 5); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSection, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 6); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSectionExt, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 7); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_MatchingDeviceId, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 8); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_DriverProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 9); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_DriverPropPageProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 10); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_DriverCoInstallers, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 11); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerTags, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 12); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerExceptions, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 13); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_DriverRank, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 14); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_DriverLogoLevel, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 15); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_Device_NoConnectSound, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 17); // DEVPROP_TYPE_BOOLEAN +DEFINE_PROPERTYKEY(PKEY_Device_GenericDriverInstalled, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 18); // DEVPROP_TYPE_BOOLEAN +DEFINE_PROPERTYKEY(PKEY_Device_AdditionalSoftwareRequested, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 19);// DEVPROP_TYPE_BOOLEAN + +// +// Device safe-removal properties +// +DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequired, 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 2); // DEVPROP_TYPE_BOOLEAN +DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequiredOverride, 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 3);// DEVPROP_TYPE_BOOLEAN + + +// +// Device properties that were set by the driver package that was installed +// on the device. +// +DEFINE_PROPERTYKEY(PKEY_DrvPkg_Model, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 2); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DrvPkg_VendorWebSite, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 3); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DrvPkg_DetailedDescription, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 4); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DrvPkg_DocumentationLink, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 5); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DrvPkg_Icon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 6); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_DrvPkg_BrandingIcon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 7); // DEVPROP_TYPE_STRING_LIST + +// +// Device setup class properties +// These PKEYs correspond to the old setupapi SPCRP_XXX properties +// +DEFINE_PROPERTYKEY(PKEY_DeviceClass_UpperFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 19); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_DeviceClass_LowerFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 20); // DEVPROP_TYPE_STRING_LIST +DEFINE_PROPERTYKEY(PKEY_DeviceClass_Security, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR +DEFINE_PROPERTYKEY(PKEY_DeviceClass_SecuritySDS, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING +DEFINE_PROPERTYKEY(PKEY_DeviceClass_DevType, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 27); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_DeviceClass_Exclusive, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 28); // DEVPROP_TYPE_UINT32 +DEFINE_PROPERTYKEY(PKEY_DeviceClass_Characteristics, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 29); // DEVPROP_TYPE_UINT32 + +// +// Device setup class properties +// These PKEYs correspond to registry values under the device class GUID key +// +DEFINE_PROPERTYKEY(PKEY_DeviceClass_Name, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 2); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassName, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 3); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DeviceClass_Icon, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 4); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassInstaller, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 5); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DeviceClass_PropPageProvider, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 6); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoInstallClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 7); // DEVPROP_TYPE_BOOLEAN +DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoDisplayClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 8); // DEVPROP_TYPE_BOOLEAN +DEFINE_PROPERTYKEY(PKEY_DeviceClass_SilentInstall, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 9); // DEVPROP_TYPE_BOOLEAN +DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoUseClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 10); // DEVPROP_TYPE_BOOLEAN +DEFINE_PROPERTYKEY(PKEY_DeviceClass_DefaultService, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 11); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DeviceClass_IconPath, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 12); // DEVPROP_TYPE_STRING_LIST + +// +// Other Device setup class properties +// +DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassCoInstallers, 0x713d1703, 0xa2e2, 0x49f5, 0x92, 0x14, 0x56, 0x47, 0x2e, 0xf3, 0xda, 0x5c, 2); // DEVPROP_TYPE_STRING_LIST + +// +// Device interface properties +// +DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 2); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Enabled, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 3); // DEVPROP_TYPE_BOOLEAN +DEFINE_PROPERTYKEY(PKEY_DeviceInterface_ClassGuid, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 4); // DEVPROP_TYPE_GUID + +// +// Device interface class properties +// +DEFINE_PROPERTYKEY(PKEY_DeviceInterfaceClass_DefaultInterface, 0x14c83a99, 0x0b3f, 0x44b7, 0xbe, 0x4c, 0xa1, 0x78, 0xd3, 0x99, 0x05, 0x64, 2); // DEVPROP_TYPE_STRING + + +*/ + + public enum class CLSCTX: System::UInt32 + { + ALL = + 0x1 // CLSCTX_INPROC_SERVER + | 0x2 // CLSCTX_INPROC_HANDLER + | 0x4 // CLSCTX_LOCAL_SERVER + | 0x10 // CLSCTX_REMOTE_SERVER + }; + + //ObjBase.h + public enum class STGM: System::UInt32 + { + READ = 0x00000000L, + WRITE = 0x00000001L, + READWRITE = 0x00000002L, + }; + + public enum class DEVICE_STATE: System::UInt32 + { + ACTIVE = 0x00000001, + DISABLED = 0x00000002, + NOTPRESENT = 0x00000004, + UNPLUGGED = 0x00000008, + + MASK_ALL = 0x0000000f, + }; + + [ + InteropServices::ComImport, + System::Security::SuppressUnmanagedCodeSecurity, + InteropServices::Guid("D666063F-1587-4E43-81F1-B948E807363F"), + InteropServices::InterfaceType(InteropServices::ComInterfaceType::InterfaceIsIUnknown), + InteropServices::TypeLibType(InteropServices::TypeLibTypeFlags::FNonExtensible) + ] + public interface class IMMDevice + { + void Activate( + [InteropServices::In] Guiddef::Guid^ iid, + [InteropServices::In] CLSCTX dwClsCtx, + [InteropServices::In] PropIdl::PROPVARIANT^ pActivationParams, + [InteropServices::Out] System::IntPtr% ppInterface + ); + + void OpenPropertyStore( + [InteropServices::In] STGM stgmAccess, + [InteropServices::Out][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] PropIdl::IPropertyStore^% ppProperties + ); + + void GetId( + [InteropServices::Out][InteropServices::MarshalAs(InteropServices::UnmanagedType::LPWStr)] System::String^% ppstrId + ); + + void GetState( + [InteropServices::Out] DEVICE_STATE% pdwState + ); + }; + + public enum class EDataFlow: System::UInt32 { + eRender, + eCapture, + eAll, + EDataFlow_enum_count + }; + + public enum class ERole: System::UInt32 + { + eConsole, + eMultimedia, + eCommunications, + ERole_enum_count + }; + + [ + InteropServices::ComImport, + System::Security::SuppressUnmanagedCodeSecurity, + InteropServices::Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), + InteropServices::InterfaceType(InteropServices::ComInterfaceType::InterfaceIsIUnknown), + InteropServices::TypeLibType(InteropServices::TypeLibTypeFlags::FNonExtensible) + ] + public interface class IMMDeviceCollection + { + void GetCount( + [InteropServices::Out] System::UInt32% pcDevices + ); + + void Item( + [InteropServices::In] System::UInt32 nDevice, + [InteropServices::Out][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMDevice^% ppDevice + ); + }; + + [ + InteropServices::ComImport, + System::Security::SuppressUnmanagedCodeSecurity, + InteropServices::Guid("7991EEC9-7E89-4D85-8390-6C703CEC60C0"), + InteropServices::InterfaceType(InteropServices::ComInterfaceType::InterfaceIsIUnknown), + InteropServices::TypeLibType(InteropServices::TypeLibTypeFlags::FNonExtensible) + ] + public interface class IMMNotificationClient + { + void OnDeviceStateChanged( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::LPWStr)] System::String^ pwstrDeviceId, + [InteropServices::In] System::UInt32 dwNewState + ); + + void OnDeviceAdded( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::LPWStr)] System::String^ pwstrDeviceId + ); + + void OnDeviceRemoved( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::LPWStr)] System::String^ pwstrDeviceId + ); + + void OnDefaultDeviceChanged( + [InteropServices::In] EDataFlow flow, + [InteropServices::In] ERole role, + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::LPWStr)] System::String^ pwstrDefaultDeviceId + ); + + void OnPropertyValueChanged( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::LPWStr)] System::String^ pwstrDeviceId, + [InteropServices::In] PropIdl::PROPERTYKEY^ key + ); + }; + + [ + InteropServices::ComImport, + System::Security::SuppressUnmanagedCodeSecurity, + InteropServices::Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), + InteropServices::InterfaceType(InteropServices::ComInterfaceType::InterfaceIsIUnknown), + InteropServices::TypeLibType(InteropServices::TypeLibTypeFlags::FNonExtensible) + ] + public interface class IMMDeviceEnumerator + { + void EnumAudioEndpoints( + [InteropServices::In] EDataFlow dataFlow, + [InteropServices::In] System::UInt32 dwStateMask, + [InteropServices::Out][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMDeviceCollection^% ppDevices + ); + + void GetDefaultAudioEndpoint( + [InteropServices::In] EDataFlow dataFlow, + [InteropServices::In] ERole role, + [InteropServices::Out][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMDevice^% ppEndpoint + ); + + void GetDevice( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::LPWStr)] System::String^ pwstrId, + [InteropServices::Out][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMDevice^% ppDevice + ); + + void RegisterEndpointNotificationCallback( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMNotificationClient^ pClient + ); + + void UnregisterEndpointNotificationCallback( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMNotificationClient^ pClient + ); + }; + + + ref class MMDeviceEnumeratorClass; + [ + InteropServices::ComImport, + InteropServices::CoClass(MMDeviceEnumeratorClass::typeid), + InteropServices::Guid("A95664D2-9614-4F35-A746-DE8DB63617E6") + ] + public interface class MMDeviceEnumerator: IMMDeviceEnumerator {}; + + [ + InteropServices::ComImport, + InteropServices::ClassInterface(InteropServices::ClassInterfaceType::None), + InteropServices::Guid("BCDE0395-E52F-467C-8E3D-C4579291692E"), + InteropServices::TypeLibType(InteropServices::TypeLibTypeFlags::FCanCreate) + ] + public ref class MMDeviceEnumeratorClass : MMDeviceEnumerator, IMMDeviceEnumerator + { + public: + [CompilerServices::MethodImpl(CompilerServices::MethodImplOptions::InternalCall)] + virtual void EnumAudioEndpoints( + [InteropServices::In] EDataFlow dataFlow, + [InteropServices::In] System::UInt32 dwStateMask, + [InteropServices::Out][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMDeviceCollection^% ppDevices + ); + + [CompilerServices::MethodImpl(CompilerServices::MethodImplOptions::InternalCall)] + virtual void GetDefaultAudioEndpoint( + [InteropServices::In] EDataFlow dataFlow, + [InteropServices::In] ERole role, + [InteropServices::Out][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMDevice^% ppEndpoint + ); + + [CompilerServices::MethodImpl(CompilerServices::MethodImplOptions::InternalCall)] + virtual void GetDevice( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::LPWStr)] System::String^ pwstrId, + [InteropServices::Out][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMDevice^% ppDevice + ); + + [CompilerServices::MethodImpl(CompilerServices::MethodImplOptions::InternalCall)] + virtual void RegisterEndpointNotificationCallback( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMNotificationClient^ pClient + ); + + [CompilerServices::MethodImpl(CompilerServices::MethodImplOptions::InternalCall)] + virtual void UnregisterEndpointNotificationCallback( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::Interface)] IMMNotificationClient^ pClient + ); + }; + +} +} +} diff --git a/Core/Momiji.Interop.PropIdl.h b/Core/Momiji.Interop.PropIdl.h new file mode 100644 index 0000000..ab27a07 --- /dev/null +++ b/Core/Momiji.Interop.PropIdl.h @@ -0,0 +1,1718 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Interop.PropIdl.h + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Interop.Guiddef.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Interop { +namespace PropIdl { + + //Propsys.h + WIN32_DLL_STRUCTLAYOUT public ref struct PROPERTYKEY + { + public: + Guiddef::Guid fmtid; + System::UInt32 pid; + + virtual System::String^ ToString() override sealed + { + return + "fmtid["+fmtid+"] pid["+pid+"]"; + } + PROPERTYKEY() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + ~PROPERTYKEY() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + }; + + public enum class VT : System::UInt16 + { + EMPTY = 0, + NULL = 1, + I2 = 2, + I4 = 3, + R4 = 4, + R8 = 5, + CY = 6, + DATE = 7, + BSTR = 8, + DISPATCH = 9, + ERROR = 10, + BOOL = 11, + VARIANT = 12, + UNKNOWN = 13, + DECIMAL = 14, + I1 = 16, + UI1 = 17, + UI2 = 18, + UI4 = 19, + I8 = 20, + UI8 = 21, + INT = 22, + UINT = 23, + VOID = 24, + HRESULT = 25, + PTR = 26, + SAFEARRAY = 27, + CARRAY = 28, + USERDEFINED = 29, + LPSTR = 30, + LPWSTR = 31, + RECORD = 36, + INT_PTR = 37, + UINT_PTR = 38, + FILETIME = 64, + BLOB = 65, + STREAM = 66, + STORAGE = 67, + STREAMED_OBJECT = 68, + STORED_OBJECT = 69, + BLOB_OBJECT = 70, + CF = 71, + CLSID = 72, + VERSIONED_STREAM = 73, + BSTR_BLOB = 0xfff, + VECTOR = 0x1000, + ARRAY = 0x2000, + BYREF = 0x4000, + RESERVED = 0x8000, + ILLEGAL = 0xffff, + ILLEGALMASKED = 0xfff, + TYPEMASK = 0xfff + }; + + + WIN32_DLL_STRUCTLAYOUT public ref struct BLOB + { + System::UInt32 cbSize; + array^ pBlobData; + + virtual System::String^ ToString() override sealed + { + return "vt["+cbSize.ToString()+"] wReserved1["+pBlobData->ToString()+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public ref struct PROPVARIANT + { + VT vt; + System::UInt16 wReserved1; + System::UInt16 wReserved2; + System::UInt16 wReserved3; + + System::Object^ value; + + virtual System::String^ ToString() override sealed + { + return "vt["+vt.ToString()+"] wReserved1["+wReserved1+"] wReserved2["+wReserved2+"] wReserved3["+wReserved3+"] value["+value+"]"; + } + PROPVARIANT() + { + #ifdef _DEBUG +// System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + ~PROPVARIANT() + { + #ifdef _DEBUG +// System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + }; + + + public ref class PROPVARIANTMarshaler : InteropServices::ICustomMarshaler + { + private: + static PROPVARIANTMarshaler^ instance; + public: + virtual System::Object^ MarshalNativeToManaged(System::IntPtr val) + { + #ifdef _DEBUG +// System::Console::WriteLine("[{0}][val:{1}]",__FUNCTION__, val); + #endif + auto obj = gcnew PROPVARIANT(); + + obj->vt = safe_cast(InteropServices::Marshal::ReadInt16(val, 0)); + obj->wReserved1 = InteropServices::Marshal::ReadInt16(val, 2); + obj->wReserved2 = InteropServices::Marshal::ReadInt16(val, 4); + obj->wReserved3 = InteropServices::Marshal::ReadInt16(val, 6); + + switch(obj->vt) { + + //EMPTY = 0, + //NULL = 1, + + case VT::I2 : + { + obj->value = InteropServices::Marshal::ReadInt16(val, 8); + break; + } + + case VT::I4 : + { + obj->value = InteropServices::Marshal::ReadInt32(val, 8); + break; + } + + //R4 = 4, + //R8 = 5, + //CY = 6, + //DATE = 7, + //BSTR = 8, + //DISPATCH = 9, + //ERROR = 10, + //BOOL = 11, + //VARIANT = 12, + //UNKNOWN = 13, + //DECIMAL = 14, + + //I1 = 16, + //UI1 = 17, + //UI2 = 18, + + case VT::UI4 : + { + auto temp = gcnew array(4); + auto ptr = val + 8; + InteropServices::Marshal::Copy(ptr, temp, 0, 4); + obj->value = System::BitConverter::ToUInt32(temp, 0); + break; + } + + //I8 = 20, + //UI8 = 21, + //INT = 22, + //UINT = 23, + //VOID = 24, + //HRESULT = 25, + //PTR = 26, + //SAFEARRAY = 27, + //CARRAY = 28, + //USERDEFINED = 29, + //LPSTR = 30, + + case VT::LPWSTR : + { + auto ptr = InteropServices::Marshal::ReadIntPtr(val, 8); + obj->value = InteropServices::Marshal::PtrToStringUni(ptr); + InteropServices::Marshal::FreeCoTaskMem(ptr); + break; + } + + //RECORD = 36, + //INT_PTR = 37, + //UINT_PTR = 38, + //FILETIME = 64, + + //BLOB = 65, + case VT::BLOB : + { + auto blob = gcnew BLOB(); + + auto temp = gcnew array(4); + auto ptr = val + 8; + InteropServices::Marshal::Copy(ptr, temp, 0, 4); + blob->cbSize = System::BitConverter::ToUInt32(temp, 0); + + ptr += 4; + blob->pBlobData = gcnew array(blob->cbSize); + InteropServices::Marshal::Copy(ptr, blob->pBlobData, 0, blob->cbSize); + + obj->value = blob; + break; + } + + //STREAM = 66, + //STORAGE = 67, + //STREAMED_OBJECT = 68, + //STORED_OBJECT = 69, + //BLOB_OBJECT = 70, + //CF = 71, + + + case VT::CLSID : + { + auto ptr = InteropServices::Marshal::ReadIntPtr(val, 8); + obj->value = InteropServices::Marshal::PtrToStructure(ptr, Guiddef::Guid::typeid); + InteropServices::Marshal::FreeCoTaskMem(ptr); + break; + } + + + //VERSIONED_STREAM = 73, + //BSTR_BLOB = 0xfff, + //VECTOR = 0x1000, + //ARRAY = 0x2000, + //BYREF = 0x4000, + //RESERVED = 0x8000, + //ILLEGAL = 0xffff, + //ILLEGALMASKED = 0xfff, + //TYPEMASK = 0xfff + + default: + { + System::Console::WriteLine("[{0}]–¢ƒTƒ|[ƒg‚ÌŒ^[VT:{1}]",__FUNCTION__, obj->vt); + break; + } + } + + #ifdef _DEBUG + // System::Console::WriteLine("[{0}][obj:{1}]",__FUNCTION__, obj); + #endif + return obj; + } + + virtual System::IntPtr MarshalManagedToNative(System::Object^ obj) + { + #ifdef _DEBUG +// System::Console::WriteLine("[{0}][obj:{1}]",__FUNCTION__, obj); + #endif + if(obj == nullptr) + { + return System::IntPtr::Zero; + } + + auto val = InteropServices::Marshal::AllocCoTaskMem(32); + #ifdef _DEBUG +// System::Console::WriteLine("[{0}][val:{1}]",__FUNCTION__, val); + #endif + + return val; + } + + virtual void CleanUpNativeData(System::IntPtr val) + { + #ifdef _DEBUG +// System::Console::WriteLine("[{0}][val:{1}]",__FUNCTION__, val); + #endif + InteropServices::Marshal::FreeCoTaskMem(val); + } + + virtual void CleanUpManagedData(System::Object^ obj) + { + #ifdef _DEBUG +// System::Console::WriteLine("[{0}][obj:{1}]",__FUNCTION__, obj); + #endif + + } + + virtual System::Int32 GetNativeDataSize() + { + #ifdef _DEBUG +// System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + return 0; + } + + static InteropServices::ICustomMarshaler^ GetInstance(System::String^ cookie) + { + #ifdef _DEBUG +// System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + if (instance == nullptr) + { + instance = gcnew PROPVARIANTMarshaler(); + } + return instance; + } + + PROPVARIANTMarshaler() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + ~PROPVARIANTMarshaler() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + }; + + /* + WIN32_DLL_STRUCTLAYOUT_UNION_ANSI + public ref struct PROPVARIANT + { + [InteropServices::FieldOffset(0)] VT vt; + [InteropServices::FieldOffset(2)] System::UInt16 wReserved1; + [InteropServices::FieldOffset(4)] System::UInt16 wReserved2; + [InteropServices::FieldOffset(6)] System::UInt16 wReserved3; + + [InteropServices::FieldOffset(8)] System::SByte cVal; + [InteropServices::FieldOffset(8)] System::Byte bVal; + [InteropServices::FieldOffset(8)] System::Int16 iVal; + [InteropServices::FieldOffset(8)] System::UInt16 uiVal; + [InteropServices::FieldOffset(8)] System::Int32 lVal; + [InteropServices::FieldOffset(8)] System::UInt32 ulVal; + [InteropServices::FieldOffset(8)] System::Int32 intVal; + [InteropServices::FieldOffset(8)] System::UInt32 uintVal; + + [InteropServices::FieldOffset(8)] LARGE_INTEGER hVal; + [InteropServices::FieldOffset(8)] ULARGE_INTEGER uhVal; + [InteropServices::FieldOffset(8)] FLOAT fltVal; + [InteropServices::FieldOffset(8)] DOUBLE dblVal; + [InteropServices::FieldOffset(8)] VARIANT_BOOL boolVal; + [InteropServices::FieldOffset(8)] _VARIANT_BOOL bool; + [InteropServices::FieldOffset(8)] SCODE scode; + [InteropServices::FieldOffset(8)] CY cyVal; + [InteropServices::FieldOffset(8)] DATE date; + + [InteropServices::FieldOffset(8)] InteropServices::ComTypes::FILETIME filetime; + + [InteropServices::FieldOffset(8)] CLSID *puuid; + [InteropServices::FieldOffset(8)] CLIPDATA *pclipdata; + [InteropServices::FieldOffset(8)] BSTR bstrVal; + [InteropServices::FieldOffset(8)] BSTRBLOB bstrblobVal; + [InteropServices::FieldOffset(8)] BLOB blob; + [InteropServices::FieldOffset(8)] LPSTR pszVal; + [InteropServices::FieldOffset(8)] LPWSTR pwszVal; + [InteropServices::FieldOffset(8)] IUnknown *punkVal; + [InteropServices::FieldOffset(8)] IDispatch *pdispVal; + [InteropServices::FieldOffset(8)] IStream *pStream; + [InteropServices::FieldOffset(8)] IStorage *pStorage; + [InteropServices::FieldOffset(8)] LPVERSIONEDSTREAM pVersionedStream; + [InteropServices::FieldOffset(8)] LPSAFEARRAY parray; + [InteropServices::FieldOffset(8)] CAC cac; + [InteropServices::FieldOffset(8)] CAUB caub; + [InteropServices::FieldOffset(8)] CAI cai; + [InteropServices::FieldOffset(8)] CAUI caui; + [InteropServices::FieldOffset(8)] CAL cal; + [InteropServices::FieldOffset(8)] CAUL caul; + [InteropServices::FieldOffset(8)] CAH cah; + [InteropServices::FieldOffset(8)] CAUH cauh; + [InteropServices::FieldOffset(8)] CAFLT caflt; + [InteropServices::FieldOffset(8)] CADBL cadbl; + [InteropServices::FieldOffset(8)] CABOOL cabool; + [InteropServices::FieldOffset(8)] CASCODE cascode; + [InteropServices::FieldOffset(8)] CACY cacy; + [InteropServices::FieldOffset(8)] CADATE cadate; + [InteropServices::FieldOffset(8)] CAFILETIME cafiletime; + [InteropServices::FieldOffset(8)] CACLSID cauuid; + [InteropServices::FieldOffset(8)] CACLIPDATA caclipdata; + [InteropServices::FieldOffset(8)] CABSTR cabstr; + [InteropServices::FieldOffset(8)] CABSTRBLOB cabstrblob; + [InteropServices::FieldOffset(8)] CALPSTR calpstr; + [InteropServices::FieldOffset(8)] CALPWSTR calpwstr; + [InteropServices::FieldOffset(8)] CAPROPVARIANT capropvar; + [InteropServices::FieldOffset(8)] CHAR *pcVal; + [InteropServices::FieldOffset(8)] UCHAR *pbVal; + [InteropServices::FieldOffset(8)] SHORT *piVal; + [InteropServices::FieldOffset(8)] USHORT *puiVal; + [InteropServices::FieldOffset(8)] LONG *plVal; + [InteropServices::FieldOffset(8)] ULONG *pulVal; + [InteropServices::FieldOffset(8)] INT *pintVal; + [InteropServices::FieldOffset(8)] UINT *puintVal; + [InteropServices::FieldOffset(8)] FLOAT *pfltVal; + [InteropServices::FieldOffset(8)] DOUBLE *pdblVal; + [InteropServices::FieldOffset(8)] VARIANT_BOOL *pboolVal; + [InteropServices::FieldOffset(8)] DECIMAL *pdecVal; + [InteropServices::FieldOffset(8)] SCODE *pscode; + [InteropServices::FieldOffset(8)] CY *pcyVal; + [InteropServices::FieldOffset(8)] DATE *pdate; + [InteropServices::FieldOffset(8)] BSTR *pbstrVal; + [InteropServices::FieldOffset(8)] IUnknown **ppunkVal; + [InteropServices::FieldOffset(8)] IDispatch **ppdispVal; + [InteropServices::FieldOffset(8)] LPSAFEARRAY *pparray; + [InteropServices::FieldOffset(8)] PROPVARIANT *pvarVal; + + }; + */ + + //propsys.h + [InteropServices::ComImport] + [InteropServices::Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")] + [InteropServices::InterfaceType(InteropServices::ComInterfaceType::InterfaceIsIUnknown)] + public interface class IPropertyStore + { + void GetCount( + [InteropServices::Out] System::UInt32% cProps + ); + + void GetAt( + [InteropServices::In] System::UInt32 iProp, + [InteropServices::Out] PROPERTYKEY^ pkey + ); + + void GetValue( + [InteropServices::In] PROPERTYKEY^ key, + [InteropServices::Out] System::IntPtr pv //TODO: ƒJƒXƒ^ƒ€ƒ}[ƒVƒƒƒ‰[‚ðŽw’è‚·‚é‚ƁAoutƒpƒ‰ƒ[ƒ^‚Å’l‚ðŽó‚¯Žæ‚ê‚È‚¢ + ); + + void SetValue( + [InteropServices::In] PROPERTYKEY^ key, + [InteropServices::In] System::IntPtr propvar + ); + + void Commit(); + }; + + + + /* + +typedef struct tagVersionedStream + { + GUID guidVersion; + IStream *pStream; + } VERSIONEDSTREAM; + +typedef struct tagVersionedStream *LPVERSIONEDSTREAM; + + +// Flags for IPropertySetStorage::Create +#define PROPSETFLAG_DEFAULT ( 0 ) + +#define PROPSETFLAG_NONSIMPLE ( 1 ) + +#define PROPSETFLAG_ANSI ( 2 ) + +// (This flag is only supported on StgCreatePropStg & StgOpenPropStg +#define PROPSETFLAG_UNBUFFERED ( 4 ) + +// (This flag causes a version-1 property set to be created +#define PROPSETFLAG_CASE_SENSITIVE ( 8 ) + + +// Flags for the reservied PID_BEHAVIOR property +#define PROPSET_BEHAVIOR_CASE_SENSITIVE ( 1 ) + +#ifdef MIDL_PASS +// This is the PROPVARIANT definition for marshaling. +typedef struct tag_inner_PROPVARIANT PROPVARIANT; + +#else +// This is the standard C layout of the PROPVARIANT. +typedef struct tagPROPVARIANT PROPVARIANT; +#endif +typedef struct tagCAC + { + ULONG cElems; + CHAR *pElems; + } CAC; + +typedef struct tagCAUB + { + ULONG cElems; + UCHAR *pElems; + } CAUB; + +typedef struct tagCAI + { + ULONG cElems; + SHORT *pElems; + } CAI; + +typedef struct tagCAUI + { + ULONG cElems; + USHORT *pElems; + } CAUI; + +typedef struct tagCAL + { + ULONG cElems; + LONG *pElems; + } CAL; + +typedef struct tagCAUL + { + ULONG cElems; + ULONG *pElems; + } CAUL; + +typedef struct tagCAFLT + { + ULONG cElems; + FLOAT *pElems; + } CAFLT; + +typedef struct tagCADBL + { + ULONG cElems; + DOUBLE *pElems; + } CADBL; + +typedef struct tagCACY + { + ULONG cElems; + CY *pElems; + } CACY; + +typedef struct tagCADATE + { + ULONG cElems; + DATE *pElems; + } CADATE; + +typedef struct tagCABSTR + { + ULONG cElems; + BSTR *pElems; + } CABSTR; + +typedef struct tagCABSTRBLOB + { + ULONG cElems; + BSTRBLOB *pElems; + } CABSTRBLOB; + +typedef struct tagCABOOL + { + ULONG cElems; + VARIANT_BOOL *pElems; + } CABOOL; + +typedef struct tagCASCODE + { + ULONG cElems; + SCODE *pElems; + } CASCODE; + +typedef struct tagCAPROPVARIANT + { + ULONG cElems; + PROPVARIANT *pElems; + } CAPROPVARIANT; + +typedef struct tagCAH + { + ULONG cElems; + LARGE_INTEGER *pElems; + } CAH; + +typedef struct tagCAUH + { + ULONG cElems; + ULARGE_INTEGER *pElems; + } CAUH; + +typedef struct tagCALPSTR + { + ULONG cElems; + LPSTR *pElems; + } CALPSTR; + +typedef struct tagCALPWSTR + { + ULONG cElems; + LPWSTR *pElems; + } CALPWSTR; + +typedef struct tagCAFILETIME + { + ULONG cElems; + FILETIME *pElems; + } CAFILETIME; + +typedef struct tagCACLIPDATA + { + ULONG cElems; + CLIPDATA *pElems; + } CACLIPDATA; + +typedef struct tagCACLSID + { + ULONG cElems; + CLSID *pElems; + } CACLSID; + + +struct tag_inner_PROPVARIANT + { + VARTYPE vt; + PROPVAR_PAD1 wReserved1; + PROPVAR_PAD2 wReserved2; + PROPVAR_PAD3 wReserved3; + /* [switch_type] union + { + /* Empty union arm + CHAR cVal; + UCHAR bVal; + SHORT iVal; + USHORT uiVal; + LONG lVal; + ULONG ulVal; + INT intVal; + UINT uintVal; + LARGE_INTEGER hVal; + ULARGE_INTEGER uhVal; + FLOAT fltVal; + DOUBLE dblVal; + VARIANT_BOOL boolVal; + _VARIANT_BOOL bool; + SCODE scode; + CY cyVal; + DATE date; + FILETIME filetime; + CLSID *puuid; + CLIPDATA *pclipdata; + BSTR bstrVal; + BSTRBLOB bstrblobVal; + BLOB blob; + LPSTR pszVal; + LPWSTR pwszVal; + IUnknown *punkVal; + IDispatch *pdispVal; + IStream *pStream; + IStorage *pStorage; + LPVERSIONEDSTREAM pVersionedStream; + LPSAFEARRAY parray; + CAC cac; + CAUB caub; + CAI cai; + CAUI caui; + CAL cal; + CAUL caul; + CAH cah; + CAUH cauh; + CAFLT caflt; + CADBL cadbl; + CABOOL cabool; + CASCODE cascode; + CACY cacy; + CADATE cadate; + CAFILETIME cafiletime; + CACLSID cauuid; + CACLIPDATA caclipdata; + CABSTR cabstr; + CABSTRBLOB cabstrblob; + CALPSTR calpstr; + CALPWSTR calpwstr; + CAPROPVARIANT capropvar; + CHAR *pcVal; + UCHAR *pbVal; + SHORT *piVal; + USHORT *puiVal; + LONG *plVal; + ULONG *pulVal; + INT *pintVal; + UINT *puintVal; + FLOAT *pfltVal; + DOUBLE *pdblVal; + VARIANT_BOOL *pboolVal; + DECIMAL *pdecVal; + SCODE *pscode; + CY *pcyVal; + DATE *pdate; + BSTR *pbstrVal; + IUnknown **ppunkVal; + IDispatch **ppdispVal; + LPSAFEARRAY *pparray; + PROPVARIANT *pvarVal; + } ; + } ; +#ifndef MIDL_PASS + DECIMAL decVal; + }; +}; + + + + [ComConversionLoss] + [StructLayout(LayoutKind.Explicit, Pack = 8, Size = 8)] + public struct __MIDL___MIDL_itf_mmdeviceapi_0003_0085_0001 + { + [FieldOffset(0)] + public sbyte cVal; + [FieldOffset(0)] + public byte bVal; + [FieldOffset(0)] + public short iVal; + [FieldOffset(0)] + public ushort uiVal; + [FieldOffset(0)] + public int lVal; + [FieldOffset(0)] + public uint ulVal; + [FieldOffset(0)] + public int intVal; + [FieldOffset(0)] + public uint uintVal; + [FieldOffset(0)] + public _LARGE_INTEGER hVal; + [FieldOffset(0)] + public _ULARGE_INTEGER uhVal; + [FieldOffset(0)] + public float fltVal; + [FieldOffset(0)] + public double dblVal; + [FieldOffset(0)] + public short boolVal; + [FieldOffset(0)] + public short @bool; + [FieldOffset(0)] + [MarshalAs(UnmanagedType.Error)] + public int scode; + [FieldOffset(0)] + [MarshalAs(UnmanagedType.Currency)] + public decimal cyVal; + [FieldOffset(0)] + public DateTime date; + [FieldOffset(0)] + public _FILETIME filetime; + [FieldOffset(0)] + public tagBSTRBLOB bstrblobVal; + [FieldOffset(0)] + public tagBLOB blob; + [FieldOffset(0)] + public tagCAC cac; + [FieldOffset(0)] + public tagCAUB caub; + [FieldOffset(0)] + public tagCAI cai; + [FieldOffset(0)] + public tagCAUI caui; + [FieldOffset(0)] + public tagCAL cal; + [FieldOffset(0)] + public tagCAUL caul; + [FieldOffset(0)] + public tagCAFLT caflt; + [FieldOffset(0)] + public tagCADBL cadbl; + [FieldOffset(0)] + public tagCABOOL cabool; + [FieldOffset(0)] + public tagCASCODE cascode; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pcVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pbVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr piVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr puiVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr plVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pulVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pintVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr puintVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pfltVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pdblVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pboolVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pscode; + } + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct _LARGE_INTEGER + { + public long QuadPart; + } + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct _ULARGE_INTEGER + { + public ulong QuadPart; + } + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _FILETIME + { + public uint dwLowDateTime; + public uint dwHighDateTime; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagBSTRBLOB + { + public uint cbSize; + [ComConversionLoss] + public IntPtr pData; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagBLOB + { + public uint cbSize; + [ComConversionLoss] + public IntPtr pBlobData; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAC + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAUB + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAI + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAUI + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAL + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAUL + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAFLT + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCADBL + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCABOOL + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCASCODE + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCLIPDATA + { + public uint cbSize; + public int ulClipFmt; + [ComConversionLoss] + public IntPtr pClipData; + } + [Guid("0C733A30-2A1C-11CE-ADE5-00AA0044773D"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ISequentialStream + { + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteRead(out byte pv, [In] uint cb, out uint pcbRead); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteWrite([In] ref byte pv, [In] uint cb, out uint pcbWritten); + } + [Guid("0000000C-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IStream : ISequentialStream + { + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteRead(out byte pv, [In] uint cb, out uint pcbRead); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteWrite([In] ref byte pv, [In] uint cb, out uint pcbWritten); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteSeek([In] _LARGE_INTEGER dlibMove, [In] uint dwOrigin, out _ULARGE_INTEGER plibNewPosition); + [MethodImpl(MethodImplOptions.InternalCall)] + void SetSize([In] _ULARGE_INTEGER libNewSize); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteCopyTo([MarshalAs(UnmanagedType.Interface)] [In] IStream pstm, [In] _ULARGE_INTEGER cb, out _ULARGE_INTEGER pcbRead, out _ULARGE_INTEGER pcbWritten); + [MethodImpl(MethodImplOptions.InternalCall)] + void Commit([In] uint grfCommitFlags); + [MethodImpl(MethodImplOptions.InternalCall)] + void Revert(); + [MethodImpl(MethodImplOptions.InternalCall)] + void LockRegion([In] _ULARGE_INTEGER libOffset, [In] _ULARGE_INTEGER cb, [In] uint dwLockType); + [MethodImpl(MethodImplOptions.InternalCall)] + void UnlockRegion([In] _ULARGE_INTEGER libOffset, [In] _ULARGE_INTEGER cb, [In] uint dwLockType); + [MethodImpl(MethodImplOptions.InternalCall)] + void Stat(out tagSTATSTG pstatstg, [In] uint grfStatFlag); + [MethodImpl(MethodImplOptions.InternalCall)] + void Clone([MarshalAs(UnmanagedType.Interface)] out IStream ppstm); + } + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct tagSTATSTG + { + [MarshalAs(UnmanagedType.LPWStr)] + public string pwcsName; + public uint type; + public _ULARGE_INTEGER cbSize; + public _FILETIME mtime; + public _FILETIME ctime; + public _FILETIME atime; + public uint grfMode; + public uint grfLocksSupported; + public Guid clsid; + public uint grfStateBits; + public uint reserved; + } + [Guid("0000000B-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IStorage + { + [MethodImpl(MethodImplOptions.InternalCall)] + void CreateStream([MarshalAs(UnmanagedType.LPWStr)] [In] string pwcsName, [In] uint grfMode, [In] uint reserved1, [In] uint reserved2, [MarshalAs(UnmanagedType.Interface)] out IStream ppstm); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteOpenStream([MarshalAs(UnmanagedType.LPWStr)] [In] string pwcsName, [In] uint cbReserved1, [In] ref byte reserved1, [In] uint grfMode, [In] uint reserved2, [MarshalAs(UnmanagedType.Interface)] out IStream ppstm); + [MethodImpl(MethodImplOptions.InternalCall)] + void CreateStorage([MarshalAs(UnmanagedType.LPWStr)] [In] string pwcsName, [In] uint grfMode, [In] uint reserved1, [In] uint reserved2, [MarshalAs(UnmanagedType.Interface)] out IStorage ppstg); + [MethodImpl(MethodImplOptions.InternalCall)] + void OpenStorage([MarshalAs(UnmanagedType.LPWStr)] [In] string pwcsName, [MarshalAs(UnmanagedType.Interface)] [In] IStorage pstgPriority, [In] uint grfMode, [ComAliasName("MMDeviceAPILib.wireSNB")] [In] ref tagRemSNB snbExclude, [In] uint reserved, [MarshalAs(UnmanagedType.Interface)] out IStorage ppstg); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteCopyTo([In] uint ciidExclude, [In] ref Guid rgiidExclude, [ComAliasName("MMDeviceAPILib.wireSNB")] [In] ref tagRemSNB snbExclude, [MarshalAs(UnmanagedType.Interface)] [In] IStorage pstgDest); + [MethodImpl(MethodImplOptions.InternalCall)] + void MoveElementTo([MarshalAs(UnmanagedType.LPWStr)] [In] string pwcsName, [MarshalAs(UnmanagedType.Interface)] [In] IStorage pstgDest, [MarshalAs(UnmanagedType.LPWStr)] [In] string pwcsNewName, [In] uint grfFlags); + [MethodImpl(MethodImplOptions.InternalCall)] + void Commit([In] uint grfCommitFlags); + [MethodImpl(MethodImplOptions.InternalCall)] + void Revert(); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteEnumElements([In] uint reserved1, [In] uint cbReserved2, [In] ref byte reserved2, [In] uint reserved3, [MarshalAs(UnmanagedType.Interface)] out IEnumSTATSTG ppenum); + [MethodImpl(MethodImplOptions.InternalCall)] + void DestroyElement([MarshalAs(UnmanagedType.LPWStr)] [In] string pwcsName); + [MethodImpl(MethodImplOptions.InternalCall)] + void RenameElement([MarshalAs(UnmanagedType.LPWStr)] [In] string pwcsOldName, [MarshalAs(UnmanagedType.LPWStr)] [In] string pwcsNewName); + [MethodImpl(MethodImplOptions.InternalCall)] + void SetElementTimes([MarshalAs(UnmanagedType.LPWStr)] [In] string pwcsName, [In] ref _FILETIME pctime, [In] ref _FILETIME patime, [In] ref _FILETIME pmtime); + [MethodImpl(MethodImplOptions.InternalCall)] + void SetClass([In] ref Guid clsid); + [MethodImpl(MethodImplOptions.InternalCall)] + void SetStateBits([In] uint grfStateBits, [In] uint grfMask); + [MethodImpl(MethodImplOptions.InternalCall)] + void Stat(out tagSTATSTG pstatstg, [In] uint grfStatFlag); + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagRemSNB + { + public uint ulCntStr; + public uint ulCntChar; + [ComConversionLoss] + public IntPtr rgString; + } + [Guid("0000000D-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IEnumSTATSTG + { + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteNext([In] uint celt, out tagSTATSTG rgelt, out uint pceltFetched); + [MethodImpl(MethodImplOptions.InternalCall)] + void Skip([In] uint celt); + [MethodImpl(MethodImplOptions.InternalCall)] + void Reset(); + [MethodImpl(MethodImplOptions.InternalCall)] + void Clone([MarshalAs(UnmanagedType.Interface)] out IEnumSTATSTG ppenum); + } + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagVersionedStream + { + public Guid guidVersion; + [MarshalAs(UnmanagedType.Interface)] + public IStream pStream; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _wireSAFEARRAY + { + public ushort cDims; + public ushort fFeatures; + public uint cbElements; + public uint cLocks; + public _wireSAFEARRAY_UNION uArrayStructs; + [ComConversionLoss] + public IntPtr rgsabound; + } + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _wireSAFEARRAY_UNION + { + public uint sfType; + public __MIDL_IOleAutomationTypes_0001 u; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 24)] + public struct __MIDL_IOleAutomationTypes_0001 + { + [FieldOffset(0)] + public _BYTE_SIZEDARR ByteStr; + [FieldOffset(0)] + public _SHORT_SIZEDARR WordStr; + [FieldOffset(0)] + public _LONG_SIZEDARR LongStr; + [FieldOffset(0)] + public _HYPER_SIZEDARR HyperStr; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _BYTE_SIZEDARR + { + public uint clSize; + [ComConversionLoss] + public IntPtr pData; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _SHORT_SIZEDARR + { + public uint clSize; + [ComConversionLoss] + public IntPtr pData; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _LONG_SIZEDARR + { + public uint clSize; + [ComConversionLoss] + public IntPtr pData; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _HYPER_SIZEDARR + { + public uint clSize; + [ComConversionLoss] + public IntPtr pData; + } + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagSAFEARRAYBOUND + { + public uint cElements; + public int lLbound; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _wireSAFEARR_BSTR + { + public uint Size; + [ComConversionLoss] + public IntPtr aBstr; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _FLAGGED_WORD_BLOB + { + public uint fFlags; + public uint clSize; + [ComConversionLoss] + public IntPtr asData; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _wireSAFEARR_UNKNOWN + { + public uint Size; + [ComConversionLoss] + public IntPtr apUnknown; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _wireSAFEARR_DISPATCH + { + public uint Size; + [ComConversionLoss] + public IntPtr apDispatch; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _wireSAFEARR_VARIANT + { + public uint Size; + [ComConversionLoss] + public IntPtr aVariant; + } + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct _wireVARIANT + { + public uint clSize; + public uint rpcReserved; + public ushort vt; + public ushort wReserved1; + public ushort wReserved2; + public ushort wReserved3; + public __MIDL_IOleAutomationTypes_0004 DUMMYUNIONNAME; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Explicit, Pack = 8, Size = 16)] + public struct __MIDL_IOleAutomationTypes_0004 + { + [FieldOffset(0)] + public long llVal; + [FieldOffset(0)] + public int lVal; + [FieldOffset(0)] + public byte bVal; + [FieldOffset(0)] + public short iVal; + [FieldOffset(0)] + public float fltVal; + [FieldOffset(0)] + public double dblVal; + [FieldOffset(0)] + public short boolVal; + [FieldOffset(0)] + [MarshalAs(UnmanagedType.Error)] + public int scode; + [FieldOffset(0)] + [MarshalAs(UnmanagedType.Currency)] + public decimal cyVal; + [FieldOffset(0)] + public DateTime date; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pbVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr piVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr plVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pllVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pfltVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pdblVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pboolVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pscode; + [FieldOffset(0)] + public sbyte cVal; + [FieldOffset(0)] + public ushort uiVal; + [FieldOffset(0)] + public uint ulVal; + [FieldOffset(0)] + public ulong ullVal; + [FieldOffset(0)] + public int intVal; + [FieldOffset(0)] + public uint uintVal; + [FieldOffset(0)] + public decimal decVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pcVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr puiVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pulVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pullVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pintVal; + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr puintVal; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _wireBRECORD + { + public uint fFlags; + public uint clSize; + [MarshalAs(UnmanagedType.Interface)] + public IRecordInfo pRecInfo; + [ComConversionLoss] + public IntPtr pRecord; + } + [Guid("0000002F-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IRecordInfo + { + [MethodImpl(MethodImplOptions.InternalCall)] + void RecordInit([Out] IntPtr pvNew); + [MethodImpl(MethodImplOptions.InternalCall)] + void RecordClear([In] IntPtr pvExisting); + [MethodImpl(MethodImplOptions.InternalCall)] + void RecordCopy([In] IntPtr pvExisting, [Out] IntPtr pvNew); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetGuid(out Guid pguid); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetName([MarshalAs(UnmanagedType.BStr)] out string pbstrName); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetSize(out uint pcbSize); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetTypeInfo([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler")] out Type ppTypeInfo); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetField([In] IntPtr pvData, [MarshalAs(UnmanagedType.LPWStr)] [In] string szFieldName, [MarshalAs(UnmanagedType.Struct)] out object pvarField); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetFieldNoCopy([In] IntPtr pvData, [MarshalAs(UnmanagedType.LPWStr)] [In] string szFieldName, [MarshalAs(UnmanagedType.Struct)] out object pvarField, out IntPtr ppvDataCArray); + [MethodImpl(MethodImplOptions.InternalCall)] + void PutField([In] uint wFlags, [In] [Out] IntPtr pvData, [MarshalAs(UnmanagedType.LPWStr)] [In] string szFieldName, [MarshalAs(UnmanagedType.Struct)] [In] ref object pvarField); + [MethodImpl(MethodImplOptions.InternalCall)] + void PutFieldNoCopy([In] uint wFlags, [In] [Out] IntPtr pvData, [MarshalAs(UnmanagedType.LPWStr)] [In] string szFieldName, [MarshalAs(UnmanagedType.Struct)] [In] ref object pvarField); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetFieldNames([In] [Out] ref uint pcNames, [MarshalAs(UnmanagedType.BStr)] out string rgBstrNames); + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + int IsMatchingType([MarshalAs(UnmanagedType.Interface)] [In] IRecordInfo pRecordInfo); + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + IntPtr RecordCreate(); + [MethodImpl(MethodImplOptions.InternalCall)] + void RecordCreateCopy([In] IntPtr pvSource, out IntPtr ppvDest); + [MethodImpl(MethodImplOptions.InternalCall)] + void RecordDestroy([In] IntPtr pvRecord); + } + [ComConversionLoss, Guid("00020401-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ITypeInfo + { + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteGetTypeAttr([Out] IntPtr ppTypeAttr, [ComAliasName("MMDeviceAPILib.DWORD")] out uint pDummy); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetTypeComp([MarshalAs(UnmanagedType.Interface)] out ITypeComp ppTComp); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteGetFuncDesc([In] uint index, [Out] IntPtr ppFuncDesc, [ComAliasName("MMDeviceAPILib.DWORD")] out uint pDummy); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteGetVarDesc([In] uint index, [Out] IntPtr ppVarDesc, [ComAliasName("MMDeviceAPILib.DWORD")] out uint pDummy); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteGetNames([In] int memid, [MarshalAs(UnmanagedType.BStr)] out string rgBstrNames, [In] uint cMaxNames, out uint pcNames); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetRefTypeOfImplType([In] uint index, out uint pRefType); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetImplTypeFlags([In] uint index, out int pImplTypeFlags); + [MethodImpl(MethodImplOptions.InternalCall)] + void LocalGetIDsOfNames(); + [MethodImpl(MethodImplOptions.InternalCall)] + void LocalInvoke(); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteGetDocumentation([In] int memid, [In] uint refPtrFlags, [MarshalAs(UnmanagedType.BStr)] out string pbstrName, [MarshalAs(UnmanagedType.BStr)] out string pBstrDocString, out uint pdwHelpContext, [MarshalAs(UnmanagedType.BStr)] out string pBstrHelpFile); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteGetDllEntry([In] int memid, [In] tagINVOKEKIND invkind, [In] uint refPtrFlags, [MarshalAs(UnmanagedType.BStr)] out string pBstrDllName, [MarshalAs(UnmanagedType.BStr)] out string pbstrName, out ushort pwOrdinal); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetRefTypeInfo([In] uint hreftype, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler")] out Type ppTInfo); + [MethodImpl(MethodImplOptions.InternalCall)] + void LocalAddressOfMember(); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteCreateInstance([In] ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppvObj); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetMops([In] int memid, [MarshalAs(UnmanagedType.BStr)] out string pBstrMops); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteGetContainingTypeLib([MarshalAs(UnmanagedType.Interface)] out ITypeLib ppTLib, out uint pIndex); + [MethodImpl(MethodImplOptions.InternalCall)] + void LocalReleaseTypeAttr(); + [MethodImpl(MethodImplOptions.InternalCall)] + void LocalReleaseFuncDesc(); + [MethodImpl(MethodImplOptions.InternalCall)] + void LocalReleaseVarDesc(); + } + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagTYPEATTR + { + public Guid guid; + public uint lcid; + public uint dwReserved; + public int memidConstructor; + public int memidDestructor; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpstrSchema; + public uint cbSizeInstance; + public tagTYPEKIND typekind; + public ushort cFuncs; + public ushort cVars; + public ushort cImplTypes; + public ushort cbSizeVft; + public ushort cbAlignment; + public ushort wTypeFlags; + public ushort wMajorVerNum; + public ushort wMinorVerNum; + public tagTYPEDESC tdescAlias; + public tagIDLDESC idldescType; + } + [ComConversionLoss, Guid("00020403-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ITypeComp + { + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteBind([MarshalAs(UnmanagedType.LPWStr)] [In] string szName, [In] uint lHashVal, [In] ushort wFlags, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler")] out Type ppTInfo, out tagDESCKIND pDescKind, [Out] IntPtr ppFuncDesc, [Out] IntPtr ppVarDesc, [MarshalAs(UnmanagedType.Interface)] out ITypeComp ppTypeComp, [ComAliasName("MMDeviceAPILib.DWORD")] out uint pDummy); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteBindType([MarshalAs(UnmanagedType.LPWStr)] [In] string szName, [In] uint lHashVal, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler")] out Type ppTInfo); + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagFUNCDESC + { + public int memid; + [ComConversionLoss] + public IntPtr lprgscode; + [ComConversionLoss] + public IntPtr lprgelemdescParam; + public tagFUNCKIND funckind; + public tagINVOKEKIND invkind; + public tagCALLCONV callconv; + public short cParams; + public short cParamsOpt; + public short oVft; + public short cScodes; + public tagELEMDESC elemdescFunc; + public ushort wFuncFlags; + } + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagVARDESC + { + public int memid; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpstrSchema; + public __MIDL_IOleAutomationTypes_0006 DUMMYUNIONNAME; + public tagELEMDESC elemdescVar; + public ushort wVarFlags; + public tagVARKIND varkind; + } + public enum tagINVOKEKIND + { + INVOKE_FUNC = 1, + INVOKE_PROPERTYGET, + INVOKE_PROPERTYPUT = 4, + INVOKE_PROPERTYPUTREF = 8 + } + [ComConversionLoss, Guid("00020402-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ITypeLib + { + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteGetTypeInfoCount(out uint pcTInfo); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetTypeInfo([In] uint index, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler")] out Type ppTInfo); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetTypeInfoType([In] uint index, out tagTYPEKIND pTKind); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetTypeInfoOfGuid([In] ref Guid guid, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler")] out Type ppTInfo); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteGetLibAttr([Out] IntPtr ppTLibAttr, [ComAliasName("MMDeviceAPILib.DWORD")] out uint pDummy); + [MethodImpl(MethodImplOptions.InternalCall)] + void GetTypeComp([MarshalAs(UnmanagedType.Interface)] out ITypeComp ppTComp); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteGetDocumentation([In] int index, [In] uint refPtrFlags, [MarshalAs(UnmanagedType.BStr)] out string pbstrName, [MarshalAs(UnmanagedType.BStr)] out string pBstrDocString, out uint pdwHelpContext, [MarshalAs(UnmanagedType.BStr)] out string pBstrHelpFile); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteIsName([MarshalAs(UnmanagedType.LPWStr)] [In] string szNameBuf, [In] uint lHashVal, out int pfName, [MarshalAs(UnmanagedType.BStr)] out string pBstrLibName); + [MethodImpl(MethodImplOptions.InternalCall)] + void RemoteFindName([MarshalAs(UnmanagedType.LPWStr)] [In] string szNameBuf, [In] uint lHashVal, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler")] out Type ppTInfo, out int rgMemId, [In] [Out] ref ushort pcFound, [MarshalAs(UnmanagedType.BStr)] out string pBstrLibName); + [MethodImpl(MethodImplOptions.InternalCall)] + void LocalReleaseTLibAttr(); + } + public enum tagTYPEKIND + { + TKIND_ENUM, + TKIND_RECORD, + TKIND_MODULE, + TKIND_INTERFACE, + TKIND_DISPATCH, + TKIND_COCLASS, + TKIND_ALIAS, + TKIND_UNION, + TKIND_MAX + } + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagTYPEDESC + { + public __MIDL_IOleAutomationTypes_0005 DUMMYUNIONNAME; + public ushort vt; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 4)] + public struct __MIDL_IOleAutomationTypes_0005 + { + [FieldOffset(0)] + public uint hreftype; + } + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagIDLDESC + { + [ComAliasName("MMDeviceAPILib.ULONG_PTR")] + public uint dwReserved; + public ushort wIDLFlags; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagARRAYDESC + { + public tagTYPEDESC tdescElem; + public ushort cDims; + [ComConversionLoss] + public IntPtr rgbounds; + } + public enum tagDESCKIND + { + DESCKIND_NONE, + DESCKIND_FUNCDESC, + DESCKIND_VARDESC, + DESCKIND_TYPECOMP, + DESCKIND_IMPLICITAPPOBJ, + DESCKIND_MAX + } + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagELEMDESC + { + public tagTYPEDESC tdesc; + public tagPARAMDESC paramdesc; + } + public enum tagFUNCKIND + { + FUNC_VIRTUAL, + FUNC_PUREVIRTUAL, + FUNC_NONVIRTUAL, + FUNC_STATIC, + FUNC_DISPATCH + } + public enum tagCALLCONV + { + CC_FASTCALL, + CC_CDECL, + CC_MSCPASCAL, + CC_PASCAL = 2, + CC_MACPASCAL, + CC_STDCALL, + CC_FPFASTCALL, + CC_SYSCALL, + CC_MPWCDECL, + CC_MPWPASCAL, + CC_MAX + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagPARAMDESC + { + [ComConversionLoss] + public IntPtr pparamdescex; + public ushort wParamFlags; + } + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct tagPARAMDESCEX + { + public uint cBytes; + [MarshalAs(UnmanagedType.Struct)] + public object varDefaultValue; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 4)] + public struct __MIDL_IOleAutomationTypes_0006 + { + [FieldOffset(0)] + public uint oInst; + } + public enum tagVARKIND + { + VAR_PERINSTANCE, + VAR_STATIC, + VAR_CONST, + VAR_DISPATCH + } + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagTLIBATTR + { + public Guid guid; + public uint lcid; + public tagSYSKIND syskind; + public ushort wMajorVerNum; + public ushort wMinorVerNum; + public ushort wLibFlags; + } + public enum tagSYSKIND + { + SYS_WIN16, + SYS_WIN32, + SYS_MAC, + SYS_WIN64 + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _wireSAFEARR_BRECORD + { + public uint Size; + [ComConversionLoss] + public IntPtr aRecord; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _wireSAFEARR_HAVEIID + { + public uint Size; + [ComConversionLoss] + public IntPtr apUnknown; + public Guid iid; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAH + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAUH + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCACY + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCADATE + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAFILETIME + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCACLSID + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCACLIPDATA + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCABSTR + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCABSTRBLOB + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCALPSTR + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCALPWSTR + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + [ComConversionLoss] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct tagCAPROPVARIANT + { + public uint cElems; + [ComConversionLoss] + public IntPtr pElems; + } + + */ +} +} +} diff --git a/Core/Momiji.Interop.Setupapi.h b/Core/Momiji.Interop.Setupapi.h new file mode 100644 index 0000000..9721f36 --- /dev/null +++ b/Core/Momiji.Interop.Setupapi.h @@ -0,0 +1,298 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Interop.Setupapi.h + windows multi media dll importer. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Interop.Guiddef.h" +#include "Momiji.Interop.Kernel32.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Interop { +namespace Setupapi { + +#define SETUP_API_DLLIMPORT WIN32_DLL_IMPORT("setupapi") +#define ADV_API_DLLIMPORT WIN32_DLL_IMPORT("advapi32") + + [System::FlagsAttribute] + public enum class DIGCF: System::UInt32 + { + DEFAULT = 0x00000001, // only valid with DIGCF_DEVICEINTERFACE + PRESENT = 0x00000002, + ALLCLASSES = 0x00000004, + PROFILE = 0x00000008, + DEVICEINTERFACE = 0x00000010, + }; + + public enum class SPDRP: System::UInt32 + { + DEVICEDESC = 0x00000000, // DeviceDesc = R/W, + HARDWAREID = 0x00000001, // HardwareID = R/W, + COMPATIBLEIDS = 0x00000002, // CompatibleIDs = R/W, + UNUSED0 = 0x00000003, // unused + SERVICE = 0x00000004, // Service = R/W, + UNUSED1 = 0x00000005, // unused + UNUSED2 = 0x00000006, // unused + CLASS = 0x00000007, // Class = R--tied to ClassGUID, + CLASSGUID = 0x00000008, // ClassGUID = R/W, + DRIVER = 0x00000009, // Driver = R/W, + CONFIGFLAGS = 0x0000000A, // ConfigFlags = R/W, + MFG = 0x0000000B, // Mfg = R/W, + FRIENDLYNAME = 0x0000000C, // FriendlyName = R/W, + LOCATION_INFORMATION = 0x0000000D, // LocationInformation = R/W, + PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E, // PhysicalDeviceObjectName = R, + CAPABILITIES = 0x0000000F, // Capabilities = R, + UI_NUMBER = 0x00000010, // UiNumber = R, + UPPERFILTERS = 0x00000011, // UpperFilters = R/W, + LOWERFILTERS = 0x00000012, // LowerFilters = R/W, + BUSTYPEGUID = 0x00000013, // BusTypeGUID = R, + LEGACYBUSTYPE = 0x00000014, // LegacyBusType = R, + BUSNUMBER = 0x00000015, // BusNumber = R, + ENUMERATOR_NAME = 0x00000016, // Enumerator Name = R, + SECURITY = 0x00000017, // Security = R/W, binary form, + SECURITY_SDS = 0x00000018, // Security = W, SDS form, + DEVTYPE = 0x00000019, // Device Type = R/W, + EXCLUSIVE = 0x0000001A, // Device is exclusive-access = R/W, + CHARACTERISTICS = 0x0000001B, // Device Characteristics = R/W, + ADDRESS = 0x0000001C, // Device Address = R, + UI_NUMBER_DESC_FORMAT = 0X0000001D, // UiNumberDescFormat = R/W, + DEVICE_POWER_DATA = 0x0000001E, // Device Power Data = R, + REMOVAL_POLICY = 0x0000001F, // Removal Policy = R, + REMOVAL_POLICY_HW_DEFAULT = 0x00000020, // Hardware Removal Policy = R, + REMOVAL_POLICY_OVERRIDE = 0x00000021, // Removal Policy Override = RW, + INSTALL_STATE = 0x00000022, // Device Install State = R, + LOCATION_PATHS = 0x00000023, // Device Location Paths = R, + BASE_CONTAINERID = 0x00000024, // Base ContainerID = R, + }; + + // + // Flags for SP_DEVICE_INTERFACE_DATA.Flags field. + // + [System::FlagsAttribute] + public enum class SPINT: System::UInt32 + { + ACTIVE = 0x00000001, + DEFAULT = 0x00000002, + REMOVED = 0x00000004, + }; + + + // + // Device information structure (references a device instance + // that is a member of a device information set) + // + WIN32_DLL_STRUCTLAYOUT public value struct SpDevinfoData { + System::UInt32 cbSize; + Guiddef::Guid ClassGuid; + System::UInt32 DevInst; // DEVINST handle + System::IntPtr Reserved; + + virtual System::String^ ToString() override + { + return + "cbSize["+cbSize+"] classGuid["+ClassGuid+"] devInst["+DevInst+"]"; + } + }; + + // + // Device interface information structure (references a device + // interface that is associated with the device information + // element that owns it). + // + WIN32_DLL_STRUCTLAYOUT public value struct SpDeviceInterfaceData { + System::UInt32 cbSize; + Guiddef::Guid InterfaceClassGuid; + SPINT Flags; + System::IntPtr Reserved; + + virtual System::String^ ToString() override + { + return + "cbSize["+cbSize+"] interfaceClassGuid["+InterfaceClassGuid+"] flags["+Flags.ToString("F")+"]"; + } + }; + + //TODO: 64bitの場合は8バイトでパッキングする必要がある + WIN32_DLL_STRUCTLAYOUT public value struct SpDeviceInterfaceDetailData { + System::UInt32 cbSize; + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=1024)] + System::String^ DevicePath; + + virtual System::String^ ToString() override + { + return + "cbSize["+cbSize+"] devicePath["+DevicePath+"]"; + } + }; + + public value class Function + { + public: + [System::Security::Permissions::SecurityPermissionAttribute(System::Security::Permissions::SecurityAction::InheritanceDemand, UnmanagedCode = true)] + ref class DeviceInfoSet + : public Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid + { + public: + DeviceInfoSet(): Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid(true) {}; + + protected: + virtual System::Boolean ReleaseHandle() override + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + if (this->IsInvalid) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] invalid",__FUNCTION__); + #endif + + return false; + } + + System::Boolean result = SetupDiDestroyDeviceInfoList(this->handle); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] result {1}",__FUNCTION__, result); + #endif + return result; + }; + }; + + SETUP_API_DLLIMPORT static DeviceInfoSet^ SetupDiGetClassDevs( + [InteropServices::In] Guiddef::Guid% classGuid, + [InteropServices::In] System::String^ enumerator, + [InteropServices::In] InteropServices::HandleRef hwndParent, + [InteropServices::In] DIGCF flags + ); + private: + SETUP_API_DLLIMPORT static System::Boolean SetupDiDestroyDeviceInfoList( + [InteropServices::In] System::IntPtr deviceInfoSet + ); + public: + SETUP_API_DLLIMPORT static System::Boolean SetupDiEnumDeviceInterfaces( + [InteropServices::In] DeviceInfoSet^ deviceInfoSet, + [InteropServices::In] SpDevinfoData^ deviceInfoData, + [InteropServices::In] Guiddef::Guid% interfaceClassGuid, + [InteropServices::In] System::UInt32 memberIndex, + [InteropServices::In, InteropServices::Out] SpDeviceInterfaceData% deviceInterfaceData + ); + + SETUP_API_DLLIMPORT static System::Boolean SetupDiGetDeviceInterfaceDetail( + [InteropServices::In] DeviceInfoSet^ deviceInfoSet, + [InteropServices::In] SpDeviceInterfaceData% deviceInterfaceData, + [InteropServices::In, InteropServices::Out] SpDeviceInterfaceDetailData% deviceInterfaceDetailData, + [InteropServices::In] System::UInt32 deviceInterfaceDetailDataSize, + [InteropServices::Out] System::UInt32% requiredSize, + [InteropServices::In, InteropServices::Out] SpDevinfoData% deviceInfoData + ); + + //サイズ取得用のオーバーロード + SETUP_API_DLLIMPORT static System::Boolean SetupDiGetDeviceInterfaceDetail( + [InteropServices::In] DeviceInfoSet^ deviceInfoSet, + [InteropServices::In] SpDeviceInterfaceData% deviceInterfaceData, + [InteropServices::In] System::IntPtr deviceInterfaceDetailData, + [InteropServices::In] System::UInt32 deviceInterfaceDetailDataSize, + [InteropServices::Out] System::UInt32% requiredSize, + [InteropServices::In] System::IntPtr deviceInfoData + ); + + SETUP_API_DLLIMPORT static System::Boolean SetupDiGetDeviceInterfaceAlias( + [InteropServices::In] DeviceInfoSet^ deviceInfoSet, + [InteropServices::In] SpDeviceInterfaceData% deviceInterfaceData, + [InteropServices::In] Guiddef::Guid% aliasInterfaceClassGuid, + [InteropServices::In, InteropServices::Out] SpDeviceInterfaceData% aliasDeviceInterfaceData + ); + + + SETUP_API_DLLIMPORT static System::Boolean SetupDiGetDeviceRegistryProperty( + [InteropServices::In] DeviceInfoSet^ deviceInfoSet, + [InteropServices::In] SpDevinfoData% deviceInfoData, + [InteropServices::In] SPDRP propertyDrp, + [InteropServices::Out] System::UInt32% propertyRegDataType, + [InteropServices::Out] System::Text::StringBuilder^ propertyBuffer, + [InteropServices::In] System::UInt32 propertyBufferSize, + [InteropServices::Out] System::UInt32% requiredSize + ); + + public: + [System::Security::Permissions::SecurityPermissionAttribute(System::Security::Permissions::SecurityAction::InheritanceDemand, UnmanagedCode = true)] + ref class RegKey + : public Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid + { + public: + RegKey(): Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid(true) {}; + + protected: + virtual System::Boolean ReleaseHandle() override + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + if (this->IsInvalid) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] invalid",__FUNCTION__); + #endif + + return false; + } + + System::UInt32 result = RegCloseKey(this->handle); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] result {1}",__FUNCTION__, result); + #endif + + return (result == 0); + }; + }; + + SETUP_API_DLLIMPORT static RegKey^ SetupDiOpenDeviceInterfaceRegKey( + [InteropServices::In] DeviceInfoSet^ deviceInfoSet, + [InteropServices::In] SpDeviceInterfaceData% deviceInterfaceData, + [InteropServices::In] System::UInt32 reserved, + [InteropServices::In] Interop::Kernel32::ACCESS_TYPES samDesired + ); + private: + ADV_API_DLLIMPORT static System::UInt32 RegCloseKey( + [InteropServices::In] System::IntPtr hKey + ); + + public: + ADV_API_DLLIMPORT static System::UInt32 RegQueryValueEx( + [InteropServices::In] RegKey^ hKey, + [InteropServices::In] System::String^ lpValueName, + [InteropServices::In] System::IntPtr lpReserved, + [InteropServices::Out] System::UInt32% lpType, + [InteropServices::In] System::IntPtr lpData, + [InteropServices::In, InteropServices::Out] System::UInt32% lpcbData + ); + }; + +} +} +} diff --git a/Core/Momiji.Interop.Vst.h b/Core/Momiji.Interop.Vst.h new file mode 100644 index 0000000..4f36167 --- /dev/null +++ b/Core/Momiji.Interop.Vst.h @@ -0,0 +1,726 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Vst.h + vst dll importer. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +using namespace System::Runtime; + +namespace Momiji{ +namespace Interop { +namespace Vst { + +#define VST_DLL_DELEGATE(_charset_) [InteropServices::UnmanagedFunctionPointerAttribute(InteropServices::CallingConvention::Cdecl, CharSet = InteropServices::CharSet::##_charset_##, SetLastError = false)] + + //------------------------------------------------------------------------------------------------------- + /** AEffect flags */ + //------------------------------------------------------------------------------------------------------- + [System::FlagsAttribute] + public enum class VstAEffectFlags: System::Int32 + { + //------------------------------------------------------------------------------------------------------- + effFlagsHasEditor = 1 << 0, //< set if the plug-in provides a custom editor + effFlagsCanReplacing = 1 << 4, //< supports replacing process mode (which should the default mode in VST 2.4) + effFlagsProgramChunks = 1 << 5, //< program data is handled in formatless chunks + effFlagsIsSynth = 1 << 8, //< plug-in is a synth (VSTi), Host may assign mixer channels for its outputs + effFlagsNoSoundInStop = 1 << 9, //< plug-in does not produce sound when input is all silence + effFlagsCanDoubleReplacing = 1 << 12, //< plug-in supports double precision processing + + effFlagsHasClipDeprecated = 1 << 1, //< \deprecated deprecated in VST 2.4 + effFlagsHasVuDeprecated = 1 << 2, //< \deprecated deprecated in VST 2.4 + effFlagsCanMonoDeprecated = 1 << 3, //< \deprecated deprecated in VST 2.4 + effFlagsExtIsAsyncDeprecated = 1 << 10, //< \deprecated deprecated in VST 2.4 + effFlagsExtHasBufferDeprecated = 1 << 11 //< \deprecated deprecated in VST 2.4 + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + /** String length limits (in characters excl. 0 byte) */ + //------------------------------------------------------------------------------------------------------- + public enum class VstStringConstants: System::Int32 + { + //------------------------------------------------------------------------------------------------------- + kVstMaxProgNameLen = 24, //< used for #effGetProgramName, #effSetProgramName, #effGetProgramNameIndexed + kVstMaxParamStrLen = 8, //< used for #effGetParamLabel, #effGetParamDisplay, #effGetParamName + kVstMaxVendorStrLen = 64, //< used for #effGetVendorString, #audioMasterGetVendorString + kVstMaxProductStrLen = 64, //< used for #effGetProductString, #audioMasterGetProductString + kVstMaxEffectNameLen = 32, //< used for #effGetEffectName + kVstMaxNameLen = 64, //< used for #MidiProgramName, #MidiProgramCategory, #MidiKeyName, #VstSpeakerProperties, #VstPinProperties + kVstMaxLabelLen = 64, //< used for #VstParameterProperties->label, #VstPinProperties->label + kVstMaxShortLabelLen = 8, //< used for #VstParameterProperties->shortLabel, #VstPinProperties->shortLabel + kVstMaxCategLabelLen = 24, //< used for #VstParameterProperties->label + kVstMaxFileNameLen = 100 //< used for #VstAudioFile->name + //------------------------------------------------------------------------------------------------------- + }; + + WIN32_DLL_STRUCTLAYOUT_ANSI public ref struct AEffect + { + public: + //------------------------------------------------------------------------------------------------------- + System::Int32 magic; //< must be #kEffectMagic ('VstP') + + /** Host to Plug-in dispatcher @see AudioEffect::dispatcher */ + System::IntPtr dispatcher; + + /** \deprecated Accumulating process mode is deprecated in VST 2.4! Use AEffect::processReplacing instead! */ + System::IntPtr processDeprecated; + + /** Set new value of automatable parameter @see AudioEffect::setParameter */ + System::IntPtr setParameter; + + /** Returns current value of automatable parameter @see AudioEffect::getParameter*/ + System::IntPtr getParameter; + + System::Int32 numPrograms; //< number of programs + System::Int32 numParams; //< all programs are assumed to have numParams parameters + System::Int32 numInputs; //< number of audio inputs + System::Int32 numOutputs; //< number of audio outputs + + VstAEffectFlags flags; //< @see VstAEffectFlags + + System::IntPtr resvd1; //< reserved for Host, must be 0 + System::IntPtr resvd2; //< reserved for Host, must be 0 + + System::Int32 initialDelay; //< for algorithms which need input in the first place (Group delay or latency in Samples). This value should be initialized in a resume state. + + System::Int32 realQualitiesDeprecated; //< \deprecated unused member + System::Int32 offQualitiesDeprecated; //< \deprecated unused member + System::Single ioRatioDeprecated; //< \deprecated unused member + + System::IntPtr object; //< #AudioEffect class pointer + System::IntPtr user; //< user-defined pointer + + System::Int32 uniqueID; //< registered unique identifier (register it at Steinberg 3rd party support Web). This is used to identify a plug-in during save+load of preset and project. + System::Int32 version; //< plug-in version (example 1100 for version 1.1.0.0) + + /** Process audio samples in replacing mode @see AudioEffect::processReplacing */ + System::IntPtr processReplacing; + + /** Process double-precision audio samples in replacing mode @see AudioEffect::processDoubleReplacing */ + System::IntPtr processDoubleReplacing; + + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValArray, SizeConst=56)] + array^ future; //< reserved for future use (please zero) + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + /** Basic dispatcher Opcodes (Host to Plug-in) */ + //------------------------------------------------------------------------------------------------------- + public enum class AEffectOpcodes: System::Int32 + { + effOpen = 0, ///< no arguments @see AudioEffect::open + effClose, ///< no arguments @see AudioEffect::close + + effSetProgram, ///< [value]: new program number @see AudioEffect::setProgram + effGetProgram, ///< [return value]: current program number @see AudioEffect::getProgram + effSetProgramName, ///< [ptr]: char* with new program name, limited to #kVstMaxProgNameLen @see AudioEffect::setProgramName + effGetProgramName, ///< [ptr]: char buffer for current program name, limited to #kVstMaxProgNameLen @see AudioEffect::getProgramName + + effGetParamLabel, ///< [ptr]: char buffer for parameter label, limited to #kVstMaxParamStrLen @see AudioEffect::getParameterLabel + effGetParamDisplay, ///< [ptr]: char buffer for parameter display, limited to #kVstMaxParamStrLen @see AudioEffect::getParameterDisplay + effGetParamName, ///< [ptr]: char buffer for parameter name, limited to #kVstMaxParamStrLen @see AudioEffect::getParameterName + + effGetVuDeprecated, ///< \deprecated deprecated in VST 2.4 + + effSetSampleRate, ///< [opt]: new sample rate for audio processing @see AudioEffect::setSampleRate + effSetBlockSize, ///< [value]: new maximum block size for audio processing @see AudioEffect::setBlockSize + effMainsChanged, ///< [value]: 0 means "turn off", 1 means "turn on" @see AudioEffect::suspend @see AudioEffect::resume + + effEditGetRect, ///< [ptr]: #ERect** receiving pointer to editor size @see ERect @see AEffEditor::getRect + effEditOpen, ///< [ptr]: system dependent Window pointer, e.g. HWND on Windows @see AEffEditor::open + effEditClose, ///< no arguments @see AEffEditor::close + + effEditDrawDeprecated, ///< \deprecated deprecated in VST 2.4 + effEditMouseDeprecated, ///< \deprecated deprecated in VST 2.4 + effEditKeyDeprecated, ///< \deprecated deprecated in VST 2.4 + + effEditIdle, ///< no arguments @see AEffEditor::idle + + effEditTopDeprecated, ///< \deprecated deprecated in VST 2.4 + effEditSleepDeprecated, ///< \deprecated deprecated in VST 2.4 + effIdentifyDeprecated, ///< \deprecated deprecated in VST 2.4 + + effGetChunk, ///< [ptr]: void** for chunk data address [index]: 0 for bank, 1 for program @see AudioEffect::getChunk + effSetChunk, ///< [ptr]: chunk data [value]: byte size [index]: 0 for bank, 1 for program @see AudioEffect::setChunk + + effProcessEvents, ///< [ptr]: #VstEvents* @see AudioEffectX::processEvents + + effCanBeAutomated, ///< [index]: parameter index [return value]: 1=true, 0=false @see AudioEffectX::canParameterBeAutomated + effString2Parameter, ///< [index]: parameter index [ptr]: parameter string [return value]: true for success @see AudioEffectX::string2parameter + + effGetNumProgramCategoriesDeprecated, ///< \deprecated deprecated in VST 2.4 + + effGetProgramNameIndexed, ///< [index]: program index [ptr]: buffer for program name, limited to #kVstMaxProgNameLen [return value]: true for success @see AudioEffectX::getProgramNameIndexed + + effCopyProgramDeprecated, ///< \deprecated deprecated in VST 2.4 + effConnectInputDeprecated, ///< \deprecated deprecated in VST 2.4 + effConnectOutputDeprecated, ///< \deprecated deprecated in VST 2.4 + + effGetInputProperties, ///< [index]: input index [ptr]: #VstPinProperties* [return value]: 1 if supported @see AudioEffectX::getInputProperties + effGetOutputProperties, ///< [index]: output index [ptr]: #VstPinProperties* [return value]: 1 if supported @see AudioEffectX::getOutputProperties + effGetPlugCategory, ///< [return value]: category @see VstPlugCategory @see AudioEffectX::getPlugCategory + + effGetCurrentPositionDeprecated, ///< \deprecated deprecated in VST 2.4 + effGetDestinationBufferDeprecated, ///< \deprecated deprecated in VST 2.4 + + effOfflineNotify, ///< [ptr]: #VstAudioFile array [value]: count [index]: start flag @see AudioEffectX::offlineNotify + effOfflinePrepare, ///< [ptr]: #VstOfflineTask array [value]: count @see AudioEffectX::offlinePrepare + effOfflineRun, ///< [ptr]: #VstOfflineTask array [value]: count @see AudioEffectX::offlineRun + + effProcessVarIo, ///< [ptr]: #VstVariableIo* @see AudioEffectX::processVariableIo + effSetSpeakerArrangement, ///< [value]: input #VstSpeakerArrangement* [ptr]: output #VstSpeakerArrangement* @see AudioEffectX::setSpeakerArrangement + + effSetBlockSizeAndSampleRateDeprecated, ///< \deprecated deprecated in VST 2.4 + + effSetBypass, ///< [value]: 1 = bypass, 0 = no bypass @see AudioEffectX::setBypass + effGetEffectName, ///< [ptr]: buffer for effect name, limited to #kVstMaxEffectNameLen @see AudioEffectX::getEffectName + + effGetErrorTextDeprecated, ///< \deprecated deprecated in VST 2.4 + + effGetVendorString, ///< [ptr]: buffer for effect vendor string, limited to #kVstMaxVendorStrLen @see AudioEffectX::getVendorString + effGetProductString, ///< [ptr]: buffer for effect vendor string, limited to #kVstMaxProductStrLen @see AudioEffectX::getProductString + effGetVendorVersion, ///< [return value]: vendor-specific version @see AudioEffectX::getVendorVersion + effVendorSpecific, ///< no definition, vendor specific handling @see AudioEffectX::vendorSpecific + effCanDo, ///< [ptr]: "can do" string [return value]: 0: "don't know" -1: "no" 1: "yes" @see AudioEffectX::canDo + effGetTailSize, ///< [return value]: tail size (for example the reverb time of a reverb plug-in); 0 is default (return 1 for 'no tail') + + effIdleDeprecated, ///< \deprecated deprecated in VST 2.4 + effGetIconDeprecated, ///< \deprecated deprecated in VST 2.4 + effSetViewPositionDeprecated, ///< \deprecated deprecated in VST 2.4 + + effGetParameterProperties, ///< [index]: parameter index [ptr]: #VstParameterProperties* [return value]: 1 if supported @see AudioEffectX::getParameterProperties + + effKeysRequiredDeprecated, ///< \deprecated deprecated in VST 2.4 + + effGetVstVersion, ///< [return value]: VST version @see AudioEffectX::getVstVersion + + effEditKeyDown, ///< [index]: ASCII character [value]: virtual key [opt]: modifiers [return value]: 1 if key used @see AEffEditor::onKeyDown + effEditKeyUp, ///< [index]: ASCII character [value]: virtual key [opt]: modifiers [return value]: 1 if key used @see AEffEditor::onKeyUp + effSetEditKnobMode, ///< [value]: knob mode 0: circular, 1: circular relativ, 2: linear (CKnobMode in VSTGUI) @see AEffEditor::setKnobMode + + effGetMidiProgramName, ///< [index]: MIDI channel [ptr]: #MidiProgramName* [return value]: number of used programs, 0 if unsupported @see AudioEffectX::getMidiProgramName + effGetCurrentMidiProgram, ///< [index]: MIDI channel [ptr]: #MidiProgramName* [return value]: index of current program @see AudioEffectX::getCurrentMidiProgram + effGetMidiProgramCategory, ///< [index]: MIDI channel [ptr]: #MidiProgramCategory* [return value]: number of used categories, 0 if unsupported @see AudioEffectX::getMidiProgramCategory + effHasMidiProgramsChanged, ///< [index]: MIDI channel [return value]: 1 if the #MidiProgramName(s) or #MidiKeyName(s) have changed @see AudioEffectX::hasMidiProgramsChanged + effGetMidiKeyName, ///< [index]: MIDI channel [ptr]: #MidiKeyName* [return value]: true if supported, false otherwise @see AudioEffectX::getMidiKeyName + + effBeginSetProgram, ///< no arguments @see AudioEffectX::beginSetProgram + effEndSetProgram, ///< no arguments @see AudioEffectX::endSetProgram + + effGetSpeakerArrangement, ///< [value]: input #VstSpeakerArrangement* [ptr]: output #VstSpeakerArrangement* @see AudioEffectX::getSpeakerArrangement + effShellGetNextPlugin, ///< [ptr]: buffer for plug-in name, limited to #kVstMaxProductStrLen [return value]: next plugin's uniqueID @see AudioEffectX::getNextShellPlugin + + effStartProcess, ///< no arguments @see AudioEffectX::startProcess + effStopProcess, ///< no arguments @see AudioEffectX::stopProcess + effSetTotalSampleToProcess, ///< [value]: number of samples to process, offline only! @see AudioEffectX::setTotalSampleToProcess + effSetPanLaw, ///< [value]: pan law [opt]: gain @see VstPanLawType @see AudioEffectX::setPanLaw + + effBeginLoadBank, ///< [ptr]: #VstPatchChunkInfo* [return value]: -1: bank can't be loaded, 1: bank can be loaded, 0: unsupported @see AudioEffectX::beginLoadBank + effBeginLoadProgram, ///< [ptr]: #VstPatchChunkInfo* [return value]: -1: prog can't be loaded, 1: prog can be loaded, 0: unsupported @see AudioEffectX::beginLoadProgram + + effSetProcessPrecision, ///< [value]: @see VstProcessPrecision @see AudioEffectX::setProcessPrecision + effGetNumMidiInputChannels, ///< [return value]: number of used MIDI input channels (1-15) @see AudioEffectX::getNumMidiInputChannels + effGetNumMidiOutputChannels, ///< [return value]: number of used MIDI output channels (1-15) @see AudioEffectX::getNumMidiOutputChannels + }; + + //------------------------------------------------------------------------------------------------------- + /** Basic dispatcher Opcodes (Plug-in to Host) */ + //------------------------------------------------------------------------------------------------------- + public enum class AudioMasterOpcodes: System::Int32 + { + //------------------------------------------------------------------------------------------------------- + audioMasterAutomate = 0, ///< [index]: parameter index [opt]: parameter value @see AudioEffect::setParameterAutomated + audioMasterVersion, ///< [return value]: Host VST version (for example 2400 for VST 2.4) @see AudioEffect::getMasterVersion + audioMasterCurrentId, ///< [return value]: current unique identifier on shell plug-in @see AudioEffect::getCurrentUniqueId + audioMasterIdle, ///< no arguments @see AudioEffect::masterIdle + audioMasterPinConnectedDeprecated, ///< \deprecated deprecated in VST 2.4 r2 + + audioMasterDeprecated, + audioMasterWantMidiDeprecated, ///< \deprecated deprecated in VST 2.4 + + audioMasterGetTime, ///< [return value]: #VstTimeInfo* or null if not supported [value]: request mask @see VstTimeInfoFlags @see AudioEffectX::getTimeInfo + audioMasterProcessEvents, ///< [ptr]: pointer to #VstEvents @see VstEvents @see AudioEffectX::sendVstEventsToHost + + audioMasterSetTimeDeprecated, ///< \deprecated deprecated in VST 2.4 + audioMasterTempoAtDeprecated, ///< \deprecated deprecated in VST 2.4 + audioMasterGetNumAutomatableParametersDeprecated, ///< \deprecated deprecated in VST 2.4 + audioMasterGetParameterQuantizationDeprecated, ///< \deprecated deprecated in VST 2.4 + + audioMasterIOChanged, ///< [return value]: 1 if supported @see AudioEffectX::ioChanged + + audioMasterNeedIdleDeprecated, ///< \deprecated deprecated in VST 2.4 + + audioMasterSizeWindow, ///< [index]: new width [value]: new height [return value]: 1 if supported @see AudioEffectX::sizeWindow + audioMasterGetSampleRate, ///< [return value]: current sample rate @see AudioEffectX::updateSampleRate + audioMasterGetBlockSize, ///< [return value]: current block size @see AudioEffectX::updateBlockSize + audioMasterGetInputLatency, ///< [return value]: input latency in audio samples @see AudioEffectX::getInputLatency + audioMasterGetOutputLatency, ///< [return value]: output latency in audio samples @see AudioEffectX::getOutputLatency + + audioMasterGetPreviousPlugDeprecated, ///< \deprecated deprecated in VST 2.4 + audioMasterGetNextPlugDeprecated, ///< \deprecated deprecated in VST 2.4 + audioMasterWillReplaceOrAccumulateDeprecated, ///< \deprecated deprecated in VST 2.4 + + audioMasterGetCurrentProcessLevel, ///< [return value]: current process level @see VstProcessLevels + audioMasterGetAutomationState, ///< [return value]: current automation state @see VstAutomationStates + + audioMasterOfflineStart, ///< [index]: numNewAudioFiles [value]: numAudioFiles [ptr]: #VstAudioFile* @see AudioEffectX::offlineStart + audioMasterOfflineRead, ///< [index]: bool readSource [value]: #VstOfflineOption* @see VstOfflineOption [ptr]: #VstOfflineTask* @see VstOfflineTask @see AudioEffectX::offlineRead + audioMasterOfflineWrite, ///< @see audioMasterOfflineRead @see AudioEffectX::offlineRead + audioMasterOfflineGetCurrentPass, ///< @see AudioEffectX::offlineGetCurrentPass + audioMasterOfflineGetCurrentMetaPass, ///< @see AudioEffectX::offlineGetCurrentMetaPass + + audioMasterSetOutputSampleRateDeprecated, ///< \deprecated deprecated in VST 2.4 + audioMasterGetOutputSpeakerArrangementDeprecated, ///< \deprecated deprecated in VST 2.4 + + audioMasterGetVendorString, ///< [ptr]: char buffer for vendor string, limited to #kVstMaxVendorStrLen @see AudioEffectX::getHostVendorString + audioMasterGetProductString, ///< [ptr]: char buffer for vendor string, limited to #kVstMaxProductStrLen @see AudioEffectX::getHostProductString + audioMasterGetVendorVersion, ///< [return value]: vendor-specific version @see AudioEffectX::getHostVendorVersion + audioMasterVendorSpecific, ///< no definition, vendor specific handling @see AudioEffectX::hostVendorSpecific + + audioMasterSetIconDeprecated, ///< \deprecated deprecated in VST 2.4 + + audioMasterCanDo, ///< [ptr]: "can do" string [return value]: 1 for supported + audioMasterGetLanguage, ///< [return value]: language code @see VstHostLanguage + + audioMasterOpenWindowDeprecated, ///< \deprecated deprecated in VST 2.4 + audioMasterCloseWindowDeprecated, ///< \deprecated deprecated in VST 2.4 + + audioMasterGetDirectory, ///< [return value]: FSSpec on MAC, else char* @see AudioEffectX::getDirectory + audioMasterUpdateDisplay, ///< no arguments + audioMasterBeginEdit, ///< [index]: parameter index @see AudioEffectX::beginEdit + audioMasterEndEdit, ///< [index]: parameter index @see AudioEffectX::endEdit + audioMasterOpenFileSelector, ///< [ptr]: VstFileSelect* [return value]: 1 if supported @see AudioEffectX::openFileSelector + audioMasterCloseFileSelector, ///< [ptr]: VstFileSelect* @see AudioEffectX::closeFileSelector + + audioMasterEditFileDeprecated, ///< \deprecated deprecated in VST 2.4 + + audioMasterGetChunkFileDeprecated, ///< \deprecated deprecated in VST 2.4 [ptr]: char[2048] or sizeof (FSSpec) [return value]: 1 if supported @see AudioEffectX::getChunkFile + + audioMasterGetInputSpeakerArrangementDeprecated, ///< \deprecated deprecated in VST 2.4 + + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + /** Parameter Properties used in #effGetParameterProperties. */ + //------------------------------------------------------------------------------------------------------- + WIN32_DLL_STRUCTLAYOUT_ANSI public value struct VstParameterProperties + { + public: + [System::FlagsAttribute] + enum class VstParameterFlags: System::Int32 + { + //------------------------------------------------------------------------------------------------------- + kVstParameterIsSwitch = 1 << 0, ///< parameter is a switch (on/off) + kVstParameterUsesIntegerMinMax = 1 << 1, ///< minInteger, maxInteger valid + kVstParameterUsesFloatStep = 1 << 2, ///< stepFloat, smallStepFloat, largeStepFloat valid + kVstParameterUsesIntStep = 1 << 3, ///< stepInteger, largeStepInteger valid + kVstParameterSupportsDisplayIndex = 1 << 4, ///< displayIndex valid + kVstParameterSupportsDisplayCategory = 1 << 5, ///< category, etc. valid + kVstParameterCanRamp = 1 << 6 ///< set if parameter value can ramp up/down + //------------------------------------------------------------------------------------------------------- + }; + + public: + //------------------------------------------------------------------------------------------------------- + System::Single stepFloat; //< System::Single step + System::Single smallStepFloat; //< small System::Single step + System::Single largeStepFloat; //< large System::Single step + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=safe_cast(VstStringConstants::kVstMaxLabelLen))] + System::String^ label; //< parameter label + VstParameterFlags flags; //< @see VstParameterFlags + System::Int32 minInteger; //< integer minimum + System::Int32 maxInteger; //< integer maximum + System::Int32 stepInteger; //< integer step + System::Int32 largeStepInteger; //< large integer step + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=safe_cast(VstStringConstants::kVstMaxShortLabelLen))] + System::String^ shortLabel; //< short label, recommended: 6 + delimiter + + // The following are for remote controller display purposes. + // Note that the kVstParameterSupportsDisplayIndex flag must be set. + // Host can scan all parameters, and find out in what order + // to display them: + + System::Int16 displayIndex; //< index where this parameter should be displayed (starting with 0) + + // Host can also possibly display the parameter group (category), such as... + // --------------------------- + // Osc 1 + // Wave Detune Octave Mod + // --------------------------- + // ...if the plug-in supports it (flag #kVstParameterSupportsDisplayCategory) + + System::Int16 category; //< 0: no category, else group index + 1 + System::Int16 numParametersInCategory; //< number of parameters in category + System::Int16 reserved; //< zero + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=safe_cast(VstStringConstants::kVstMaxCategLabelLen))] + System::String^ categoryLabel; //< category label, e.g. "Osc 1" + + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValArray, SizeConst=16)] + array^ future; //< reserved for future use + //------------------------------------------------------------------------------------------------------- + }; + + + //------------------------------------------------------------------------------------------------------- + /** Speaker Arrangement Types*/ + //------------------------------------------------------------------------------------------------------- + public enum class VstSpeakerArrangementType: System::Int32 + { + //------------------------------------------------------------------------------------------------------- + kSpeakerArrUserDefined = -2,//< user defined + kSpeakerArrEmpty = -1, //< empty arrangement + kSpeakerArrMono = 0, //< M + kSpeakerArrStereo, //< L R + kSpeakerArrStereoSurround, //< Ls Rs + kSpeakerArrStereoCenter, //< Lc Rc + kSpeakerArrStereoSide, //< Sl Sr + kSpeakerArrStereoCLfe, //< C Lfe + kSpeakerArr30Cine, //< L R C + kSpeakerArr30Music, //< L R S + kSpeakerArr31Cine, //< L R C Lfe + kSpeakerArr31Music, //< L R Lfe S + kSpeakerArr40Cine, //< L R C S (LCRS) + kSpeakerArr40Music, //< L R Ls Rs (Quadro) + kSpeakerArr41Cine, //< L R C Lfe S (LCRS+Lfe) + kSpeakerArr41Music, //< L R Lfe Ls Rs (Quadro+Lfe) + kSpeakerArr50, //< L R C Ls Rs + kSpeakerArr51, //< L R C Lfe Ls Rs + kSpeakerArr60Cine, //< L R C Ls Rs Cs + kSpeakerArr60Music, //< L R Ls Rs Sl Sr + kSpeakerArr61Cine, //< L R C Lfe Ls Rs Cs + kSpeakerArr61Music, //< L R Lfe Ls Rs Sl Sr + kSpeakerArr70Cine, //< L R C Ls Rs Lc Rc + kSpeakerArr70Music, //< L R C Ls Rs Sl Sr + kSpeakerArr71Cine, //< L R C Lfe Ls Rs Lc Rc + kSpeakerArr71Music, //< L R C Lfe Ls Rs Sl Sr + kSpeakerArr80Cine, //< L R C Ls Rs Lc Rc Cs + kSpeakerArr80Music, //< L R C Ls Rs Cs Sl Sr + kSpeakerArr81Cine, //< L R C Lfe Ls Rs Lc Rc Cs + kSpeakerArr81Music, //< L R C Lfe Ls Rs Cs Sl Sr + kSpeakerArr102, //< L R C Lfe Ls Rs Tfl Tfc Tfr Trl Trr Lfe2 + kNumSpeakerArr + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + /** Pin Properties used in #effGetInputProperties and #effGetOutputProperties. */ + //------------------------------------------------------------------------------------------------------- + WIN32_DLL_STRUCTLAYOUT_ANSI public value struct VstPinProperties + { + public: + [System::FlagsAttribute] + enum class VstPinPropertiesFlags: System::Int32 + { + //------------------------------------------------------------------------------------------------------- + kVstPinIsActive = 1 << 0, //< pin is active, ignored by Host + kVstPinIsStereo = 1 << 1, //< pin is first of a stereo pair + kVstPinUseSpeaker = 1 << 2 //< #VstPinProperties::arrangementType is valid and can be used to get the wanted arrangement + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + public: + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=safe_cast(VstStringConstants::kVstMaxLabelLen))] + System::String^ label; //< pin name + VstPinPropertiesFlags flags; //< @see VstPinPropertiesFlags + VstSpeakerArrangementType arrangementType; //< @see VstSpeakerArrangementType + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=safe_cast(VstStringConstants::kVstMaxShortLabelLen))] + System::String^ shortLabel; //< short name (recommended: 6 + delimiter) + + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValArray, SizeConst=48)] + array^ future; //< reserved for future use + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + // VstEvent + //------------------------------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------------------------- + /** A generic timestamped event. */ + //------------------------------------------------------------------------------------------------------- + WIN32_DLL_STRUCTLAYOUT_UNION_ANSI + //WIN32_DLL_STRUCTLAYOUT_ANSI + public value struct VstEvent + { + public: + //------------------------------------------------------------------------------------------------------- + /** VstEvent Types used by #VstEvent. */ + //------------------------------------------------------------------------------------------------------- + enum class VstEventTypes: System::Int32 + { + //------------------------------------------------------------------------------------------------------- + kVstMidiType = 1, //< MIDI event @see VstMidiEvent + kVstAudioTypeDeprecated, //< \deprecated unused event type + kVstVideoTypeDeprecated, //< \deprecated unused event type + kVstParameterTypeDeprecated, //< \deprecated unused event type + kVstTriggerTypeDeprecated, //< \deprecated unused event type + kVstSysExType //< MIDI system exclusive @see VstMidiSysexEvent + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + /** Flags used in #VstMidiEvent. */ + //------------------------------------------------------------------------------------------------------- + enum class VstMidiEventFlags: System::Int32 + { + //------------------------------------------------------------------------------------------------------- + kVstMidiEventIsRealtime = 1 << 0 //< means that this event is played life (not in playback from a sequencer track).\n This allows the Plug-In to handle these flagged events with higher priority, especially when the Plug-In has a big latency (AEffect::initialDelay) + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + public: +/* VstEvent() + { + this->byteSize = + InteropServices::Marshal::SizeOf(this) + - ( + 4 //InteropServices::Marshal::SizeOf(this->type) + + 4 //InteropServices::Marshal::SizeOf(this->byteSize) + ); + } +*/ + public: + [InteropServices::FieldOffset(0)] VstEventTypes type; //< @see VstEventTypes + [InteropServices::FieldOffset(4)] System::Int32 byteSize; //< size of this event, excl. type and byteSize + [InteropServices::FieldOffset(8)] System::Int32 deltaFrames; //< sample frames related to the current block start sample position + [InteropServices::FieldOffset(12)] System::Int32 _flags; //< generic flags, none defined yet + + //** VstMidiEvent ** + [InteropServices::FieldOffset(12)] VstMidiEventFlags flags; //< @see VstMidiEventFlags + [InteropServices::FieldOffset(16)] System::Int32 noteLength; //< (in sample frames) of entire note, if available, else 0 + [InteropServices::FieldOffset(20)] System::Int32 noteOffset; //< offset (in sample frames) into note from note start if available, else 0 + [InteropServices::FieldOffset(24)] System::Int32 midiData; //< 1 to 3 MIDI bytes; midiData[3] is reserved (zero) + [InteropServices::FieldOffset(24)] System::Byte midiData0; //< 1 to 3 MIDI bytes; midiData[3] is reserved (zero) + [InteropServices::FieldOffset(25)] System::Byte midiData1; + [InteropServices::FieldOffset(26)] System::Byte midiData2; + [InteropServices::FieldOffset(27)] System::Byte midiData3; + [InteropServices::FieldOffset(28)] System::Byte detune; //< -64 to +63 cents; for scales other than 'well-tempered' ('microtuning') + [InteropServices::FieldOffset(29)] System::Byte noteOffVelocity;//< Note Off Velocity [0, 127] + [InteropServices::FieldOffset(30)] System::Byte reserved1; //< zero (Reserved for future use) + [InteropServices::FieldOffset(31)] System::Byte reserved2; //< zero (Reserved for future use) + + //** VstMidiSysexEvent ** //TODO: 64bitに対応してない + [InteropServices::FieldOffset(16)] System::Int32 dumpBytes; //< byte size of sysexDump + [InteropServices::FieldOffset(20)] System::IntPtr resvd1; //< zero (Reserved for future use) + [InteropServices::FieldOffset(24)] System::IntPtr sysexDump; //< sysex dump + [InteropServices::FieldOffset(28)] System::IntPtr resvd2; //< zero (Reserved for future use) + //------------------------------------------------------------------------------------------------------- + + virtual System::String^ ToString() override + { + if (type == VstEventTypes::kVstMidiType) { + return + "type["+type.ToString("F")+"] byteSize["+byteSize+"] deltaFrames["+deltaFrames+"] flags["+flags.ToString("F")+"] noteLength["+noteLength+" noteOffset["+noteOffset+"] midiData["+midiData.ToString("X8")+":"+midiData0.ToString("X2")+":"+midiData1.ToString("X2")+":"+midiData2.ToString("X2")+":"+midiData3.ToString("X2")+"] detune["+detune+"] noteOffVelocity["+noteOffVelocity+"]"; + } else if (type == VstEventTypes::kVstSysExType) { + return + "type["+type.ToString("F")+"] byteSize["+byteSize+"] deltaFrames["+deltaFrames+"] _flags["+_flags+"] dumpBytes["+dumpBytes+" sysexDump["+sysexDump+"]"; + } else { + return + "type["+type.ToString("F")+"] byteSize["+byteSize+"] deltaFrames["+deltaFrames+"] _flags["+_flags+"]"; + } + } + }; + + + //------------------------------------------------------------------------------------------------------- + /** A block of events for the current processed audio block. */ + //------------------------------------------------------------------------------------------------------- + WIN32_DLL_STRUCTLAYOUT_ANSI public value struct VstEvents + { + //------------------------------------------------------------------------------------------------------- + public: + System::Int32 numEvents; //< number of Events in array + System::IntPtr reserved; //< zero (Reserved for future use) + //System::IntPtr events; //VstEvent* events[2]; ///< event pointer array, variable size + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + // VstTimeInfo + //------------------------------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------------------------- + /** VstTimeInfo requested via #audioMasterGetTime. @see AudioEffectX::getTimeInfo + + \note VstTimeInfo::samplePos :Current Position. It must always be valid, and should not cost a lot to ask for. The sample position is ahead of the time displayed to the user. In sequencer stop mode, its value does not change. A 32 bit integer is too small for sample positions, and it's a double to make it easier to convert between ppq and samples. + \note VstTimeInfo::ppqPos : At tempo 120, 1 quarter makes 1/2 second, so 2.0 ppq translates to 48000 samples at 48kHz sample rate. + .25 ppq is one sixteenth note then. if you need something like 480ppq, you simply multiply ppq by that scaler. + \note VstTimeInfo::barStartPos : Say we're at bars/beats readout 3.3.3. That's 2 bars + 2 q + 2 sixteenth, makes 2 * 4 + 2 + .25 = 10.25 ppq. at tempo 120, that's 10.25 * .5 = 5.125 seconds, times 48000 = 246000 samples (if my calculator servers me well :-). + \note VstTimeInfo::samplesToNextClock : MIDI Clock Resolution (24 per Quarter Note), can be negative the distance to the next midi clock (24 ppq, pulses per quarter) in samples. unless samplePos falls precicely on a midi clock, this will either be negative such that the previous MIDI clock is addressed, or positive when referencing the following (future) MIDI clock. + */ + //------------------------------------------------------------------------------------------------------- + WIN32_DLL_STRUCTLAYOUT_ANSI public value struct VstTimeInfo + { + public: + //------------------------------------------------------------------------------------------------------- + /** Flags used in #VstTimeInfo. */ + //------------------------------------------------------------------------------------------------------- + [System::FlagsAttribute] + enum class VstTimeInfoFlags: System::Int32 + { + //------------------------------------------------------------------------------------------------------- + kVstTransportChanged = 1, ///< indicates that play, cycle or record state has changed + kVstTransportPlaying = 1 << 1, ///< set if Host sequencer is currently playing + kVstTransportCycleActive = 1 << 2, ///< set if Host sequencer is in cycle mode + kVstTransportRecording = 1 << 3, ///< set if Host sequencer is in record mode + kVstAutomationWriting = 1 << 6, ///< set if automation write mode active (record parameter changes) + kVstAutomationReading = 1 << 7, ///< set if automation read mode active (play parameter changes) + kVstNanosValid = 1 << 8, ///< VstTimeInfo::nanoSeconds valid + kVstPpqPosValid = 1 << 9, ///< VstTimeInfo::ppqPos valid + kVstTempoValid = 1 << 10, ///< VstTimeInfo::tempo valid + kVstBarsValid = 1 << 11, ///< VstTimeInfo::barStartPos valid + kVstCyclePosValid = 1 << 12, ///< VstTimeInfo::cycleStartPos and VstTimeInfo::cycleEndPos valid + kVstTimeSigValid = 1 << 13, ///< VstTimeInfo::timeSigNumerator and VstTimeInfo::timeSigDenominator valid + kVstSmpteValid = 1 << 14, ///< VstTimeInfo::smpteOffset and VstTimeInfo::smpteFrameRate valid + kVstClockValid = 1 << 15 ///< VstTimeInfo::samplesToNextClock valid + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + /** SMPTE Frame Rates. */ + //------------------------------------------------------------------------------------------------------- + enum class VstSmpteFrameRate: System::Int32 + { + //------------------------------------------------------------------------------------------------------- + kVstSmpte24fps = 0, ///< 24 fps + kVstSmpte25fps = 1, ///< 25 fps + kVstSmpte2997fps = 2, ///< 29.97 fps + kVstSmpte30fps = 3, ///< 30 fps + kVstSmpte2997dfps = 4, ///< 29.97 drop + kVstSmpte30dfps = 5, ///< 30 drop + + kVstSmpteFilm16mm = 6, ///< Film 16mm + kVstSmpteFilm35mm = 7, ///< Film 35mm + kVstSmpte239fps = 10, ///< HDTV: 23.976 fps + kVstSmpte249fps = 11, ///< HDTV: 24.976 fps + kVstSmpte599fps = 12, ///< HDTV: 59.94 fps + kVstSmpte60fps = 13 ///< HDTV: 60 fps + //------------------------------------------------------------------------------------------------------- + }; + + //------------------------------------------------------------------------------------------------------- + public: + System::Double samplePos; ///< current Position in audio samples (always valid) + System::Double sampleRate; ///< current Sample Rate in Herz (always valid) + System::Double nanoSeconds; ///< System Time in nanoseconds (10^-9 second) + System::Double ppqPos; ///< Musical Position, in Quarter Note (1.0 equals 1 Quarter Note) + System::Double tempo; ///< current Tempo in BPM (Beats Per Minute) + System::Double barStartPos; ///< last Bar Start Position, in Quarter Note + System::Double cycleStartPos; ///< Cycle Start (left locator), in Quarter Note + System::Double cycleEndPos; ///< Cycle End (right locator), in Quarter Note + System::Int32 timeSigNumerator; ///< Time Signature Numerator (e.g. 3 for 3/4) + System::Int32 timeSigDenominator; ///< Time Signature Denominator (e.g. 4 for 3/4) + System::Int32 smpteOffset; ///< SMPTE offset (in SMPTE subframes (bits; 1/80 of a frame)). The current SMPTE position can be calculated using #samplePos, #sampleRate, and #smpteFrameRate. + System::Int32 smpteFrameRate; ///< @see VstSmpteFrameRate + System::Int32 samplesToNextClock; ///< MIDI Clock Resolution (24 Per Quarter Note), can be negative (nearest clock) + VstTimeInfoFlags flags; ///< @see VstTimeInfoFlags + //------------------------------------------------------------------------------------------------------- + }; + + + //------------------------------------------------------------------------------------------------------- + /** Variable IO for Offline Processing. */ + //------------------------------------------------------------------------------------------------------- + WIN32_DLL_STRUCTLAYOUT_ANSI public value struct VstVariableIo + { + //------------------------------------------------------------------------------------------------------- + System::IntPtr inputs; //< float** input audio buffers + System::IntPtr outputs; //< float** output audio buffers + System::Int32 numSamplesInput; //< number of incoming samples + System::Int32 numSamplesOutput; //< number of outgoing samples + System::IntPtr numSamplesInputProcessed; //< System::Int32* number of samples actually processed of input + System::IntPtr numSamplesOutputProcessed; //< System::Int32* number of samples actually processed of output + //------------------------------------------------------------------------------------------------------- + }; + + public value class AudioMasterCallBack + { + public: + ref class AudioMasterEventArgs: System::EventArgs + { + public: + System::IntPtr/*AEffect^*/ effect; + AudioMasterOpcodes opcode; + System::Int32 index; + System::IntPtr value; + System::IntPtr ptr; + System::Single opt; + System::IntPtr returnValue; + }; + + VST_DLL_DELEGATE(Ansi) delegate System::IntPtr Delegate( + [InteropServices::In]System::IntPtr/*AEffect^*/ effect, + [InteropServices::In]AudioMasterOpcodes opcode, + [InteropServices::In]System::Int32 index, + [InteropServices::In]System::IntPtr value, + [InteropServices::In]System::IntPtr ptr, + [InteropServices::In]System::Single opt + ); + }; + + + VST_DLL_DELEGATE(Ansi) public delegate System::IntPtr AEffectDispatcherProc( + [InteropServices::In]System::IntPtr/*AEffect^*/ effect, + [InteropServices::In]AEffectOpcodes opcode, + [InteropServices::In]System::Int32 index, + [InteropServices::In]System::IntPtr value, + [InteropServices::In]System::IntPtr ptr, + [InteropServices::In]System::Single opt + ); + + VST_DLL_DELEGATE(Ansi) public delegate void AEffectProcessProc( + [InteropServices::In]System::IntPtr/*AEffect^*/ effect, + [InteropServices::In]System::IntPtr inputs, + [InteropServices::In]System::IntPtr outputs, + [InteropServices::In]System::Int32 sampleFrames + ); + + VST_DLL_DELEGATE(Ansi) public delegate void AEffectProcessDoubleProc( + [InteropServices::In]System::IntPtr/*AEffect^*/ effect, + [InteropServices::In]System::IntPtr inputs, + [InteropServices::In]System::IntPtr outputs, + [InteropServices::In]System::Int32 sampleFrames + ); + + VST_DLL_DELEGATE(Ansi) public delegate void AEffectSetParameterProc( + [InteropServices::In]System::IntPtr/*AEffect^*/ effect, + [InteropServices::In]System::Int32 index, + [InteropServices::In]System::Single parameter + ); + + VST_DLL_DELEGATE(Ansi) public delegate System::Single AEffectGetParameterProc( + [InteropServices::In]System::IntPtr/*AEffect^*/ effect, + [InteropServices::In]System::Int32 index + ); + + VST_DLL_DELEGATE(Ansi) public delegate System::IntPtr VSTPluginMain( + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::FunctionPtr)] + AudioMasterCallBack::Delegate^ audioMaster + ); + + +} +} +} diff --git a/Core/Momiji.Interop.Winmm.h b/Core/Momiji.Interop.Winmm.h new file mode 100644 index 0000000..f8f57d2 --- /dev/null +++ b/Core/Momiji.Interop.Winmm.h @@ -0,0 +1,927 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Core.Winmm.h + windows multi media dll importer. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Interop.Guiddef.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Interop { +namespace Winmm { + +#define WIN_MM_DLLIMPORT WIN32_DLL_IMPORT("winmm") + + /** + + MMRESULT + + */ + public enum class MMRESULT: System::UInt32 { + NOERROR = 0, + + WAVERR_BASE = 32, + + MIDIERR_BASE = 64, + + TIMERR_BASE = 96, + TIMERR_NOCANDO = (TIMERR_BASE+1), // request not completed + }; + + public value class DriverCallBack + { + public: + enum class TYPE: System::UInt32 { + TYPEMASK = 0x00070000l, // callback type mask + NULL = 0x00000000l, // no callback + WINDOW = 0x00010000l, // dwCallback is a HWND + TASK = 0x00020000l, // dwCallback is a HTASK + FUNCTION = 0x00030000l, // dwCallback is a FARPROC + THREAD = TASK, // thread ID replaces 16 bit task + EVENT = 0x00050000l, // dwCallback is an EVENT Handle + + WAVE_FORMAT_QUERY = 0x0001, + WAVE_ALLOWSYNC = 0x0002, + WAVE_MAPPED = 0x0004, + WAVE_FORMAT_DIRECT = 0x0008, + WAVE_FORMAT_DIRECT_QUERY = (WAVE_FORMAT_QUERY | WAVE_FORMAT_DIRECT), + WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE = 0x0010, + }; + + enum class MM_EXT_WINDOW_MESSAGE: System::UInt32 { + WOM_OPEN = 0x3BB, // waveform output + WOM_CLOSE = 0x3BC, + WOM_DONE = 0x3BD, + + WIM_OPEN = 0x3BE, // waveform input + WIM_CLOSE = 0x3BF, + WIM_DATA = 0x3C0, + + MIM_OPEN = 0x3C1, // MIDI input + MIM_CLOSE = 0x3C2, + MIM_DATA = 0x3C3, + MIM_LONGDATA = 0x3C4, + MIM_ERROR = 0x3C5, + MIM_LONGERROR = 0x3C6, + MIM_MOREDATA = 0x3CC, // MIM_DONE w/ pending events + + MOM_OPEN = 0x3C7, // MIDI output + MOM_CLOSE = 0x3C8, + MOM_DONE = 0x3C9, + MOM_POSITIONCB = 0x3CA, // Callback for MEVT_POSITIONCB + + }; + + ref class DriverEventArgs: System::EventArgs + { + public: + System::IntPtr hdrvr; + MM_EXT_WINDOW_MESSAGE uMsg; + System::IntPtr dwUser; + System::IntPtr dw1; + System::IntPtr dw2; + }; + + delegate void Delegate( + System::IntPtr hdrvr, + MM_EXT_WINDOW_MESSAGE uMsg, + System::IntPtr dwUser, + System::IntPtr dw1, + System::IntPtr dw2 + ); + + }; + + // MIDI data block header + WIN32_DLL_STRUCTLAYOUT public ref struct MidiHeader { + // flags for dwFlags field of MIDIHDR structure + [System::FlagsAttribute] + enum class FLAG: System::UInt32 { + DONE = 0x00000001, // done bit + PREPARED = 0x00000002, // set if header prepared + INQUEUE = 0x00000004, // reserved for driver + ISSTRM = 0x00000008, // Buffer is stream buffer + }; + + System::IntPtr data; // pointer to locked data block + System::UInt32 bufferLength; // length of data in data block + System::UInt32 bytesRecorded; // used for input only + System::IntPtr user; // for client's use + FLAG flags; // assorted flags (see defines) + System::UInt32 next; // reserved for driver + System::IntPtr reserved; // reserved for driver + System::UInt32 offset; // Callback offset into buffer + //[InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValArray, SizeConst=8)] + // array^ reserve; // Reserved for MMSYSTEM + + System::IntPtr reserve1; + System::IntPtr reserve2; + System::IntPtr reserve3; + System::IntPtr reserve4; + System::IntPtr reserve5; + System::IntPtr reserve6; + System::IntPtr reserve7; + System::IntPtr reserve8; + + virtual System::String^ ToString() override + { + return + "data ["+data.ToString("X")+"] bufferLength ["+bufferLength+"] bytesRecorded ["+bytesRecorded+"] flags ["+flags.ToString("F")+"] next ["+next+"] reserved ["+reserved+"] offset ["+offset+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public ref struct MidiOutCapabilities { + // flags for wTechnology field of MIDIOUTCAPS structure + enum class MOD: System::UInt16 { + MIDIPORT = 1, // output port + SYNTH = 2, // generic internal synth + SQSYNTH = 3, // square wave internal synth + FMSYNTH = 4, // FM internal synth + MAPPER = 5, // MIDI mapper + WAVETABLE = 6, // hardware wavetable synth + SWSYNTH = 7, // software synth + }; + + //flags for dwSupport field of MIDIOUTCAPS structure + [System::FlagsAttribute] + enum class MIDICAPS: System::UInt32 { + VOLUME = 0x0001, // supports volume control + LRVOLUME = 0x0002, // separate left-right volume control + CACHE = 0x0004, + STREAM = 0x0008, // driver supports midiStreamOut directly + }; + + System::UInt16 manufacturerID; + System::UInt16 productID; + System::UInt32 driverVersion; + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=32)] + System::String^ productName; + MOD technology; + System::UInt16 voices; + System::UInt16 notes; + System::UInt16 channelMask; + MIDICAPS support; + + Guiddef::Guid manufacturerGuid; // for extensible MID mapping + Guiddef::Guid productGuid; // for extensible PID mapping + Guiddef::Guid nameGuid; // for name lookup in registry + }; + + WIN32_DLL_STRUCTLAYOUT public ref struct MidiInCapabilities { + //flags for dwSupport field of MIDIOUTCAPS structure + [System::FlagsAttribute] + enum class MIDICAPS: System::UInt32 { + VOLUME = 0x0001, // supports volume control + LRVOLUME = 0x0002, // separate left-right volume control + CACHE = 0x0004, + STREAM = 0x0008, // driver supports midiStreamOut directly + }; + + System::UInt16 manufacturerID; + System::UInt16 productID; + System::UInt32 driverVersion; + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=32)] + System::String^ productName; + MIDICAPS support; + + Guiddef::Guid manufacturerGuid; // for extensible MID mapping + Guiddef::Guid productGuid; // for extensible PID mapping + Guiddef::Guid nameGuid; // for name lookup in registry + }; + + public value class TimerCallBack + { + public: + enum class TYPE: System::UInt32 { + // flags for fuEvent parameter of timeSetEvent() function + ONESHOT = 0x0000, // program timer for single event + PERIODIC = 0x0001, // program for continuous periodic event + + CALLBACK_FUNCTION = 0x0000, // callback is function + CALLBACK_EVENT_SET = 0x0010, // callback is event - use SetEvent + CALLBACK_EVENT_PULSE = 0x0020, // callback is event - use PulseEvent + + KILL_SYNCHRONOUS = 0x0100, // This flag prevents the event from occurring + // after the user calls timeKillEvent() to + // destroy it. + }; + + ref class TimerEventArgs: System::EventArgs + { + public: + System::UInt32 uTimerID; + System::UInt32 uMsg; + System::IntPtr dwUser; + System::IntPtr dw1; + System::IntPtr dw2; + }; + + delegate void Delegate( + System::UInt32 uTimerID, + System::UInt32 uMsg, + System::IntPtr dwUser, + System::IntPtr dw1, + System::IntPtr dw2 + ); + }; + + WIN32_DLL_STRUCTLAYOUT public ref struct TimeCapabilities { + System::UInt32 periodMin; // minimum period supported + System::UInt32 periodMax; // maximum period supported + }; + + + // flags for dwFlags parameter in waveOutOpen() and waveInOpen() + [System::FlagsAttribute] + public enum class WAVE: System::UInt32 { + FORMAT_QUERY = 0x0001, + ALLOWSYNC = 0x0002, + MAPPED = 0x0004, + FORMAT_DIRECT = 0x0008, + FORMAT_DIRECT_QUERY = (FORMAT_QUERY | FORMAT_DIRECT), + MAPPED_DEFAULT_COMMUNICATION_DEVICE = 0x0010, + }; + + // wave data block header + WIN32_DLL_STRUCTLAYOUT public ref struct WaveHeader { + // flags for dwFlags field of WAVEHDR + [System::FlagsAttribute] + enum class FLAG: System::UInt32 { + DONE = 0x00000001, // done bit + PREPARED = 0x00000002, // set if this header has been prepared + BEGINLOOP = 0x00000004, // loop start block + ENDLOOP = 0x00000008, // loop end block + INQUEUE = 0x00000010, // reserved for driver + }; + + System::IntPtr data; // pointer to locked data buffer + System::UInt32 bufferLength; // length of data buffer + System::UInt32 bytesRecorded; // used for input only + System::IntPtr user; // for client's use + FLAG flags; // assorted flags (see defines) + System::UInt32 loops; // loop control counter + System::IntPtr next; // reserved for driver + System::IntPtr reserved; // reserved for driver + + virtual System::String^ ToString() override + { + return + "data["+data+"] bufferLength["+bufferLength+"] bytesRecorded["+bytesRecorded+"] user["+user+"] flags["+flags.ToString("F")+"] loops["+loops+"] next["+next+"] reserved["+reserved+"]"; + } + }; + + //defines for dwFormat field of WAVEINCAPS and WAVEOUTCAPS + [System::FlagsAttribute] + public enum class WAVE_FORMAT: System::UInt32 { + FORMAT_INVALID = 0x00000000, // invalid format + FORMAT_1M08 = 0x00000001, // 11.025 kHz, Mono, 8-bit + FORMAT_1S08 = 0x00000002, // 11.025 kHz, Stereo, 8-bit + FORMAT_1M16 = 0x00000004, // 11.025 kHz, Mono, 16-bit + FORMAT_1S16 = 0x00000008, // 11.025 kHz, Stereo, 16-bit + FORMAT_2M08 = 0x00000010, // 22.05 kHz, Mono, 8-bit + FORMAT_2S08 = 0x00000020, // 22.05 kHz, Stereo, 8-bit + FORMAT_2M16 = 0x00000040, // 22.05 kHz, Mono, 16-bit + FORMAT_2S16 = 0x00000080, // 22.05 kHz, Stereo, 16-bit + FORMAT_4M08 = 0x00000100, // 44.1 kHz, Mono, 8-bit + FORMAT_4S08 = 0x00000200, // 44.1 kHz, Stereo, 8-bit + FORMAT_4M16 = 0x00000400, // 44.1 kHz, Mono, 16-bit + FORMAT_4S16 = 0x00000800, // 44.1 kHz, Stereo, 16-bit + FORMAT_44M08 = 0x00000100, // 44.1 kHz, Mono, 8-bit + FORMAT_44S08 = 0x00000200, // 44.1 kHz, Stereo, 8-bit + FORMAT_44M16 = 0x00000400, // 44.1 kHz, Mono, 16-bit + FORMAT_44S16 = 0x00000800, // 44.1 kHz, Stereo, 16-bit + FORMAT_48M08 = 0x00001000, // 48 kHz, Mono, 8-bit + FORMAT_48S08 = 0x00002000, // 48 kHz, Stereo, 8-bit + FORMAT_48M16 = 0x00004000, // 48 kHz, Mono, 16-bit + FORMAT_48S16 = 0x00008000, // 48 kHz, Stereo, 16-bit + FORMAT_96M08 = 0x00010000, // 96 kHz, Mono, 8-bit + FORMAT_96S08 = 0x00020000, // 96 kHz, Stereo, 8-bit + FORMAT_96M16 = 0x00040000, // 96 kHz, Mono, 16-bit + FORMAT_96S16 = 0x00080000, // 96 kHz, Stereo, 16-bit + }; + + WIN32_DLL_STRUCTLAYOUT public ref struct WaveOutCapabilities { + //flags for dwSupport field of WAVEOUTCAPS + [System::FlagsAttribute] + enum class WAVECAPS: System::UInt32 { + PITCH = 0x0001, // supports pitch control + PLAYBACKRATE = 0x0002, // supports playback rate control + VOLUME = 0x0004, // supports volume control + LRVOLUME = 0x0008, // separate left-right volume control + SYNC = 0x0010, + SAMPLEACCURATE = 0x0020, + }; + + System::UInt16 manufacturerID; + System::UInt16 productID; + System::UInt32 driverVersion; + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=32)] + System::String^ productName; + WAVE_FORMAT formats; + System::UInt16 channels; + System::UInt16 reserved1; + WAVECAPS support; + Guiddef::Guid manufacturerGuid; // for extensible MID mapping + Guiddef::Guid productGuid; // for extensible PID mapping + Guiddef::Guid nameGuid; // for name lookup in registry + }; + + WIN32_DLL_STRUCTLAYOUT public ref struct WaveInCapabilities { + System::UInt16 manufacturerID; + System::UInt16 productID; + System::UInt32 driverVersion; + [InteropServices::MarshalAs(InteropServices::UnmanagedType::ByValTStr, SizeConst=32)] + System::String^ productName; + WAVE_FORMAT formats; + System::UInt16 channels; + System::UInt16 reserved1; + Guiddef::Guid manufacturerGuid; // for extensible MID mapping + Guiddef::Guid productGuid; // for extensible PID mapping + Guiddef::Guid nameGuid; // for name lookup in registry + }; + + + // general extended waveform format structure + // Use this for all NON PCM formats + // (information common to all formats) + WIN32_DLL_STRUCTLAYOUT public value struct WaveFormatEx + { + // flags for wFormatTag field of WAVEFORMAT + enum class FORMAT: System::UInt16 { + PCM = 0x0001, + ADPCM = 0x0002, + IEEE_FLOAT = 0x0003, + + EXTENSIBLE = 0xFFFE, + }; + + FORMAT formatType; // format type + System::UInt16 channels; // number of channels (i.e. mono, stereo...) + System::UInt32 samplesPerSecond; // sample rate + System::UInt32 averageBytesPerSecond; // for buffer estimation + System::UInt16 blockAlign; // block size of data + System::UInt16 bitsPerSample; // Number of bits per sample of mono data + System::UInt16 size; // The count in bytes of the size of extra information (after cbSize) + + virtual System::String^ ToString() override + { + return + "formatType["+formatType.ToString("F")+"] channels["+channels+"] samplesPerSecond["+samplesPerSecond+"] averageBytesPerSecond["+averageBytesPerSecond+"] blockAlign["+blockAlign+"] bitsPerSample["+bitsPerSample+"] size["+size+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct WaveFormat + { + WaveFormatEx::FORMAT formatType; // format type + System::UInt16 channels; // number of channels (i.e. mono, stereo...) + System::UInt32 samplesPerSecond; // sample rate + System::UInt32 averageBytesPerSecond; // for buffer estimation + System::UInt16 blockAlign; // block size of data + + virtual System::String^ ToString() override + { + return + "formatType["+formatType.ToString("F")+"] channels["+channels+"] samplesPerSecond["+samplesPerSecond+"] averageBytesPerSecond["+averageBytesPerSecond+"] blockAlign["+blockAlign+"]"; + } + }; + + WIN32_DLL_STRUCTLAYOUT public value struct PcmWaveFormat + { + WaveFormat wf; + System::UInt16 bitsPerSample; // Number of bits per sample of mono data + + virtual System::String^ ToString() override + { + return + "wf["+wf.ToString()+"] bitsPerSample["+bitsPerSample+"]"; + } + }; + + // + // New wave format development should be based on the + // WAVEFORMATEXTENSIBLE structure. WAVEFORMATEXTENSIBLE allows you to + // avoid having to register a new format tag with Microsoft. Simply + // define a new GUID value for the WAVEFORMATEXTENSIBLE.SubFormat field + // and use WAVE_FORMAT_EXTENSIBLE in the + // WAVEFORMATEXTENSIBLE.Format.wFormatTag field. + // + WIN32_DLL_STRUCTLAYOUT public value struct WaveFormatExtensiblePart + { + [System::FlagsAttribute] + enum class SPEAKER: System::UInt32 { + FRONT_LEFT = 0x00000001, + FRONT_RIGHT = 0x00000002, + FRONT_CENTER = 0x00000004, + LOW_FREQUENCY = 0x00000008, + BACK_LEFT = 0x00000010, + BACK_RIGHT = 0x00000020, + FRONT_LEFT_OF_CENTER = 0x00000040, + FRONT_RIGHT_OF_CENTER = 0x00000080, + BACK_CENTER = 0x00000100, + SIDE_LEFT = 0x00000200, + SIDE_RIGHT = 0x00000400, + TOP_CENTER = 0x00000800, + TOP_FRONT_LEFT = 0x00001000, + TOP_FRONT_CENTER = 0x00002000, + TOP_FRONT_RIGHT = 0x00004000, + TOP_BACK_LEFT = 0x00008000, + TOP_BACK_CENTER = 0x00010000, + TOP_BACK_RIGHT = 0x00020000, + RESERVED = 0x7FFC0000, // Bit mask locations reserved for future use + ALL = 0x80000000, // Used to specify that any possible permutation of speaker configurations + }; + + System::UInt16 validBitsPerSample; + SPEAKER channelMask; + Guiddef::Guid subFormat; + + virtual System::String^ ToString() override + { + return + "validBitsPerSample["+validBitsPerSample+"] channelMask["+channelMask.ToString("F")+"] subFormat["+subFormat+"]"; + } + }; + + + // + // extended waveform format structure used for all non-PCM formats. this + // structure is common to all non-PCM formats. + // + WIN32_DLL_STRUCTLAYOUT public value struct WaveFormatExtensible + { + WaveFormatEx wfe; + WaveFormatExtensiblePart exp; + + virtual System::String^ ToString() override + { + return + "wfe["+wfe.ToString()+"] exp["+exp.ToString()+"]"; + } + + }; + + public value class Function + { + public: + [System::Security::Permissions::SecurityPermissionAttribute(System::Security::Permissions::SecurityAction::InheritanceDemand, UnmanagedCode = true)] + ref class MidiOut + : public Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid + { + public: + MidiOut() + : Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid(true) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + }; + + protected: + [ConstrainedExecution::ReliabilityContract(ConstrainedExecution::Consistency::WillNotCorruptState, ConstrainedExecution::Cer::MayFail)] + virtual System::Boolean ReleaseHandle() override + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + MMRESULT mmResult = midiOutClose(this->handle); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] midiOutClose result {1}",__FUNCTION__, mmResult); + #endif + return (mmResult == Interop::Winmm::MMRESULT::NOERROR); + }; + }; + + WIN_MM_DLLIMPORT static System::UInt32 midiOutGetNumDevs(); + + WIN_MM_DLLIMPORT static MMRESULT midiOutGetDevCaps( + [InteropServices::In] System::UInt32 uDeviceID, + [InteropServices::Out] MidiOutCapabilities^ pmoc, + [InteropServices::In] System::UInt32 cbmoc + ); + + WIN_MM_DLLIMPORT static MMRESULT midiOutGetErrorText( + [InteropServices::In] MMRESULT mmrError, + [InteropServices::Out] System::Text::StringBuilder^ pszText, + [InteropServices::In] System::UInt32 cchText + ); + + WIN_MM_DLLIMPORT static MMRESULT midiOutOpen( + [InteropServices::Out] MidiOut^% phmo, + [InteropServices::In] System::UInt32 uDeviceID, + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::FunctionPtr)] + DriverCallBack::Delegate^ dwCallback, + [InteropServices::In] System::IntPtr dwInstance, + [InteropServices::In] DriverCallBack::TYPE fdwOpen + ); + private: + WIN_MM_DLLIMPORT static MMRESULT midiOutClose( + [InteropServices::In] System::IntPtr hmo + ); + public: + WIN_MM_DLLIMPORT static MMRESULT midiOutShortMsg( + [InteropServices::In] MidiOut^ hmo, + [InteropServices::In] System::UInt32 dwMsg + ); + + WIN_MM_DLLIMPORT static MMRESULT midiOutPrepareHeader( + [InteropServices::In] MidiOut^ hmo, + [InteropServices::In] System::IntPtr pmh, + [InteropServices::In] System::UInt32 cbmh + ); + + WIN_MM_DLLIMPORT static MMRESULT midiOutUnprepareHeader( + [InteropServices::In] MidiOut^ hmo, + [InteropServices::In] System::IntPtr pmh, + [InteropServices::In] System::UInt32 cbmh + ); + + WIN_MM_DLLIMPORT static MMRESULT midiOutLongMsg( + [InteropServices::In] MidiOut^ hmo, + [InteropServices::In] System::IntPtr pmh, + [InteropServices::In] System::UInt32 cbmh + ); + + WIN_MM_DLLIMPORT static MMRESULT midiOutReset( + [InteropServices::In] MidiOut^ hmo + ); + + //WINMMAPI MMRESULT WINAPI midiOutCachePatches( __in HMIDIOUT hmo, __in UINT uBank, __in_ecount(MIDIPATCHSIZE) LPWORD pwpa, __in UINT fuCache); + //WINMMAPI MMRESULT WINAPI midiOutCacheDrumPatches( __in HMIDIOUT hmo, __in UINT uPatch, __in_ecount(MIDIPATCHSIZE) LPWORD pwkya, __in UINT fuCache); + + WIN_MM_DLLIMPORT static MMRESULT midiOutGetID( + [InteropServices::In] MidiOut^ hmo, + [InteropServices::Out] System::UInt32% puDeviceID + ); + + WIN_MM_DLLIMPORT static MMRESULT midiOutMessage( + [InteropServices::In] MidiOut^ hmo, + [InteropServices::In] System::UInt32 uMsg, + [InteropServices::In] System::IntPtr dw1, + [InteropServices::In] System::IntPtr dw2 + ); + + [System::Security::Permissions::SecurityPermissionAttribute(System::Security::Permissions::SecurityAction::InheritanceDemand, UnmanagedCode = true)] + ref class MidiIn + : public Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid + { + public: + MidiIn() + : Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid(true) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + }; + + protected: + [ConstrainedExecution::ReliabilityContract(ConstrainedExecution::Consistency::WillNotCorruptState, ConstrainedExecution::Cer::MayFail)] + virtual System::Boolean ReleaseHandle() override + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + MMRESULT mmResult = midiInClose(this->handle); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] midiInClose result {1}",__FUNCTION__, mmResult); + #endif + return (mmResult == Interop::Winmm::MMRESULT::NOERROR); + }; + }; + + WIN_MM_DLLIMPORT static System::UInt32 midiInGetNumDevs(); + + WIN_MM_DLLIMPORT static MMRESULT midiInGetDevCaps( + [InteropServices::In] System::UInt32 uDeviceID, + [InteropServices::Out] MidiInCapabilities^ pmic, + [InteropServices::In] System::UInt32 cbmoc + ); + + WIN_MM_DLLIMPORT static MMRESULT midiInGetErrorText( + [InteropServices::In] MMRESULT mmrError, + [InteropServices::Out] System::Text::StringBuilder^ pszText, + [InteropServices::In] System::UInt32 cchText + ); + + WIN_MM_DLLIMPORT static MMRESULT midiInOpen( + [InteropServices::Out] MidiIn^% phmi, + [InteropServices::In] System::UInt32 uDeviceID, + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::FunctionPtr)] + DriverCallBack::Delegate^ dwCallback, + [InteropServices::In] System::IntPtr dwInstance, + [InteropServices::In] DriverCallBack::TYPE fdwOpen + ); + private: + WIN_MM_DLLIMPORT static MMRESULT midiInClose( + [InteropServices::In] System::IntPtr hmi + ); + public: + WIN_MM_DLLIMPORT static MMRESULT midiInPrepareHeader( + [InteropServices::In] MidiIn^ hmi, + [InteropServices::In] System::IntPtr pmh, + [InteropServices::In] System::UInt32 cbmh + ); + + WIN_MM_DLLIMPORT static MMRESULT midiInUnprepareHeader( + [InteropServices::In] MidiIn^ hmi, + [InteropServices::In] System::IntPtr pmh, + [InteropServices::In] System::UInt32 cbmh + ); + + WIN_MM_DLLIMPORT static MMRESULT midiInAddBuffer( + [InteropServices::In] MidiIn^ hmi, + [InteropServices::In] System::IntPtr pmh, + [InteropServices::In] System::UInt32 cbmh + ); + + WIN_MM_DLLIMPORT static MMRESULT midiInStart( + [InteropServices::In] MidiIn^ hmi + ); + + WIN_MM_DLLIMPORT static MMRESULT midiInStop( + [InteropServices::In] MidiIn^ hmi + ); + + WIN_MM_DLLIMPORT static MMRESULT midiInReset( + [InteropServices::In] MidiIn^ hmi + ); + + WIN_MM_DLLIMPORT static MMRESULT midiInGetID( + [InteropServices::In] MidiIn^ hmi, + [InteropServices::Out] System::UInt32% puDeviceID + ); + + WIN_MM_DLLIMPORT static MMRESULT midiInMessage( + [InteropServices::In] MidiIn^ hmi, + [InteropServices::In] System::UInt32 uMsg, + [InteropServices::In] System::IntPtr dw1, + [InteropServices::In] System::IntPtr dw2 + ); + + + //WINMMAPI MMRESULT WINAPI timeGetSystemTime( __out_bcount(cbmmt) LPMMTIME pmmt, __in UINT cbmmt); + + + WIN_MM_DLLIMPORT static System::UInt32 timeGetTime(); + + WIN_MM_DLLIMPORT static System::UInt32 timeSetEvent( + [InteropServices::In] System::UInt32 uDelay, + [InteropServices::In] System::UInt32 uResolution, + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::FunctionPtr)] + TimerCallBack::Delegate^ fptc, + [InteropServices::In] System::IntPtr dwUser, + [InteropServices::In] TimerCallBack::TYPE fuEvent + ); + + WIN_MM_DLLIMPORT static MMRESULT timeKillEvent( + [InteropServices::In] System::UInt32 uTimerID + ); + + WIN_MM_DLLIMPORT static MMRESULT timeGetDevCaps( + [InteropServices::Out] TimeCapabilities^ ptc, + [InteropServices::In] System::UInt32 cbtc + ); + /* + WIN_MM_DLLIMPORT static MMRESULT timeBeginPeriod( + [InteropServices::In] System::UInt32 uPeriod + ); + + WIN_MM_DLLIMPORT static MMRESULT timeEndPeriod( + [InteropServices::In] System::UInt32 uPeriod + ); + */ + + [System::Security::Permissions::SecurityPermissionAttribute(System::Security::Permissions::SecurityAction::InheritanceDemand, UnmanagedCode = true)] + ref class WaveOut + : public Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid + { + public: + WaveOut() + : Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid(true) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + }; + + protected: + [ConstrainedExecution::ReliabilityContract(ConstrainedExecution::Consistency::WillNotCorruptState, ConstrainedExecution::Cer::MayFail)] + virtual System::Boolean ReleaseHandle() override + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + MMRESULT mmResult = waveOutClose(this->handle); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] waveOutClose result {1}",__FUNCTION__, mmResult); + #endif + return (mmResult == Interop::Winmm::MMRESULT::NOERROR); + }; + }; + + WIN_MM_DLLIMPORT static System::UInt32 waveOutGetNumDevs(); + + WIN_MM_DLLIMPORT static MMRESULT waveOutGetDevCaps( + [InteropServices::In] System::UInt32 uDeviceID, + [InteropServices::Out] WaveOutCapabilities^ pwoc, + [InteropServices::In] System::UInt32 cbwoc + ); + + WIN_MM_DLLIMPORT static MMRESULT waveOutGetVolume( + [InteropServices::In] WaveOut^ hwo, + [InteropServices::Out] System::UInt32% pdwVolume + ); + + WIN_MM_DLLIMPORT static MMRESULT waveOutSetVolume( + [InteropServices::In] WaveOut^ hwo, + [InteropServices::In] System::UInt32 pdwVolume + ); + + WIN_MM_DLLIMPORT static MMRESULT waveOutGetErrorText( + [InteropServices::In] MMRESULT mmrError, + [InteropServices::Out] System::Text::StringBuilder^ pszText, + [InteropServices::In] System::UInt32 cchText + ); + + WIN_MM_DLLIMPORT static MMRESULT waveOutOpen( + [InteropServices::Out] WaveOut^% phwo, + [InteropServices::In] System::UInt32 uDeviceID, + [InteropServices::In] WaveFormatExtensible% pwfx, + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::FunctionPtr)] + DriverCallBack::Delegate^ dwCallback, + [InteropServices::In] System::IntPtr dwInstance, + [InteropServices::In] DriverCallBack::TYPE fdwOpen + ); + private: + WIN_MM_DLLIMPORT static MMRESULT waveOutClose( + [InteropServices::In] System::IntPtr hwo + ); + public: + WIN_MM_DLLIMPORT static MMRESULT waveOutPrepareHeader( + [InteropServices::In] WaveOut^ hwo, + [InteropServices::In] System::IntPtr pwh, + [InteropServices::In] System::UInt32 cbwh + ); + + WIN_MM_DLLIMPORT static MMRESULT waveOutUnprepareHeader( + [InteropServices::In] WaveOut^ hwo, + [InteropServices::In] System::IntPtr pwh, + [InteropServices::In] System::UInt32 cbwh + ); + + WIN_MM_DLLIMPORT static MMRESULT waveOutWrite( + [InteropServices::In] WaveOut^ hwo, + [InteropServices::In] System::IntPtr pwh, + [InteropServices::In] System::UInt32 cbwh + ); + + WIN_MM_DLLIMPORT static MMRESULT waveOutPause( + [InteropServices::In] WaveOut^ hwo + ); + + WIN_MM_DLLIMPORT static MMRESULT waveOutRestart( + [InteropServices::In] WaveOut^ hwo + ); + + WIN_MM_DLLIMPORT static MMRESULT waveOutReset( + [InteropServices::In] WaveOut^ hwo + ); + + WIN_MM_DLLIMPORT static MMRESULT waveOutBreakLoop( + [InteropServices::In] WaveOut^ hwo + ); + + /* + WINMMAPI MMRESULT WINAPI waveOutGetPosition( __in HWAVEOUT hwo, __inout_bcount(cbmmt) LPMMTIME pmmt, __in UINT cbmmt); + WINMMAPI MMRESULT WINAPI waveOutGetPitch( __in HWAVEOUT hwo, __out LPDWORD pdwPitch); + WINMMAPI MMRESULT WINAPI waveOutSetPitch( __in HWAVEOUT hwo, __in DWORD dwPitch); + WINMMAPI MMRESULT WINAPI waveOutGetPlaybackRate( __in HWAVEOUT hwo, __out LPDWORD pdwRate); + WINMMAPI MMRESULT WINAPI waveOutSetPlaybackRate( __in HWAVEOUT hwo, __in DWORD dwRate); + WINMMAPI MMRESULT WINAPI waveOutGetID( __in HWAVEOUT hwo, __out LPUINT puDeviceID); + WINMMAPI MMRESULT WINAPI waveOutMessage( __in_opt HWAVEOUT hwo, __in UINT uMsg, __in DWORD_PTR dw1, __in DWORD_PTR dw2); + */ + + [System::Security::Permissions::SecurityPermissionAttribute(System::Security::Permissions::SecurityAction::InheritanceDemand, UnmanagedCode = true)] + ref class WaveIn + : public Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid + { + public: + WaveIn() + : Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid(true) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + }; + + protected: + [ConstrainedExecution::ReliabilityContract(ConstrainedExecution::Consistency::WillNotCorruptState, ConstrainedExecution::Cer::MayFail)] + virtual System::Boolean ReleaseHandle() override + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + MMRESULT mmResult = waveInClose(this->handle); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] waveInClose result {1}",__FUNCTION__, mmResult); + #endif + return (mmResult == Interop::Winmm::MMRESULT::NOERROR); + }; + }; + + WIN_MM_DLLIMPORT static System::UInt32 waveInGetNumDevs(); + + WIN_MM_DLLIMPORT static MMRESULT waveInGetDevCaps( + [InteropServices::In] System::UInt32 uDeviceID, + [InteropServices::Out] WaveInCapabilities% pwic, + [InteropServices::In] System::UInt32 cbwic + ); + + WIN_MM_DLLIMPORT static MMRESULT waveInGetErrorText( + [InteropServices::In] MMRESULT mmrError, + [InteropServices::Out] System::Text::StringBuilder^ pszText, + [InteropServices::In] System::UInt32 cchText + ); + + WIN_MM_DLLIMPORT static MMRESULT waveInOpen( + [InteropServices::Out] WaveIn^% phwi, + [InteropServices::In] System::UInt32 uDeviceID, + [InteropServices::In] WaveFormatExtensible% pwfx, + [InteropServices::In][InteropServices::MarshalAs(InteropServices::UnmanagedType::FunctionPtr)] + DriverCallBack::Delegate^ dwCallback, + [InteropServices::In] System::IntPtr dwInstance, + [InteropServices::In] DriverCallBack::TYPE fdwOpen + ); + private: + WIN_MM_DLLIMPORT static MMRESULT waveInClose( + [InteropServices::In] System::IntPtr hwi + ); + public: + WIN_MM_DLLIMPORT static MMRESULT waveInPrepareHeader( + [InteropServices::In] WaveIn^ hwi, + [InteropServices::In] System::IntPtr pwh, + [InteropServices::In] System::UInt32 cbwh + ); + + WIN_MM_DLLIMPORT static MMRESULT waveInUnprepareHeader( + [InteropServices::In] WaveIn^ hwi, + [InteropServices::In] System::IntPtr pwh, + [InteropServices::In] System::UInt32 cbwh + ); + + WIN_MM_DLLIMPORT static MMRESULT waveInAddBuffer( + [InteropServices::In] WaveIn^ hwi, + [InteropServices::In] System::IntPtr pwh, + [InteropServices::In] System::UInt32 cbwh + ); + + WIN_MM_DLLIMPORT static MMRESULT waveInStart( + [InteropServices::In] WaveIn^ hwi + ); + + WIN_MM_DLLIMPORT static MMRESULT waveInStop( + [InteropServices::In] WaveIn^ hwi + ); + + WIN_MM_DLLIMPORT static MMRESULT waveInReset( + [InteropServices::In] WaveIn^ hwi + ); + + //WINMMAPI MMRESULT WINAPI waveInGetPosition( __in HWAVEIN hwi, __inout_bcount(cbmmt) LPMMTIME pmmt, __in UINT cbmmt); + //WINMMAPI MMRESULT WINAPI waveInGetID( __in HWAVEIN hwi, __in LPUINT puDeviceID); + //WINMMAPI MMRESULT WINAPI waveInMessage( __in_opt HWAVEIN hwi, __in UINT uMsg, __in_opt DWORD_PTR dw1, __in_opt DWORD_PTR dw2); + + + }; + +} +} +} diff --git a/Core/Momiji.Sequencer.Midi.Smf.cpp b/Core/Momiji.Sequencer.Midi.Smf.cpp new file mode 100644 index 0000000..cc37635 --- /dev/null +++ b/Core/Momiji.Sequencer.Midi.Smf.cpp @@ -0,0 +1,656 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Sequencer.Midi.Smf.cpp + stream component of standard midi file. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Sequencer.Midi.Smf.h" +#include "Momiji.Core.Midi.Data.h" +#include "Momiji.Util.h" + +namespace Momiji{ +namespace Sequencer { +namespace Midi { +namespace Smf { + + SmfStream::SmfStream(System::String^ path) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->Open(path); + this->CheckSMF(); + this->Rewind(); + } + + SmfStream::~SmfStream() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!SmfStream(); + } + + SmfStream::!SmfStream() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + if (this->_tracks != nullptr) + { + delete this->_tracks; + this->_tracks = nullptr; + } + + if (this->_view != nullptr) + { + delete this->_view; + this->_view = nullptr; + } + if (this->_mmap != nullptr) + { + delete this->_mmap; + this->_mmap = nullptr; + } + } + + void SmfStream::Open(System::String^ path) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] {1}",__FUNCTION__, path); + #endif + + auto info = gcnew System::IO::FileInfo(path); + + this->_mmap = + System::IO::MemoryMappedFiles::MemoryMappedFile::CreateFromFile( + info->FullName, + System::IO::FileMode::Open, + "momiji.smf", + info->Length, + System::IO::MemoryMappedFiles::MemoryMappedFileAccess::Read + ); + + this->_view = + this->_mmap->CreateViewAccessor( + 0, + 0, + System::IO::MemoryMappedFiles::MemoryMappedFileAccess::Read + ); + } + + void SmfStream::CheckSMF() + { + System::UInt64 offset = 0; + + this->_view->Read(offset, this->_smfHeader); + + this->_smfHeader.dwType = Util::ToHostOrder(this->_smfHeader.dwType); + this->_smfHeader.dwLength = Util::ToHostOrder(this->_smfHeader.dwLength); + this->_smfHeader.wFormat = Util::ToHostOrder(this->_smfHeader.wFormat); + this->_smfHeader.wNtrks = Util::ToHostOrder(this->_smfHeader.wNtrks); + this->_smfHeader.wDivition = Util::ToHostOrder(this->_smfHeader.wDivition); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,4:X}]",__FUNCTION__, this->_smfHeader.dwType); + System::Console::WriteLine("[{0}] [{1}]",__FUNCTION__, this->_smfHeader.dwLength); + System::Console::WriteLine("[{0}] [{1}]",__FUNCTION__, this->_smfHeader.wFormat); + System::Console::WriteLine("[{0}] [{1}]",__FUNCTION__, this->_smfHeader.wNtrks); + System::Console::WriteLine("[{0}] [{1}]",__FUNCTION__, this->_smfHeader.wDivition); + #endif + + safe_cast(this->_smfHeader.dwType); + safe_cast(this->_smfHeader.wFormat); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}]",__FUNCTION__, safe_cast(this->_smfHeader.dwType)); + System::Console::WriteLine("[{0}] [{1}]",__FUNCTION__, safe_cast(this->_smfHeader.wFormat)); + #endif + + offset += this->_smfHeader.dwLength + 8; + + this->_tracks = gcnew array(this->_smfHeader.wNtrks); + for(System::UInt16 idx = 0; idx < this->_smfHeader.wNtrks; idx++) + { + SMFTRACK_CHUNK smfTrack; + this->_view->Read(offset, smfTrack); + + smfTrack.dwType = Util::ToHostOrder(smfTrack.dwType); + smfTrack.dwLength = Util::ToHostOrder(smfTrack.dwLength); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1,4:X}]",__FUNCTION__, smfTrack.dwType); + System::Console::WriteLine("[{0}] [{1}]",__FUNCTION__, smfTrack.dwLength); + #endif + + safe_cast(smfTrack.dwType); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [{1}]",__FUNCTION__, safe_cast(smfTrack.dwType)); + #endif + + this->_tracks[idx] = + gcnew SmfTrack( + this, + (offset + 8), + (offset + 8 + smfTrack.dwLength - 1) + ); + + offset += smfTrack.dwLength + 8; + } + } + + //TODO: packetにIComparerを実装してもSortで反応してくれなかったので、仕方なくコレで。 + int IStreamPacketCompare(Core::IStreamPacket^ a, Core::IStreamPacket^ b) + { + //TODO: RPN・NRPNの塊は維持したままソートしないとダメだった + return a->tick.CompareTo(b->tick); + } + + array^ SmfStream::GetStreamPacket(System::Double deltaTime) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto result = gcnew System::Collections::Generic::List; + + for each(auto track in this->_tracks) + { + auto data = track->GetStreamPacket(deltaTime); + result->AddRange(data); + } + + // result->Sort(gcnew System::Comparison(IStreamPacketCompare)); + + return result->ToArray(); + } + + void SmfStream::Rewind() + { + for each (auto track in this->_tracks) + { + track->Rewind(); + } + + this->_speed = 100.0; + } + + SmfStream::SmfTrack::SmfTrack( + SmfStream^ stream, + System::UInt64 headOffset, + System::UInt64 tailOffset + ): _stream(stream), + _headOffset(headOffset), + _tailOffset(tailOffset), + _metaData(gcnew System::Collections::Generic::Dictionary) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->Rewind(); + } + + SmfStream::SmfTrack::~SmfTrack() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!SmfTrack(); + } + + SmfStream::SmfTrack::!SmfTrack() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + void SmfStream::SmfTrack::Rewind() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + this->_nowTick = .0; + + this->_metaData[MetaData::META_TYPE::SET_TEMPO] = gcnew MetaSetTempo(600000); + this->_metaData[MetaData::META_TYPE::PORT] = gcnew MetaPort(0); + this->_metaData[MetaData::META_TYPE::TIME_SIGNATURE] = gcnew MetaTimeSignature(4, 4, 24, 8); + this->_metaData[MetaData::META_TYPE::KEY_SIGNATURE] = gcnew MetaKeySignature(0, false); + + this->_headPacket = + gcnew SmfPacket( + this, + this->_headOffset, + 0, + 0 + ); + + this->_packet = this->_headPacket; + } + + array^ SmfStream::SmfTrack::GetStreamPacket(System::Double deltaTime) + { + auto result = gcnew System::Collections::Generic::List; + + auto packet = this->_packet; + + #ifdef _DEBUG + System::Console::WriteLine("[{0}][nowtick:{1}]",__FUNCTION__, this->_nowTick); + #endif + + auto metaSetTempo = safe_cast(this->_metaData[MetaData::META_TYPE::SET_TEMPO]); + this->_nowTick += (deltaTime * ((this->_stream->_smfHeader.wDivition * this->_stream->_speed * 10.0) / metaSetTempo->usecPerQNote)); + + while(packet->hasNext && (packet->tick <= this->_nowTick)) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}][tick:{1}]",__FUNCTION__, packet->tick); + #endif + + result->Add(packet); + packet = packet->next; + } + + this->_packet = packet; + return result->ToArray(); + } + + SmfStream::SmfTrack::SmfPacket::SmfPacket( + SmfTrack^ track, + System::UInt64 offset, + System::UInt64 previousTick, + System::Byte previousStatus + ): _track(track), _offset(offset), _isTerminate(false) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + auto tempOffset = this->_offset; + + //デルタタイム読み込み + this->_tick = previousTick + this->GetDeltaTime(tempOffset); + #ifdef _DEBUG + System::Console::WriteLine("[{0}][tick:{1}]",__FUNCTION__, this->_tick); + #endif + + //次にイベントデータ読み込み + this->_status = this->NextByte(tempOffset); + System::Byte param1 = 0; + + if (this->_status < 0x80) + {//ランニングステータス + param1 = this->_status; + this->_status = previousStatus; + } + else + { + param1 = this->NextByte(tempOffset); + } + + Core::IData^ data = nullptr; + + #ifdef _DEBUG + System::Console::WriteLine("[{0}][status:{1,2:X}]",__FUNCTION__, this->_status); + #endif + + auto metaPort = safe_cast(this->_track->_metaData[MetaData::META_TYPE::PORT]); + + switch (safe_cast(this->_status & 0xF0)) + { + case Core::Midi::MidiData::TYPE::NOTE_OFF :// {8x 128..143 | nn vv | n:note num; v:velocity} + case Core::Midi::MidiData::TYPE::NOTE_ON :// {9x 144..159 | nn vv | n:note num; v:velocity} + case Core::Midi::MidiData::TYPE::POLYHONIC_KEY_PRESSURE :// {Ax 160..176 | nn vv | n:note num; v:velocity} + case Core::Midi::MidiData::TYPE::CONTROL_CHANGE :// {Bx 176..191 | cc vv | n:ctrl num; v:value} + case Core::Midi::MidiData::TYPE::PITCH_WHILE_CHANGE :// {Ex 224..239 | ll mm | l:least sig; m:most sig} + { + data = + gcnew Core::Midi::ShortData( + metaPort->number, + this->_status, + param1, + this->NextByte(tempOffset) + ); + break; + } + case Core::Midi::MidiData::TYPE::PROGRAM_CHANGE :// {Cx 192..207 | pp | p:prog num} + case Core::Midi::MidiData::TYPE::CNANNEL_PRESSURE :// {Dx 208..223 | cc | c:chan num} + { + data = + gcnew Core::Midi::ShortData( + metaPort->number, + this->_status, + param1, + 0 + ); + break; + } + case Core::Midi::MidiData::TYPE::SYSTEM_MESSAGE :// {Fx 240..255 | ll dd..dd} + { + switch(safe_cast(this->_status)) + { + case Core::Midi::MidiData::TYPE::SYSTEM_EXCLUSIVE :// {F0 length ID data..data F7} + { + auto size = param1; + auto longData = gcnew array(size+1); + longData[0] = this->_status; + this->NextByte(longData, tempOffset, 1, size); + + data = + gcnew Core::Midi::LongData( + metaPort->number, + longData, + longData->Length + ); + break; + } + case Core::Midi::MidiData::TYPE::META :// {FF: type length bytes} + { + auto type = param1; + auto size = this->NextByte(tempOffset); + //TODO 読み取りに長さチェックを加える + auto bytes = gcnew array(size+1); + if (size > 0) + { + this->NextByte(bytes, tempOffset, 0, size); + } + bytes[size] = 0; + + #ifdef _DEBUG + System::Console::WriteLine("[{0}][type:{1,2:X}][size:{2}]]",__FUNCTION__, type, size); + #endif + + auto metaType = safe_cast(type); + + switch(metaType) + { + case MetaData::META_TYPE::SEQUENCE_NUMBER: // {FF: '00' 02 ss ss} + { + data = + gcnew MetaSequenceNumber( + Util::ToHostOrder(System::BitConverter::ToUInt16(bytes,0)) + ); + break; + } + case MetaData::META_TYPE::TEXT_EVENT: // {FF: '01' length text} + { + data = + gcnew MetaText( + "" + ); + break; + } + case MetaData::META_TYPE::COPYRIGHT_NOTICE:// {FF: '02' length text} + { + data = + gcnew MetaCopyrightNotice( + "" + ); + break; + } + case MetaData::META_TYPE::TRACK_NAME: // {FF: '03' length text} + { + data = + gcnew MetaTrackName( + "" + ); + break; + } + case MetaData::META_TYPE::INSTRUMENT_NAME: // {FF: '04' length text} + { + data = + gcnew MetaInstrumentName( + "" + ); + break; + } + case MetaData::META_TYPE::LYRIC:// {FF: '05' length text} + { + data = + gcnew MetaLyric( + "" + ); + break; + } + case MetaData::META_TYPE::MARKER:// {FF: '06' length text} + { + data = + gcnew MetaMarker( + "" + ); + break; + } + case MetaData::META_TYPE::CUE_POINT:// {FF: '07' length text} + { + data = + gcnew MetaCuePoint( + "" + ); + break; + } + case MetaData::META_TYPE::PROGRAM_NAME:// {FF: '08' length text} + { + data = + gcnew MetaProgramName( + "" + ); + break; + } + case MetaData::META_TYPE::DEVICE_NAME: // {FF: '09' length text} + { + data = + gcnew MetaDeviceName( + "" + ); + break; + } + case MetaData::META_TYPE::PORT: // {FF: '21' length PORT ??} < 2バイト目の役割が不明; + { + System::UInt16 port = bytes[0]; + + data = + gcnew MetaPort( + port //ToHostOrder(System::BitConverter::ToUInt16(bytes,0)) + ); + break; + } + case MetaData::META_TYPE::END_OF_TRACK: // {FF: '2F' 00} + { + data = + gcnew MetaEndOfTrack(); + + this->_isTerminate = true; + break; + } + case MetaData::META_TYPE::SET_TEMPO: // {FF: '51' 03 tt tt tt = microceconds/quarter note( Tempo = (60×10^6)÷MetaTempo )} + { + auto tempo = gcnew array(4); + tempo[0] = 0; + tempo[1] = bytes[0]; + tempo[2] = bytes[1]; + tempo[3] = bytes[2]; + + data = + gcnew MetaSetTempo( + Util::ToHostOrder(System::BitConverter::ToUInt32(tempo, 0)) + ); + + break; + } + case MetaData::META_TYPE::SMPTE_OFFSET: // {FF: '54' 05 hr mn se fr ff} + { + data = + gcnew MetaSMPTEOffset( + bytes[0], + bytes[1], + bytes[2], + bytes[3], + bytes[4] + ); + break; + } + case MetaData::META_TYPE::TIME_SIGNATURE: // {FF: '58' 04 nn dd cc bb} + { + data = + gcnew MetaTimeSignature( + bytes[0], + 2 ^ bytes[1], + bytes[2], + bytes[3] + ); + break; + } + case MetaData::META_TYPE::KEY_SIGNATURE: // {FF: '59' 02 sf mi} + { + data = + gcnew MetaKeySignature( + bytes[0], + System::BitConverter::ToBoolean(bytes,1) + ); + break; + } + case MetaData::META_TYPE::SEQ_SP_METAEVENT: // {FF: '7F' length data ユーザ定義メタ} + { + data = nullptr; + break; + } + } + + auto metaData = safe_cast(data); + if ( + metaData->conductor + && (safe_cast(this->_track->_stream->_smfHeader.wFormat) == SmfStream::FORMAT::MULTIPLE_SYNC) + ) + { + for each(SmfTrack^ track in this->_track->_stream->_tracks) + { + track->_metaData[metaType] = metaData; + } + } + else + { + this->_track->_metaData[metaType] = metaData; + } + + break; + } + default: + { + throw gcnew SmfException("ステータス[{0,2:X}]は、対応していない。"); + } + } + break; + } + default: + { + //ここに到達できない + throw gcnew SmfException("ロジック不正"); + } + } + + this->_data = data; + #ifdef _DEBUG + System::Console::WriteLine("[{0}][{1}]",__FUNCTION__, data); + #endif + + this->_nextOffset = tempOffset; + } + + SmfStream::SmfTrack::SmfPacket::~SmfPacket() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!SmfPacket(); + } + SmfStream::SmfTrack::SmfPacket::!SmfPacket() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + } + + Core::IStreamPacket^ SmfStream::SmfTrack::SmfPacket::next::get() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + if (!this->hasNext) + { + throw gcnew SmfException("次のデータはありません。"); + } + + return + gcnew SmfPacket( + this->_track, + this->_nextOffset, + this->_tick, + this->_status + ); + } + + System::UInt32 SmfStream::SmfTrack::SmfPacket::GetDeltaTime(System::UInt64% tempOffset) + { + System::UInt32 result = 0; + + for (auto idx = 0; idx < 4; idx++) + { + auto data = this->NextByte(tempOffset); + result = ((result << 7) | (data & 0x7F)); + if ((data & 0x80) == 0) break; + } + + return result; + } + + System::Byte SmfStream::SmfTrack::SmfPacket::NextByte(System::UInt64% tempOffset) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + return this->_track->_stream->_view->ReadByte(tempOffset++); + } + + void SmfStream::SmfTrack::SmfPacket::NextByte( + array^ dest, + System::UInt64% tempOffset, + System::Byte start, + System::Byte size + ) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->_track->_stream->_view->ReadArray(tempOffset, dest, start, size); + tempOffset += size; + } + + +} +} +} +} diff --git a/Core/Momiji.Sequencer.Midi.Smf.h b/Core/Momiji.Sequencer.Midi.Smf.h new file mode 100644 index 0000000..7530152 --- /dev/null +++ b/Core/Momiji.Sequencer.Midi.Smf.h @@ -0,0 +1,478 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Sequencer.Midi.Smf.h + stream component of standard midi file. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using +#include "Momiji.Core.Interface.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Sequencer { +namespace Midi { +namespace Smf { + + + public ref class MetaData abstract + : public Core::IData + { + public: + enum class META_TYPE: System::Byte + { + SEQUENCE_NUMBER = 0x00, // {FF: '00' 02 ss ss} + TEXT_EVENT = 0x01, // {FF: '01' length text} + COPYRIGHT_NOTICE = 0x02, // {FF: '02' length text} + TRACK_NAME = 0x03, // {FF: '03' length text} + INSTRUMENT_NAME = 0x04, // {FF: '04' length text} + LYRIC = 0x05, // {FF: '05' length text} + MARKER = 0x06, // {FF: '06' length text} + CUE_POINT = 0x07, // {FF: '07' length text} + PROGRAM_NAME = 0x08, // {FF: '08' length text} + DEVICE_NAME = 0x09, // {FF: '09' length text} + + PORT = 0x21, // {FF: '21' length PORT ??} < 2バイト目の役割が不明; + END_OF_TRACK = 0x2F, // {FF: '2F' 00} + SET_TEMPO = 0x51, // {FF: '51' 03 tt tt tt = microceconds/quarter note( Tempo = (60×10^6)÷MetaTempo )} + SMPTE_OFFSET = 0x54, // {FF: '54' 05 hr mn se fr ff} + TIME_SIGNATURE = 0x58, // {FF: '58' 04 nn dd cc bb} + /* { + nn / 2^dd + cc :the number of MIDI clocks in a metronome click (MIDI Clocks / Click) + dd :the number of notated 32nd-notes in a MIDI quarter-note (32nd Notes / MIDI Clocks) + 4分音符中の32分音符の数:8に決まってます。 + + }*/ + KEY_SIGNATURE = 0x59, // {FF: '59' 02 sf mi} + /* { + sf = -7 : 7 flats + sf = -1 : 1 flat + sf = 0 : key of C + sf = 1 : 1 sharp + sf = 7 : 7 sharps + + mi = 0 : major key + mi = 1 : minor key + }*/ + + SEQ_SP_METAEVENT = 0x7F, // {FF: '7F' length data ユーザ定義メタ} + }; + private: + META_TYPE _type; + System::Boolean _conductor; + public: + MetaData( + META_TYPE type, + System::Boolean conductor + ) : _type(type), _conductor(conductor) {} + + property META_TYPE type { META_TYPE get() {return this->_type;} } + property System::Boolean conductor { System::Boolean get() {return this->_conductor;} } + }; + + public ref class MetaSequenceNumber sealed + : public MetaData + { + private: + System::UInt16 _number; + + public: + MetaSequenceNumber( + System::UInt16 number + ): MetaData(META_TYPE::SEQUENCE_NUMBER, false), _number(number) {} + + property System::UInt16 number { System::UInt16 get() {return this->_number;} } + }; + + public ref class MetaText sealed + : public MetaData + { + private: + System::String^ _text; + public: + MetaText( + System::String^ text + ): MetaData(META_TYPE::TEXT_EVENT, false), _text(text) {} + + property System::String^ text { System::String^ get() {return this->_text;} } + }; + + public ref class MetaCopyrightNotice sealed + : public MetaData + { + private: + System::String^ _text; + public: + MetaCopyrightNotice( + System::String^ text + ): MetaData(META_TYPE::COPYRIGHT_NOTICE, false), _text(text) {} + + property System::String^ text { System::String^ get() {return this->_text;} } + }; + + public ref class MetaTrackName sealed + : public MetaData + { + private: + System::String^ _text; + public: + MetaTrackName( + System::String^ text + ): MetaData(META_TYPE::TRACK_NAME, false), _text(text) {} + + property System::String^ text { System::String^ get() {return this->_text;} } + }; + public ref class MetaInstrumentName sealed + : public MetaData + { + private: + System::String^ _text; + public: + MetaInstrumentName( + System::String^ text + ): MetaData(META_TYPE::INSTRUMENT_NAME, false), _text(text) {} + + property System::String^ text { System::String^ get() {return this->_text;} } + }; + public ref class MetaLyric sealed + : public MetaData + { + private: + System::String^ _text; + public: + MetaLyric( + System::String^ text + ): MetaData(META_TYPE::LYRIC, false), _text(text) {} + + property System::String^ text { System::String^ get() {return this->_text;} } + }; + public ref class MetaMarker sealed + : public MetaData + { + private: + System::String^ _text; + public: + MetaMarker( + System::String^ text + ): MetaData(META_TYPE::MARKER, false), _text(text) {} + + property System::String^ text { System::String^ get() {return this->_text;} } + }; + public ref class MetaCuePoint sealed + : public MetaData + { + private: + System::String^ _text; + public: + MetaCuePoint( + System::String^ text + ): MetaData(META_TYPE::CUE_POINT, false), _text(text) {} + + property System::String^ text { System::String^ get() {return this->_text;} } + }; + public ref class MetaProgramName sealed + : public MetaData + { + private: + System::String^ _text; + public: + MetaProgramName( + System::String^ text + ): MetaData(META_TYPE::PROGRAM_NAME, false), _text(text) {} + + property System::String^ text { System::String^ get() {return this->_text;} } + }; + public ref class MetaDeviceName sealed + : public MetaData + { + private: + System::String^ _text; + public: + MetaDeviceName( + System::String^ text + ): MetaData(META_TYPE::DEVICE_NAME, false), _text(text) {} + + property System::String^ text { System::String^ get() {return this->_text;} } + }; + + public ref class MetaPort sealed + : public MetaData + { + private: + System::UInt16 _number; + + public: + MetaPort( + System::UInt16 number + ): MetaData(META_TYPE::PORT, false), _number(number) {} + + property System::UInt16 number { System::UInt16 get() {return this->_number;} } + }; + + public ref class MetaEndOfTrack sealed + : public MetaData + { + public: + MetaEndOfTrack( + ): MetaData(META_TYPE::END_OF_TRACK, false) {} + }; + + public ref class MetaSetTempo sealed + : public MetaData + { + private: + System::UInt32 _usecPerQNote; + public: + MetaSetTempo( + System::UInt32 usecPerQNote + ): MetaData(META_TYPE::SET_TEMPO, true), _usecPerQNote(usecPerQNote) {} + + property System::UInt32 usecPerQNote { System::UInt32 get() {return this->_usecPerQNote;} } + }; + + public ref class MetaSMPTEOffset sealed + : public MetaData + { + private: + System::Byte _hour; + System::Byte _minute; + System::Byte _second; + System::Byte _frame; + System::Byte _subFrame; + public: + MetaSMPTEOffset( + System::Byte hour, + System::Byte minute, + System::Byte second, + System::Byte frame, + System::Byte subFrame + ): MetaData(META_TYPE::SMPTE_OFFSET, true), _hour(hour), _minute(minute), _second(second), _frame(frame), _subFrame(subFrame) {} + + property System::Byte hour { System::Byte get() {return this->_hour;} } + property System::Byte minute { System::Byte get() {return this->_minute;} } + property System::Byte second { System::Byte get() {return this->_second;} } + property System::Byte frame { System::Byte get() {return this->_frame;} } + property System::Byte subFrame { System::Byte get() {return this->_subFrame;} } + }; + + public ref class MetaTimeSignature sealed + : public MetaData + { + private: + System::Byte _bar; + System::Byte _beat; + System::Byte _metronome; + System::Byte _notes; + public: + MetaTimeSignature( + System::Byte bar, + System::Byte beat, + System::Byte metronome, + System::Byte notes + ): MetaData(META_TYPE::TIME_SIGNATURE, true), _bar(bar), _beat(beat), _metronome(metronome), _notes(notes) {} + + property System::Byte bar { System::Byte get() {return this->_bar;} } + property System::Byte beat { System::Byte get() {return this->_beat;} } + property System::Byte metronome { System::Byte get() {return this->_metronome;} } + property System::Byte notes { System::Byte get() {return this->_notes;} } + }; + + public ref class MetaKeySignature sealed + : public MetaData + { + private: + System::SByte _key; + System::Boolean _minor; + public: + MetaKeySignature( + System::SByte key, + System::Boolean minor + ): MetaData(META_TYPE::TIME_SIGNATURE, true), _key(key), _minor(minor) {} + + property System::SByte key { System::SByte get() {return this->_key;} } + property System::Boolean minor { System::Boolean get() {return this->_minor;} } + }; + + public ref class MetaDefault sealed + : public MetaData + { + private: + System::Byte _defaultType; + array^ _data; + public: + MetaDefault( + System::Byte defaultType, + array^ data + ): MetaData(META_TYPE::SEQ_SP_METAEVENT, false), _defaultType(defaultType), _data(data) {} + + property System::Byte defaultType { System::Byte get() {return this->_defaultType;} } + property array^ data { array^ get() {return this->_data;} } + }; + + /// + /// + /// + /// + public ref class SmfStream + : public Core::IStream + { + public: + ref class SmfTrack: + public Core::ITrack + { + public: + ref class SmfPacket: + public Core::IStreamPacket + { + private: + initonly SmfTrack^ _track; + initonly System::UInt64 _offset; + initonly System::UInt64 _nextOffset; + initonly System::UInt64 _tick; + initonly System::Byte _status; + initonly Core::IData^ _data; + initonly System::Boolean _isTerminate; + + private: + System::UInt32 GetDeltaTime(System::UInt64% tempOffset); + System::Byte NextByte(System::UInt64% tempOffset); + void NextByte(array^ dest, System::UInt64% tempOffset, System::Byte start, System::Byte size); + + public: + SmfPacket( + SmfTrack^ track, + System::UInt64 offset, + System::UInt64 previousTick, + System::Byte previousStatus + ); + ~SmfPacket(); + + protected: + !SmfPacket(); + + public: + property Core::IStreamPacket^ next { virtual Core::IStreamPacket^ get(); } + property System::Boolean hasNext { virtual System::Boolean get() {return !this->_isTerminate;} } + property Core::IData^ data { virtual Core::IData^ get() {return this->_data;} } + property System::UInt64 tick { virtual System::UInt64 get() {return this->_tick;} } + }; + + private: + SmfStream^ _stream; + + System::UInt64 _headOffset; + System::UInt64 _tailOffset; + + Core::IStreamPacket^ _headPacket; + + //再生中の状態 + Core::IStreamPacket^ _packet; + System::Double _nowTick; + + System::Collections::Generic::Dictionary^ _metaData; + + public: + SmfTrack( + SmfStream^ stream, + System::UInt64 headOffset, + System::UInt64 tailOffset + ); + virtual ~SmfTrack(); + protected: + !SmfTrack(); + + public: + property Core::IStreamPacket^ head { virtual Core::IStreamPacket^ get(){ return this->_headPacket; } } + + virtual void Rewind(); + virtual array^ GetStreamPacket(System::Double deltaTime); + }; + + enum class TYPE: System::UInt32 + { + HEADER = 0x4D546864L, // MThd: length format ntrks division + HEADER_R = 0x6468544DL, // 読み込み用 + TRACK = 0x4D54726BL, // MTrk: length + TRACK_R = 0x6B72544DL, // MTrk: length + }; + + enum class FORMAT: System::UInt16 + { + SINGLE = 0, // single-track + MULTIPLE_SYNC = 1, // multiple tracks, synchronous + MULTIPLE_ASYNC = 2, // multiple tracks, asynchronous + }; + + //SMFHeader Chunk + WIN32_DLL_STRUCTLAYOUT value struct SMFHEADER_CHUNK + { + System::UInt32 dwType; + System::UInt32 dwLength; + System::UInt16 wFormat; + System::UInt16 wNtrks; + System::UInt16 wDivition; + }; + + //SMFTrack chunk + WIN32_DLL_STRUCTLAYOUT value struct SMFTRACK_CHUNK + { + System::UInt32 dwType; + System::UInt32 dwLength; + }; + + private: + System::IO::MemoryMappedFiles::MemoryMappedFile^ _mmap; + System::IO::MemoryMappedFiles::MemoryMappedViewAccessor^ _view; + + SMFHEADER_CHUNK _smfHeader; + array^ _tracks; + + public: + SmfStream(System::String^ path); + virtual ~SmfStream(); + + protected: + !SmfStream(); + + private: + void Open(System::String^ path); + void CheckSMF(); + + private: + System::Double _speed; + + public: + virtual array^ GetStreamPacket(System::Double deltaTime); + virtual void Rewind(); + }; + + public ref class SmfException + : System::Exception + { + public: + SmfException(System::String^ v): System::Exception(v){}; + }; + +} +} +} +} diff --git a/Core/Momiji.Sequencer.Wave.cpp b/Core/Momiji.Sequencer.Wave.cpp new file mode 100644 index 0000000..d41d8d8 --- /dev/null +++ b/Core/Momiji.Sequencer.Wave.cpp @@ -0,0 +1,207 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Sequencer.Midi.Smf.cpp + stream component of standard midi file. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#include "StdAfx.h" + +#include "Momiji.Interop.Winmm.h" +#include "Momiji.Sequencer.Wave.h" + +namespace Momiji{ +namespace Sequencer { +namespace Wave { + + WaveStream::WaveStream(System::String^ path) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->Open(path); + this->CheckWave(); + } + + WaveStream::~WaveStream() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + this->!WaveStream(); + } + + WaveStream::!WaveStream() + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}]",__FUNCTION__); + #endif + + if (this->_view != nullptr) + { + delete this->_view; + this->_view = nullptr; + } + if (this->_mmap != nullptr) + { + delete this->_mmap; + this->_mmap = nullptr; + } + } + + void WaveStream::Open(System::String^ path) + { + #ifdef _DEBUG + System::Console::WriteLine("[{0}] {1}",__FUNCTION__, path); + #endif + + auto info = gcnew System::IO::FileInfo(path); + + this->_mmap = + System::IO::MemoryMappedFiles::MemoryMappedFile::CreateFromFile( + info->FullName, + System::IO::FileMode::Open, + "momiji.wav", + info->Length, + System::IO::MemoryMappedFiles::MemoryMappedFileAccess::Read + ); + + this->_view = + this->_mmap->CreateViewAccessor( + 0, + 0, + System::IO::MemoryMappedFiles::MemoryMappedFileAccess::Read + ); + } + + + void WaveStream::CheckWave() + { + System::Int64 offset = 0; + RIFFHEADER_CHUNK riffHeader; + + this->_view->Read(offset, riffHeader); + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [dwType {1,8:X}",__FUNCTION__, riffHeader.dwType); + System::Console::WriteLine("[{0}] [dwLength {1}]",__FUNCTION__, riffHeader.dwLength); + System::Console::WriteLine("[{0}] [dwFormat {1,8:X}",__FUNCTION__, riffHeader.dwFormat); + #endif + + if (!System::Enum::IsDefined(TYPE::typeid, riffHeader.dwType)) {throw gcnew WaveException("RIFFではない");} + if (!System::Enum::IsDefined(FORMAT::typeid, riffHeader.dwFormat)) {throw gcnew WaveException("WAVEではない");} + + offset += 12; + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [offset {1}]",__FUNCTION__, offset); + #endif + + while(offset < riffHeader.dwLength) + { + RIFFSUB_CHUNK subTrack; + this->_view->Read(offset, subTrack); + offset += 8; + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [dwType {1,8:X}]",__FUNCTION__, subTrack.dwType); + System::Console::WriteLine("[{0}] [dwLength {1}]",__FUNCTION__, subTrack.dwLength); + #endif + + //対応していないサブチャンクがあっても、気にしないことにする + //if (!System::Enum::IsDefined(SUB::typeid, subTrack.dwType)) {throw gcnew WaveException("不明なチャンク");} + + switch (subTrack.dwType) { + case SUB::fmt__R: + { + static const auto pcmSize = safe_cast(InteropServices::Marshal::SizeOf(Momiji::Interop::Winmm::PcmWaveFormat::typeid)); + + if (subTrack.dwLength == pcmSize) + { + Momiji::Interop::Winmm::PcmWaveFormat pcm; + this->_view->Read(offset, pcm); + + this->_wfx.formatType = pcm.wf.formatType; + this->_wfx.channels = pcm.wf.channels; + this->_wfx.samplesPerSecond = pcm.wf.samplesPerSecond; + this->_wfx.averageBytesPerSecond = pcm.wf.averageBytesPerSecond; + this->_wfx.blockAlign = pcm.wf.blockAlign; + this->_wfx.bitsPerSample = pcm.bitsPerSample; + } + else if (subTrack.dwLength > pcmSize) + { + this->_view->Read(offset, this->_wfx); + } + + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [wfx {1}]",__FUNCTION__, this->_wfx.ToString()); + #endif + + break; + } + + case SUB::data_R: + { + this->_dataStartPosition = offset; + this->_dataSize = subTrack.dwLength; + this->_dataSeekPosition = offset; + break; + } + } + + offset += subTrack.dwLength; + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [offset {1}]",__FUNCTION__, offset); + #endif + } + } + + //System::UInt32 WaveStream::Read(array^ buffer, System::UInt32 samplesPerBuffer) + System::UInt32 WaveStream::Read(Momiji::Core::Buffer::BufferPool^>::Buffer^ buffer, System::UInt32 samplesPerBuffer) + { + auto size = (samplesPerBuffer * this->_wfx.channels * this->_wfx.bitsPerSample / 8); + auto b = buffer->GetBuffer(); + if (b->Length < size) { + size = b->Length; + #ifdef _DEBUG + System::Console::WriteLine("[{0}] 指定したサンプル分を格納するだけのバッファが足りないので、バッファまでの読み込みにします[samplesPerBuffer {1}][buffer length {1}]",__FUNCTION__, samplesPerBuffer, b->Length); + #endif + } + + auto leftSize = this->_dataSize - safe_cast(this->_dataSeekPosition - this->_dataStartPosition); + if (leftSize < size) { + size = leftSize; + } + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [size {1}]",__FUNCTION__, size); + #endif + + //auto result = gcnew array(size); + auto readBytes = this->_view->ReadArray(this->_dataSeekPosition, b, 0, size); + #ifdef _DEBUG + System::Console::WriteLine("[{0}] [readBytes {1}]",__FUNCTION__, readBytes); + #endif + + this->_dataSeekPosition += readBytes; + + return readBytes; + } + +} +} +} diff --git a/Core/Momiji.Sequencer.Wave.h b/Core/Momiji.Sequencer.Wave.h new file mode 100644 index 0000000..0bc92d9 --- /dev/null +++ b/Core/Momiji.Sequencer.Wave.h @@ -0,0 +1,123 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Sequencer.Midi.Smf.cpp + stream component of standard midi file. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +#include "Momiji.Interop.Winmm.h" + +#include "Momiji.Core.Interface.h" +#include "Momiji.Core.Buffer.h" + +using namespace System::Runtime; + +namespace Momiji{ +namespace Sequencer { +namespace Wave { + + public ref class WaveStream + : public Core::IStream + { + public: + enum class TYPE: System::UInt32 + { + HEADER = 0x52494646L, // RIFF + HEADER_R = 0x46464952L, // 読み込み用 + }; + + enum class FORMAT: System::UInt32 + { + WAVE = 0x57415645L, // WAVE + WAVE_R = 0x45564157L, // 読み込み用 + }; + + enum class SUB: System::UInt32 + { + fmt_ = 0x666D7420L, // fmt + fmt__R = 0x20746D66L, // 読み込み用 + + data = 0x64617461L, // data + data_R = 0x61746164L, // 読み込み用 + + LIST = 0x4C495354L, // LIST + LIST_R = 0x5453494CL, // 読み込み用 + + }; + + //RIFF Header Chunk + WIN32_DLL_STRUCTLAYOUT value struct RIFFHEADER_CHUNK + { + System::UInt32 dwType; + System::UInt32 dwLength; + System::UInt32 dwFormat; + }; + + //RIFF Sub Chunk + WIN32_DLL_STRUCTLAYOUT value struct RIFFSUB_CHUNK + { + System::UInt32 dwType; + System::UInt32 dwLength; + }; + + private: + System::IO::MemoryMappedFiles::MemoryMappedFile^ _mmap; + System::IO::MemoryMappedFiles::MemoryMappedViewAccessor^ _view; + + Momiji::Interop::Winmm::WaveFormatEx _wfx; + + System::Int64 _dataStartPosition; + System::UInt32 _dataSize; + System::Int64 _dataSeekPosition; + + public: + WaveStream(System::String^ path); + virtual ~WaveStream(); + + protected: + !WaveStream(); + + private: + void Open(System::String^ path); + void CheckWave(); + + public: + virtual array^ GetStreamPacket(System::Double deltaTime) {return nullptr;}; + virtual void Rewind() {}; + + //System::UInt32 WaveStream::Read(array^ buffer, System::UInt32 samplesPerBuffer); + System::UInt32 WaveStream::Read(Momiji::Core::Buffer::BufferPool^>::Buffer^ buffer, System::UInt32 samplesPerBuffer); + + property Momiji::Interop::Winmm::WaveFormatEx format { Momiji::Interop::Winmm::WaveFormatEx get() {return this->_wfx;} } + + }; + + public ref class WaveException + : System::Exception + { + public: + WaveException(System::String^ v): System::Exception(v){}; + }; + +} +} +} diff --git a/Core/Momiji.Util.h b/Core/Momiji.Util.h new file mode 100644 index 0000000..604295f --- /dev/null +++ b/Core/Momiji.Util.h @@ -0,0 +1,79 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Momiji.Sequencer.Midi.Smf.h + stream component of standard midi file. +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +#pragma once + +#using + +using namespace System::Runtime; + +namespace Momiji{ + /** + + ユーティリティクラス(未整理ロジック) + + */ + value class Util + { + public: + /** + + ntohs + + ビッグエンディアンの2バイトデータ + システムがリトルエンディアンであれば、変換して返す。 + */ + static System::UInt16 ToHostOrder(System::UInt16 data) + { + if (System::BitConverter::IsLittleEndian) + { + return safe_cast( + ((data >> 8) & 0x00FF) | + ((data << 8) & 0xFF00) + ); + } + return data; + }; + + /** + + ntohl + + ビッグエンディアンの4バイトデータ + システムがリトルエンディアンであれば、変換して返す。 + */ + static System::UInt32 ToHostOrder(System::UInt32 data) + { + if (System::BitConverter::IsLittleEndian) + { + return ( + ((data >> 24) & 0x000000FFL) | + ((data >> 8 ) & 0x0000FF00L) | + ((data << 8 ) & 0x00FF0000L) | + ((data << 24) & 0xFF000000L) + ); + } + return data; + }; + }; + +} diff --git a/Core/Stdafx.cpp b/Core/Stdafx.cpp new file mode 100644 index 0000000..ad44cfe --- /dev/null +++ b/Core/Stdafx.cpp @@ -0,0 +1,38 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Stdafx.cpp + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +// stdafx.cpp : 標準インクルード XXMIDICLR.pch のみを +// 含むソース ファイルは、プリコンパイル済みヘッダーになります。 +// stdafx.obj にはプリコンパイル済み型情報が含まれます。 + +#include "stdafx.h" + +//#include "Momiji.Interop.DirectShow.h" +#include "Momiji.Interop.Guiddef.h" +#include "Momiji.Interop.Kernel32.h" +#include "Momiji.Interop.Ks.h" +#include "Momiji.Interop.MMDeviceAPI.h" +//#include "Momiji.Interop.PropIdl.h" +#include "Momiji.Interop.Setupapi.h" +#include "Momiji.Interop.Vst.h" +#include "Momiji.Interop.Winmm.h" +//#include "Momiji.Interop.XAudio2.h" diff --git a/Core/Stdafx.h b/Core/Stdafx.h new file mode 100644 index 0000000..d7e96ae --- /dev/null +++ b/Core/Stdafx.h @@ -0,0 +1,40 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +Stdafx.h + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または +// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル +// を記述します。 + +#pragma once + +#define WIN32_DLL_IMPORT_(_lib_, _charset_) [InteropServices::DllImport(_lib_, CallingConvention = InteropServices::CallingConvention::StdCall, CharSet = InteropServices::CharSet::##_charset_##, SetLastError = true)] +#define WIN32_DLL_IMPORT(_lib_) WIN32_DLL_IMPORT_(_lib_, Unicode) +#define WIN32_DLL_IMPORT_ANSI(_lib_) WIN32_DLL_IMPORT_(_lib_, Ansi) + +#define WIN32_DLL_STRUCTLAYOUT_(_charset_) [InteropServices::StructLayout(InteropServices::LayoutKind::Sequential, Pack=1, CharSet=InteropServices::CharSet::##_charset_##)] +#define WIN32_DLL_STRUCTLAYOUT WIN32_DLL_STRUCTLAYOUT_(Unicode) +#define WIN32_DLL_STRUCTLAYOUT_ANSI WIN32_DLL_STRUCTLAYOUT_(Ansi) + +//#define WIN32_DLL_STRUCTLAYOUT_UNION_(_size_, _charset_) [InteropServices::StructLayout(InteropServices::LayoutKind::Explicit, Size=##_size_##, CharSet=InteropServices::CharSet::##_charset_##)] +//#define WIN32_DLL_STRUCTLAYOUT_UNION_ANSI(_size_) WIN32_DLL_STRUCTLAYOUT_UNION_(_size_, Ansi) +#define WIN32_DLL_STRUCTLAYOUT_UNION_(_charset_) [InteropServices::StructLayout(InteropServices::LayoutKind::Explicit, Pack=1, CharSet=InteropServices::CharSet::##_charset_##)] +#define WIN32_DLL_STRUCTLAYOUT_UNION_ANSI WIN32_DLL_STRUCTLAYOUT_UNION_(Ansi) diff --git a/Core/app.ico b/Core/app.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/Core/app.ico differ diff --git a/Core/app.rc b/Core/app.rc new file mode 100644 index 0000000..a9a0d32 Binary files /dev/null and b/Core/app.rc differ diff --git a/Core/resource.h b/Core/resource.h new file mode 100644 index 0000000..c446f83 --- /dev/null +++ b/Core/resource.h @@ -0,0 +1,25 @@ +/* +[momiji music component library] +--------------------------------------------------------------------- +resource.h + +--------------------------------------------------------------------- +Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--------------------------------------------------------------------- +*/ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by app.rc diff --git a/Momiji.sln b/Momiji.sln new file mode 100644 index 0000000..d6347d7 --- /dev/null +++ b/Momiji.sln @@ -0,0 +1,212 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Momiji.Core", "Core\Momiji.Core.vcxproj", "{5895C214-5905-4C4F-9115-4BE323657AFC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XXMIDI2", "..\XXMIDI\XXMIDI2.vcxproj", "{881F36E3-3D20-4D9D-BEC6-B1C188480D69}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Momiji.Test", "Test\Momiji.Test\Momiji.Test.vcxproj", "{83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}" + ProjectSection(ProjectDependencies) = postProject + {5895C214-5905-4C4F-9115-4BE323657AFC} = {5895C214-5905-4C4F-9115-4BE323657AFC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Momiji.Test.MM.MidiOut", "Test\Momiji.Test.MM.MidiOut\Momiji.Test.MM.MidiOut.vcxproj", "{01789B4E-A549-4C5E-8AE3-4383E52F6E14}" + ProjectSection(ProjectDependencies) = postProject + {5895C214-5905-4C4F-9115-4BE323657AFC} = {5895C214-5905-4C4F-9115-4BE323657AFC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Momiji.Test.MM.MidiIn", "Test\Momiji.Test.MM.MidiIn\Momiji.Test.MM.MidiIn.vcxproj", "{BF11621E-392D-4814-B1BD-3AEF56CD826F}" + ProjectSection(ProjectDependencies) = postProject + {5895C214-5905-4C4F-9115-4BE323657AFC} = {5895C214-5905-4C4F-9115-4BE323657AFC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Momiji.Test.MM.Timer", "Test\Momiji.Test.MM.Timer\Momiji.Test.MM.Timer.vcxproj", "{42B61159-67AC-416D-BDAA-A5550CA88F90}" + ProjectSection(ProjectDependencies) = postProject + {5895C214-5905-4C4F-9115-4BE323657AFC} = {5895C214-5905-4C4F-9115-4BE323657AFC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Momiji.Test.Sequencer.Midi", "Test\Momiji.Test.Sequencer.Midi\Momiji.Test.Sequencer.Midi.vcxproj", "{835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}" + ProjectSection(ProjectDependencies) = postProject + {5895C214-5905-4C4F-9115-4BE323657AFC} = {5895C214-5905-4C4F-9115-4BE323657AFC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Momiji.Test.MM.WaveOut", "Test\Momiji.Test.MM.WaveOut\Momiji.Test.MM.WaveOut.vcxproj", "{5490CCD6-04CF-42F4-84A6-3145BC6234EF}" + ProjectSection(ProjectDependencies) = postProject + {5895C214-5905-4C4F-9115-4BE323657AFC} = {5895C214-5905-4C4F-9115-4BE323657AFC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Momiji.Test.DeviceInfo", "Test\Momiji.Test.DeviceInfo\Momiji.Test.DeviceInfo.vcxproj", "{2E1AFEF8-448A-4231-8868-34231CE4981B}" + ProjectSection(ProjectDependencies) = postProject + {5895C214-5905-4C4F-9115-4BE323657AFC} = {5895C214-5905-4C4F-9115-4BE323657AFC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Momiji.Test.Vst.Controller", "Test\Momiji.Test.Vst.Controller\Momiji.Test.Vst.Controller.vcxproj", "{0492D8F3-11E5-475A-9E85-813F4A42F314}" + ProjectSection(ProjectDependencies) = postProject + {5895C214-5905-4C4F-9115-4BE323657AFC} = {5895C214-5905-4C4F-9115-4BE323657AFC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectKs", "..\oss\DirectKs\DirectKs.vcxproj", "{E8C18712-6827-4DC9-AA2D-BA98E5925715}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "b", "..\oss\vsthostsrc\b\b.vcxproj", "{38A796EB-BECD-44D0-8864-3B4017EC8AB9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Momiji.Test.Sequencer.Wave", "Test\Momiji.Test.Sequencer.Wave\Momiji.Test.Sequencer.Wave.vcxproj", "{2657B6E0-7B03-487A-A149-9EDB09E0848F}" + ProjectSection(ProjectDependencies) = postProject + {5895C214-5905-4C4F-9115-4BE323657AFC} = {5895C214-5905-4C4F-9115-4BE323657AFC} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Momiji.Core.Test", "Test\Momiji.Core.Test\Momiji.Core.Test.csproj", "{6DBB1013-E8F8-431B-B50C-751C35EB9684}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5895C214-5905-4C4F-9115-4BE323657AFC}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {5895C214-5905-4C4F-9115-4BE323657AFC}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {5895C214-5905-4C4F-9115-4BE323657AFC}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {5895C214-5905-4C4F-9115-4BE323657AFC}.Debug|Win32.ActiveCfg = Debug|Win32 + {5895C214-5905-4C4F-9115-4BE323657AFC}.Debug|Win32.Build.0 = Debug|Win32 + {5895C214-5905-4C4F-9115-4BE323657AFC}.Release|Any CPU.ActiveCfg = Release|Win32 + {5895C214-5905-4C4F-9115-4BE323657AFC}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {5895C214-5905-4C4F-9115-4BE323657AFC}.Release|Mixed Platforms.Build.0 = Release|Win32 + {5895C214-5905-4C4F-9115-4BE323657AFC}.Release|Win32.ActiveCfg = Release|Win32 + {5895C214-5905-4C4F-9115-4BE323657AFC}.Release|Win32.Build.0 = Release|Win32 + {881F36E3-3D20-4D9D-BEC6-B1C188480D69}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {881F36E3-3D20-4D9D-BEC6-B1C188480D69}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {881F36E3-3D20-4D9D-BEC6-B1C188480D69}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {881F36E3-3D20-4D9D-BEC6-B1C188480D69}.Debug|Win32.ActiveCfg = Debug|Win32 + {881F36E3-3D20-4D9D-BEC6-B1C188480D69}.Release|Any CPU.ActiveCfg = Release|Win32 + {881F36E3-3D20-4D9D-BEC6-B1C188480D69}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {881F36E3-3D20-4D9D-BEC6-B1C188480D69}.Release|Mixed Platforms.Build.0 = Release|Win32 + {881F36E3-3D20-4D9D-BEC6-B1C188480D69}.Release|Win32.ActiveCfg = Release|Win32 + {881F36E3-3D20-4D9D-BEC6-B1C188480D69}.Release|Win32.Build.0 = Release|Win32 + {83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}.Debug|Win32.ActiveCfg = Debug|Win32 + {83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}.Debug|Win32.Build.0 = Debug|Win32 + {83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}.Release|Any CPU.ActiveCfg = Release|Win32 + {83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}.Release|Mixed Platforms.Build.0 = Release|Win32 + {83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}.Release|Win32.ActiveCfg = Release|Win32 + {83A5751A-F4E6-4F11-BEE1-7F9D26AB4B69}.Release|Win32.Build.0 = Release|Win32 + {01789B4E-A549-4C5E-8AE3-4383E52F6E14}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {01789B4E-A549-4C5E-8AE3-4383E52F6E14}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {01789B4E-A549-4C5E-8AE3-4383E52F6E14}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {01789B4E-A549-4C5E-8AE3-4383E52F6E14}.Debug|Win32.ActiveCfg = Debug|Win32 + {01789B4E-A549-4C5E-8AE3-4383E52F6E14}.Debug|Win32.Build.0 = Debug|Win32 + {01789B4E-A549-4C5E-8AE3-4383E52F6E14}.Release|Any CPU.ActiveCfg = Release|Win32 + {01789B4E-A549-4C5E-8AE3-4383E52F6E14}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {01789B4E-A549-4C5E-8AE3-4383E52F6E14}.Release|Mixed Platforms.Build.0 = Release|Win32 + {01789B4E-A549-4C5E-8AE3-4383E52F6E14}.Release|Win32.ActiveCfg = Release|Win32 + {01789B4E-A549-4C5E-8AE3-4383E52F6E14}.Release|Win32.Build.0 = Release|Win32 + {BF11621E-392D-4814-B1BD-3AEF56CD826F}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {BF11621E-392D-4814-B1BD-3AEF56CD826F}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {BF11621E-392D-4814-B1BD-3AEF56CD826F}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {BF11621E-392D-4814-B1BD-3AEF56CD826F}.Debug|Win32.ActiveCfg = Debug|Win32 + {BF11621E-392D-4814-B1BD-3AEF56CD826F}.Debug|Win32.Build.0 = Debug|Win32 + {BF11621E-392D-4814-B1BD-3AEF56CD826F}.Release|Any CPU.ActiveCfg = Release|Win32 + {BF11621E-392D-4814-B1BD-3AEF56CD826F}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {BF11621E-392D-4814-B1BD-3AEF56CD826F}.Release|Mixed Platforms.Build.0 = Release|Win32 + {BF11621E-392D-4814-B1BD-3AEF56CD826F}.Release|Win32.ActiveCfg = Release|Win32 + {BF11621E-392D-4814-B1BD-3AEF56CD826F}.Release|Win32.Build.0 = Release|Win32 + {42B61159-67AC-416D-BDAA-A5550CA88F90}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {42B61159-67AC-416D-BDAA-A5550CA88F90}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {42B61159-67AC-416D-BDAA-A5550CA88F90}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {42B61159-67AC-416D-BDAA-A5550CA88F90}.Debug|Win32.ActiveCfg = Debug|Win32 + {42B61159-67AC-416D-BDAA-A5550CA88F90}.Debug|Win32.Build.0 = Debug|Win32 + {42B61159-67AC-416D-BDAA-A5550CA88F90}.Release|Any CPU.ActiveCfg = Release|Win32 + {42B61159-67AC-416D-BDAA-A5550CA88F90}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {42B61159-67AC-416D-BDAA-A5550CA88F90}.Release|Mixed Platforms.Build.0 = Release|Win32 + {42B61159-67AC-416D-BDAA-A5550CA88F90}.Release|Win32.ActiveCfg = Release|Win32 + {42B61159-67AC-416D-BDAA-A5550CA88F90}.Release|Win32.Build.0 = Release|Win32 + {835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}.Debug|Win32.Build.0 = Debug|Win32 + {835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}.Release|Any CPU.ActiveCfg = Release|Win32 + {835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}.Release|Mixed Platforms.Build.0 = Release|Win32 + {835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}.Release|Win32.ActiveCfg = Release|Win32 + {835B442D-FC4F-40D3-82D5-E4B2D53A3F8D}.Release|Win32.Build.0 = Release|Win32 + {5490CCD6-04CF-42F4-84A6-3145BC6234EF}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {5490CCD6-04CF-42F4-84A6-3145BC6234EF}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {5490CCD6-04CF-42F4-84A6-3145BC6234EF}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {5490CCD6-04CF-42F4-84A6-3145BC6234EF}.Debug|Win32.ActiveCfg = Debug|Win32 + {5490CCD6-04CF-42F4-84A6-3145BC6234EF}.Debug|Win32.Build.0 = Debug|Win32 + {5490CCD6-04CF-42F4-84A6-3145BC6234EF}.Release|Any CPU.ActiveCfg = Release|Win32 + {5490CCD6-04CF-42F4-84A6-3145BC6234EF}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {5490CCD6-04CF-42F4-84A6-3145BC6234EF}.Release|Mixed Platforms.Build.0 = Release|Win32 + {5490CCD6-04CF-42F4-84A6-3145BC6234EF}.Release|Win32.ActiveCfg = Release|Win32 + {5490CCD6-04CF-42F4-84A6-3145BC6234EF}.Release|Win32.Build.0 = Release|Win32 + {2E1AFEF8-448A-4231-8868-34231CE4981B}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {2E1AFEF8-448A-4231-8868-34231CE4981B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {2E1AFEF8-448A-4231-8868-34231CE4981B}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {2E1AFEF8-448A-4231-8868-34231CE4981B}.Debug|Win32.ActiveCfg = Debug|Win32 + {2E1AFEF8-448A-4231-8868-34231CE4981B}.Debug|Win32.Build.0 = Debug|Win32 + {2E1AFEF8-448A-4231-8868-34231CE4981B}.Release|Any CPU.ActiveCfg = Release|Win32 + {2E1AFEF8-448A-4231-8868-34231CE4981B}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {2E1AFEF8-448A-4231-8868-34231CE4981B}.Release|Mixed Platforms.Build.0 = Release|Win32 + {2E1AFEF8-448A-4231-8868-34231CE4981B}.Release|Win32.ActiveCfg = Release|Win32 + {2E1AFEF8-448A-4231-8868-34231CE4981B}.Release|Win32.Build.0 = Release|Win32 + {0492D8F3-11E5-475A-9E85-813F4A42F314}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {0492D8F3-11E5-475A-9E85-813F4A42F314}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {0492D8F3-11E5-475A-9E85-813F4A42F314}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {0492D8F3-11E5-475A-9E85-813F4A42F314}.Debug|Win32.ActiveCfg = Debug|Win32 + {0492D8F3-11E5-475A-9E85-813F4A42F314}.Debug|Win32.Build.0 = Debug|Win32 + {0492D8F3-11E5-475A-9E85-813F4A42F314}.Release|Any CPU.ActiveCfg = Release|Win32 + {0492D8F3-11E5-475A-9E85-813F4A42F314}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {0492D8F3-11E5-475A-9E85-813F4A42F314}.Release|Mixed Platforms.Build.0 = Release|Win32 + {0492D8F3-11E5-475A-9E85-813F4A42F314}.Release|Win32.ActiveCfg = Release|Win32 + {0492D8F3-11E5-475A-9E85-813F4A42F314}.Release|Win32.Build.0 = Release|Win32 + {E8C18712-6827-4DC9-AA2D-BA98E5925715}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {E8C18712-6827-4DC9-AA2D-BA98E5925715}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {E8C18712-6827-4DC9-AA2D-BA98E5925715}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {E8C18712-6827-4DC9-AA2D-BA98E5925715}.Debug|Win32.ActiveCfg = Debug|Win32 + {E8C18712-6827-4DC9-AA2D-BA98E5925715}.Debug|Win32.Build.0 = Debug|Win32 + {E8C18712-6827-4DC9-AA2D-BA98E5925715}.Release|Any CPU.ActiveCfg = Release|Win32 + {E8C18712-6827-4DC9-AA2D-BA98E5925715}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {E8C18712-6827-4DC9-AA2D-BA98E5925715}.Release|Mixed Platforms.Build.0 = Release|Win32 + {E8C18712-6827-4DC9-AA2D-BA98E5925715}.Release|Win32.ActiveCfg = Release|Win32 + {E8C18712-6827-4DC9-AA2D-BA98E5925715}.Release|Win32.Build.0 = Release|Win32 + {38A796EB-BECD-44D0-8864-3B4017EC8AB9}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {38A796EB-BECD-44D0-8864-3B4017EC8AB9}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {38A796EB-BECD-44D0-8864-3B4017EC8AB9}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {38A796EB-BECD-44D0-8864-3B4017EC8AB9}.Debug|Win32.ActiveCfg = Debug|Win32 + {38A796EB-BECD-44D0-8864-3B4017EC8AB9}.Debug|Win32.Build.0 = Debug|Win32 + {38A796EB-BECD-44D0-8864-3B4017EC8AB9}.Release|Any CPU.ActiveCfg = Release|Win32 + {38A796EB-BECD-44D0-8864-3B4017EC8AB9}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {38A796EB-BECD-44D0-8864-3B4017EC8AB9}.Release|Mixed Platforms.Build.0 = Release|Win32 + {38A796EB-BECD-44D0-8864-3B4017EC8AB9}.Release|Win32.ActiveCfg = Release|Win32 + {38A796EB-BECD-44D0-8864-3B4017EC8AB9}.Release|Win32.Build.0 = Release|Win32 + {2657B6E0-7B03-487A-A149-9EDB09E0848F}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {2657B6E0-7B03-487A-A149-9EDB09E0848F}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {2657B6E0-7B03-487A-A149-9EDB09E0848F}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {2657B6E0-7B03-487A-A149-9EDB09E0848F}.Debug|Win32.ActiveCfg = Debug|Win32 + {2657B6E0-7B03-487A-A149-9EDB09E0848F}.Debug|Win32.Build.0 = Debug|Win32 + {2657B6E0-7B03-487A-A149-9EDB09E0848F}.Release|Any CPU.ActiveCfg = Release|Win32 + {2657B6E0-7B03-487A-A149-9EDB09E0848F}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {2657B6E0-7B03-487A-A149-9EDB09E0848F}.Release|Mixed Platforms.Build.0 = Release|Win32 + {2657B6E0-7B03-487A-A149-9EDB09E0848F}.Release|Win32.ActiveCfg = Release|Win32 + {2657B6E0-7B03-487A-A149-9EDB09E0848F}.Release|Win32.Build.0 = Release|Win32 + {6DBB1013-E8F8-431B-B50C-751C35EB9684}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6DBB1013-E8F8-431B-B50C-751C35EB9684}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DBB1013-E8F8-431B-B50C-751C35EB9684}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {6DBB1013-E8F8-431B-B50C-751C35EB9684}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {6DBB1013-E8F8-431B-B50C-751C35EB9684}.Debug|Win32.ActiveCfg = Debug|Any CPU + {6DBB1013-E8F8-431B-B50C-751C35EB9684}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6DBB1013-E8F8-431B-B50C-751C35EB9684}.Release|Any CPU.Build.0 = Release|Any CPU + {6DBB1013-E8F8-431B-B50C-751C35EB9684}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {6DBB1013-E8F8-431B-B50C-751C35EB9684}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {6DBB1013-E8F8-431B-B50C-751C35EB9684}.Release|Win32.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Test/Momiji.Core.Test/App.config b/Test/Momiji.Core.Test/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/Test/Momiji.Core.Test/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Test/Momiji.Core.Test/App.xaml b/Test/Momiji.Core.Test/App.xaml new file mode 100644 index 0000000..67b7f6e --- /dev/null +++ b/Test/Momiji.Core.Test/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Test/Momiji.Core.Test/App.xaml.cs b/Test/Momiji.Core.Test/App.xaml.cs new file mode 100644 index 0000000..1724478 --- /dev/null +++ b/Test/Momiji.Core.Test/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace Momiji.Core.Test +{ + /// + /// App.xaml の相互作用ロジック + /// + public partial class App : Application + { + } +} diff --git a/Test/Momiji.Core.Test/Data.cs b/Test/Momiji.Core.Test/Data.cs new file mode 100644 index 0000000..dcd0864 --- /dev/null +++ b/Test/Momiji.Core.Test/Data.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + + +namespace Momiji.Core.Test +{ + class Data + { + private System.Collections.Generic.List _waveOutCapabilities; + + public System.Collections.Generic.List waveOutCapabilitiesList { get {return this._waveOutCapabilities; } } + public Momiji.Interop.Winmm.WaveOutCapabilities waveOutCapabilitiesSelect { get; set; } + + public Data() + { + System.Console.WriteLine("Data construct"); + + this._waveOutCapabilities = + new System.Collections.Generic.List(); + + System.UInt32 nums = Momiji.Core.Wave.Out.Device.GetNumDevices(); + + for (System.UInt32 idx = 0; idx < nums; idx++) + { + var cap = Momiji.Core.Wave.Out.Device.GetCapabilities(idx); + this._waveOutCapabilities.Add(cap); + } + + this.waveOutCapabilitiesSelect = this._waveOutCapabilities[0]; + } + + } + + [System.Windows.Data.ValueConversion(typeof(System.Object), typeof(System.Collections.Generic.List))] + class FieldListConverter : System.Windows.Data.IValueConverter + { + public System.Object Convert(System.Object value, System.Type targetType, System.Object parameter, System.Globalization.CultureInfo culture) + { + System.Console.WriteLine("FieldListConverter Convert"); + var result = new System.Collections.Generic.List(); + var fields = value.GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); + foreach (var f in fields) + { + var item = new System.ComponentModel.ItemPropertyInfo(f.Name, f.FieldType, f.GetValue(value)); + result.Add(item); + } + + return result; + } + + public System.Object ConvertBack(System.Object value, System.Type targetType, System.Object parameter, System.Globalization.CultureInfo culture) + { + return System.Windows.DependencyProperty.UnsetValue; + } + } + + [System.Windows.Data.ValueConversion(typeof(System.Object), typeof(System.Object))] + class FieldConverter : System.Windows.Data.IValueConverter + { + public System.Object Convert(System.Object value, System.Type targetType, System.Object parameter, System.Globalization.CultureInfo culture) + { + System.Console.WriteLine("FieldConverter Convert"); + var f = value.GetType().GetField(parameter as System.String, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); + return f.GetValue(value); + } + + public System.Object ConvertBack(System.Object value, System.Type targetType, System.Object parameter, System.Globalization.CultureInfo culture) + { + return System.Windows.DependencyProperty.UnsetValue; + } + } +} diff --git a/Test/Momiji.Core.Test/MainWindow.xaml b/Test/Momiji.Core.Test/MainWindow.xaml new file mode 100644 index 0000000..f5f574b --- /dev/null +++ b/Test/Momiji.Core.Test/MainWindow.xaml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +