2 [momiji music component library]
3 ---------------------------------------------------------------------
4 Momiji.Core.Midi.In.cpp
6 ---------------------------------------------------------------------
7 Copyright (C) 2011 tyiki badwell {miria@users.sourceforge.jp}.
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.html>.
21 ---------------------------------------------------------------------
25 #include "Momiji.Interop.Winmm.h"
26 #include "Momiji.Core.Midi.In.h"
27 #include "Momiji.Core.Midi.Data.h"
34 void Device::OnEventHandler(
35 System::Object^ sender,
36 Interop::Winmm::DriverCallBack::DriverEventArgs^ args
40 System::Console::WriteLine("[{0}] [{1}] start", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode());
45 case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_OPEN:
47 this->DoOpen(args->dw1, args->dw2);
50 case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_CLOSE:
52 this->DoClose(args->dw1, args->dw2);
55 case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_DATA:
57 this->DoData(args->dw1, args->dw2);
60 case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_LONGDATA:
62 this->DoLongData(args->dw1, args->dw2);
65 case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_ERROR:
67 this->DoError(args->dw1, args->dw2);
70 case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_LONGERROR:
72 this->DoLongError(args->dw1, args->dw2);
75 case Interop::Winmm::DriverCallBack::MM_EXT_WINDOW_MESSAGE::MIM_MOREDATA:
77 this->DoMoreData(args->dw1, args->dw2);
82 System::Console::WriteLine("[{0}] [{1}] end", __FUNCTION__, System::Threading::Thread::CurrentThread->GetHashCode());
86 void Device::DoOpen(System::IntPtr dwParam1, System::IntPtr dwParam2)
89 System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2);
91 this->OnOpen(this, System::EventArgs::Empty);
94 void Device::DoClose(System::IntPtr dwParam1, System::IntPtr dwParam2)
97 System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2);
99 this->OnClose(this, System::EventArgs::Empty);
102 ///<summary>~</summary>
103 ///<remarks>~</remarks>
106 void Device::DoData(System::IntPtr dwParam1, System::IntPtr dwParam2)
109 System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2);
111 auto data = dwParam1.ToInt32();
112 auto time = dwParam2.ToInt32();
113 this->OnData(data, time);
116 void Device::DoLongData(System::IntPtr dwParam1, System::IntPtr dwParam2)
119 System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2);
122 this->Unprepare(dwParam1);
124 auto header = safe_cast<Interop::Winmm::MidiHeader^>(InteropServices::Marshal::PtrToStructure(dwParam1, Interop::Winmm::MidiHeader::typeid));
127 System::Console::WriteLine("[{0}] bytesRecorded {1}", __FUNCTION__, header->bytesRecorded);
130 if (header->bytesRecorded == 0)
133 System::Console::WriteLine("[{0}] resetされたと判断して、再準備はしない", __FUNCTION__);
138 auto data = gcnew array<System::Byte>(header->bytesRecorded);
141 System::Console::Write("[{0}] ", __FUNCTION__);
142 for (System::UInt32 i = 0; i < header->bytesRecorded; i++)
144 System::Console::Write("[{0,2:X}]", InteropServices::Marshal::ReadByte(header->data,i));
146 System::Console::WriteLine();
149 InteropServices::Marshal::Copy( header->data, data, 0, data->Length );
150 auto time = dwParam2.ToInt32();
151 this->OnLongData(data, time);
156 void Device::DoError(System::IntPtr dwParam1, System::IntPtr dwParam2)
159 System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2);
163 void Device::DoLongError(System::IntPtr dwParam1, System::IntPtr dwParam2)
166 System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2);
169 this->Unprepare(dwParam1);
172 void Device::DoMoreData(System::IntPtr dwParam1, System::IntPtr dwParam2)
175 System::Console::WriteLine("[{0}] [{1,8:X}][{2,8:X}]", __FUNCTION__, dwParam1, dwParam2);
178 this->Unprepare(dwParam1);
180 auto header = safe_cast<Interop::Winmm::MidiHeader^>(InteropServices::Marshal::PtrToStructure(dwParam1, Interop::Winmm::MidiHeader::typeid));
183 System::Console::WriteLine("[{0}] bytesRecorded {1}", __FUNCTION__, header->bytesRecorded);
186 auto data = gcnew array<System::Byte>(header->bytesRecorded);
189 System::Console::Write("[{0}] ", __FUNCTION__);
190 for (System::UInt32 i = 0; i < header->bytesRecorded; i++)
192 System::Console::Write("[{0,2:X}]", InteropServices::Marshal::ReadByte(header->data,i));
194 System::Console::WriteLine();
197 InteropServices::Marshal::Copy( header->data, data, 0, data->Length );
199 auto time = dwParam2.ToInt32();
200 this->OnMoreData(data, time);
204 System::UInt32 Device::GetNumDevices()
206 return Interop::Winmm::Function::midiInGetNumDevs();
209 Interop::Winmm::MidiInCapabilities^ Device::GetCapabilities(
210 const System::UInt32 deviceID
213 auto caps = gcnew Interop::Winmm::MidiInCapabilities();
215 System::Console::WriteLine("[{0}] caps size {1}",__FUNCTION__, InteropServices::Marshal::SizeOf(caps));
218 Interop::Winmm::Function::midiInGetDevCaps(
221 InteropServices::Marshal::SizeOf(caps)
223 if (mmResult != Interop::Winmm::MMRESULT::NOERROR)
225 throw gcnew MidiInException(mmResult);
231 const System::UInt32 deviceID
232 ): _deviceID(deviceID)
235 System::Console::WriteLine("[{0}] deviceID {1}",__FUNCTION__, this->_deviceID);
243 System::Console::WriteLine("[{0}]",__FUNCTION__);
251 System::Console::WriteLine("[{0}]",__FUNCTION__);
256 Interop::Winmm::MidiInCapabilities^ Device::GetCapabilities()
258 return Device::GetCapabilities(this->_deviceID);
264 System::Console::WriteLine("[{0}]",__FUNCTION__);
267 this->_callBack = gcnew Core::Winmm::DriverCallBack(false); //イベントは同期で動かす
268 this->_callBack->OnEvent += gcnew System::EventHandler<Interop::Winmm::DriverCallBack::DriverEventArgs^>(this, &Device::OnEventHandler);
271 gcnew Core::Buffer::BufferPool<Interop::Winmm::MidiHeader^>(
273 gcnew Core::Buffer::BufferPool<Interop::Winmm::MidiHeader^>::Allocator(this, &Device::AllocateHeader)
277 gcnew Core::Buffer::BufferPool<array<System::Byte>^>(
279 gcnew Core::Buffer::BufferPool<array<System::Byte>^>::Allocator(this, &Device::AllocateBuffer)
284 Interop::Winmm::Function::midiInOpen(
287 this->_callBack->GetDriverCallBackProc(),
288 System::IntPtr::Zero,
289 Interop::Winmm::DriverCallBack::TYPE::FUNCTION
291 if (mmResult != Interop::Winmm::MMRESULT::NOERROR) {
292 throw gcnew MidiInException(mmResult);
299 auto mmResult = Interop::Winmm::Function::midiInStart(this->_handle);
300 if (mmResult != Interop::Winmm::MMRESULT::NOERROR)
302 throw gcnew MidiInException(mmResult);
307 System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed);
314 System::Console::WriteLine("[{0}] Handle invalid:{1} closed:{2}",__FUNCTION__, this->_handle->IsInvalid, this->_handle->IsClosed);
317 !this->_handle->IsInvalid
318 && !this->_handle->IsClosed
322 auto mmResult = Interop::Winmm::Function::midiInStop(this->_handle);
323 if (mmResult != Interop::Winmm::MMRESULT::NOERROR)
325 throw gcnew MidiInException(mmResult);
328 System::Console::WriteLine("[{0}] midiInStop OK",__FUNCTION__);
333 auto mmResult = Interop::Winmm::Function::midiInReset(this->_handle);
334 if (mmResult != Interop::Winmm::MMRESULT::NOERROR)
336 throw gcnew MidiInException(mmResult);
339 System::Console::WriteLine("[{0}] midiInReset OK",__FUNCTION__);
344 while(this->_headerPool->IsBusy())
347 System::Console::WriteLine("[{0}] wait for unprepare headers ...",__FUNCTION__);
349 System::Threading::Thread::Sleep(5);
352 this->_handle->Close();
357 System::Console::WriteLine("[{0}] openしていない状態なので、無視します。", __FUNCTION__);
361 if (this->_callBack != nullptr)
363 this->_callBack->OnEvent -= gcnew System::EventHandler<Interop::Winmm::DriverCallBack::DriverEventArgs^>(this, &Device::OnEventHandler);
364 delete this->_callBack;
367 if (this->_headerPool != nullptr)
369 delete this->_headerPool;
372 if (this->_bufferPool != nullptr)
374 delete this->_bufferPool;
378 System::IntPtr Device::Prepare()
381 System::Console::WriteLine("[{0}]",__FUNCTION__);
384 auto header = this->_headerPool->Get();
385 auto buffer = this->_bufferPool->Get();
388 auto midiHeader = header->GetBuffer();
389 midiHeader->bufferLength = buffer->GetBuffer()->Length;
390 midiHeader->data = buffer->GetBufferIntPtr();
394 System::Console::WriteLine("[{0}] midiInPrepareHeader before", __FUNCTION__);
395 System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader);
402 Interop::Winmm::Function::midiInPrepareHeader(
404 header->GetBufferIntPtr(),
405 InteropServices::Marshal::SizeOf(Interop::Winmm::MidiHeader::typeid)
407 if (mmResult != Interop::Winmm::MMRESULT::NOERROR)
409 this->_headerPool->Release(header);
410 this->_bufferPool->Release(buffer);
412 throw gcnew MidiInException(mmResult);
417 auto midiHeader = header->GetBuffer();
418 System::Console::WriteLine("[{0}] midiInPrepareHeader after", __FUNCTION__);
419 System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader);
425 Interop::Winmm::Function::midiInAddBuffer(
427 header->GetBufferIntPtr(),
428 InteropServices::Marshal::SizeOf(Interop::Winmm::MidiHeader::typeid)
430 if (mmResult != Interop::Winmm::MMRESULT::NOERROR)
432 System::Console::WriteLine((gcnew MidiInException(mmResult))->ToString());
437 auto midiHeader = header->GetBuffer();
438 System::Console::WriteLine("[{0}] midiInAddBuffer after", __FUNCTION__);
439 System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader);
443 return header->GetBufferIntPtr();
446 void Device::Unprepare(System::IntPtr headerPtr)
449 System::Console::WriteLine("[{0}]",__FUNCTION__);
452 auto header = this->_headerPool->GetBusy(headerPtr);
456 auto midiHeader = header->GetBuffer();
457 System::Console::WriteLine("[{0}] midiInUnprepareHeader before", __FUNCTION__);
458 System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader);
463 Interop::Winmm::Function::midiInUnprepareHeader(
466 InteropServices::Marshal::SizeOf(Interop::Winmm::MidiHeader::typeid)
468 if (mmResult != Interop::Winmm::MMRESULT::NOERROR)
470 throw gcnew MidiInException(mmResult);
473 auto bufferPtr = header->GetBuffer()->data;
474 this->_headerPool->Release(header);
476 auto buffer = this->_bufferPool->GetBusy(bufferPtr);
477 this->_bufferPool->Release(buffer);
481 auto midiHeader = header->GetBuffer();
482 System::Console::WriteLine("[{0}] midiInUnprepareHeader after", __FUNCTION__);
483 System::Console::WriteLine("[{0}] {1}", __FUNCTION__, midiHeader);
488 Interop::Winmm::MidiHeader^ Device::AllocateHeader()
490 return gcnew Interop::Winmm::MidiHeader();
493 array<System::Byte>^ Device::AllocateBuffer()
495 return gcnew array<System::Byte>(256); //SMFとして最大長 + 1
498 System::String^ MidiInException::Initialize()
500 auto errorMessage = System::String::Empty;
501 auto buf = gcnew System::Text::StringBuilder(256);
504 Interop::Winmm::Function::midiInGetErrorText(
509 if (r == Interop::Winmm::MMRESULT::NOERROR)
511 errorMessage = buf->ToString();
515 errorMessage = "不明なエラー";
518 return errorMessage + "[" + this->_mmResult.ToString("D") + "]";