MIDIOutDevice.cpp
上传用户:fs3633
上传日期:2021-05-14
资源大小:909k
文件大小:10k
- /*******************************************************************************
- * MIDIOutDevice.cpp - Implementation for CMIDIOutDevice and related
- * classes.
- *
- * Copyright (C) 2002 Leslie Sanford
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Contact: jabberdabber@hotmail.com
- *
- * Last modified: 09/03/2003
- ******************************************************************************/
- //--------------------------------------------------------------------
- // Dependencies
- //--------------------------------------------------------------------
- #include "MIDIOutDevice.h"
- #include "midi.h"
- //--------------------------------------------------------------------
- // Using declarations
- //--------------------------------------------------------------------
- using midi::CMIDIOutDevice;
- using midi::CMIDIOutException;
- //--------------------------------------------------------------------
- // CMIDIOutHeader implementation
- //--------------------------------------------------------------------
- // Constructor
- CMIDIOutDevice::CMIDIOutHeader::CMIDIOutHeader(HMIDIOUT DevHandle,
- LPSTR Msg,
- DWORD MsgLength) :
- m_DevHandle(DevHandle)
- {
- // Initialize header
- m_MIDIHdr.lpData = Msg;
- m_MIDIHdr.dwBufferLength = MsgLength;
- m_MIDIHdr.dwFlags = 0;
- // Prepare header
- MMRESULT Result = ::midiOutPrepareHeader(DevHandle, &m_MIDIHdr,
- sizeof m_MIDIHdr);
- // If an error occurred, throw exception
- if(Result != MMSYSERR_NOERROR)
- {
- throw CMIDIOutException(Result);
- }
- }
- // Destructor
- CMIDIOutDevice::CMIDIOutHeader::~CMIDIOutHeader()
- {
- ::midiOutUnprepareHeader(m_DevHandle, &m_MIDIHdr,
- sizeof m_MIDIHdr);
- }
- // Sends long message
- void CMIDIOutDevice::CMIDIOutHeader::SendMsg()
- {
- MMRESULT Result = ::midiOutLongMsg(m_DevHandle, &m_MIDIHdr,
- sizeof m_MIDIHdr);
- if(Result != MMSYSERR_NOERROR)
- {
- throw CMIDIOutException(Result);
- }
- }
- //--------------------------------------------------------------------
- // CHeaderQueue implementation
- //--------------------------------------------------------------------
- // Constructor
- CMIDIOutDevice::CHeaderQueue::CHeaderQueue()
- {
- ::InitializeCriticalSection(&m_CriticalSection);
- }
- // Destructor
- CMIDIOutDevice::CHeaderQueue::~CHeaderQueue()
- {
- RemoveAll();
- ::DeleteCriticalSection(&m_CriticalSection);
- }
- // Add header to queue
- void CMIDIOutDevice::CHeaderQueue::AddHeader(
- CMIDIOutDevice::CMIDIOutHeader *Header)
- {
- ::EnterCriticalSection(&m_CriticalSection);
- m_HdrQueue.push(Header);
- ::LeaveCriticalSection(&m_CriticalSection);
- }
- // Remove header from queue
- void CMIDIOutDevice::CHeaderQueue::RemoveHeader()
- {
- ::EnterCriticalSection(&m_CriticalSection);
- if(!m_HdrQueue.empty())
- {
- delete m_HdrQueue.front();
- m_HdrQueue.pop();
- }
- ::LeaveCriticalSection(&m_CriticalSection);
- }
- // Empty header queue
- void CMIDIOutDevice::CHeaderQueue::RemoveAll()
- {
- ::EnterCriticalSection(&m_CriticalSection);
- while(!m_HdrQueue.empty())
- {
- delete m_HdrQueue.front();
- m_HdrQueue.pop();
- }
- ::LeaveCriticalSection(&m_CriticalSection);
- }
- // Determines if the header queue is empty
- bool CMIDIOutDevice::CHeaderQueue::IsEmpty()
- {
- bool Result;
- ::EnterCriticalSection(&m_CriticalSection);
- Result = m_HdrQueue.empty();
- ::LeaveCriticalSection(&m_CriticalSection);
- return Result;
- }
- //--------------------------------------------------------------------
- // CMIDIOutDevice implementation
- //--------------------------------------------------------------------
- // Constructs CMIDIOutDevice object in an closed state
- CMIDIOutDevice::CMIDIOutDevice() :
- m_State(CLOSED)
- {
- // If we are unable to create signalling event, throw exception
- if(!CreateEvent())
- {
- throw CMIDIOutEventFailure();
- }
- }
- // Constructs CMIDIOutDevice object in an opened state
- CMIDIOutDevice::CMIDIOutDevice(UINT DeviceId) :
- m_State(CLOSED)
- {
- // Open device
- Open(DeviceId);
- // If we are unable to create signalling event, throw exception
- if(!CreateEvent())
- {
- Close();
- throw CMIDIOutEventFailure();
- }
- }
- // Destruction
- CMIDIOutDevice::~CMIDIOutDevice()
- {
- // Close device
- Close();
- // Close handle to signalling event
- ::CloseHandle(m_Event);
- }
- // Opens the MIDI output device
- void CMIDIOutDevice::Open(UINT DeviceId)
- {
- // Makes sure the previous device, if any, is closed before
- // opening another one
- Close();
- // Open MIDI output device
- MMRESULT Result = ::midiOutOpen(&m_DevHandle, DeviceId,
- reinterpret_cast<DWORD>(MidiOutProc),
- reinterpret_cast<DWORD>(this),
- CALLBACK_FUNCTION);
- // If we are able to open the device, change state
- if(Result == MMSYSERR_NOERROR)
- {
- m_State = OPENED;
- m_WorkerThread = AfxBeginThread(
- reinterpret_cast<AFX_THREADPROC>(HeaderProc), this);
- }
- // Else opening failed, throw exception
- else
- {
- ::SetEvent(m_Event);
- ::WaitForSingleObject(m_WorkerThread->m_hThread, INFINITE);
- throw CMIDIOutException(Result);
- }
- }
- // Closes the MIDI output device
- void CMIDIOutDevice::Close()
- {
- // Only close an already opened device
- if(m_State == OPENED)
- {
- // Change state
- m_State = CLOSED;
- // Notify our worker thread and wait for it to finish
- ::SetEvent(m_Event);
- ::WaitForSingleObject(m_WorkerThread->m_hThread, INFINITE);
- // Empty header queue - we're finished with the headers
- m_HdrQueue.RemoveAll();
- // Close the MIDI output device
- ::midiOutClose(m_DevHandle);
- }
- }
- // Sends short message
- void CMIDIOutDevice::SendMsg(DWORD Msg)
- {
- if(m_State == OPENED)
- {
- MMRESULT Result = ::midiOutShortMsg(m_DevHandle, Msg);
- if(Result != MMSYSERR_NOERROR)
- {
- throw CMIDIOutException(Result);
- }
- }
- }
- // Sends long message
- void CMIDIOutDevice::SendMsg(LPSTR Msg, DWORD MsgLength)
- {
- if(m_State == OPENED)
- {
- CMIDIOutHeader *Header;
- try
- {
- // Create new header to send system exclusive message
- Header = new CMIDIOutHeader(m_DevHandle, Msg, MsgLength);
- }
- // If memory allocation failed, throw exception
- catch(const std::bad_alloc &)
- {
- throw CMIDIOutMemFailure();
- }
- // If preparing the header failed, rethrow exception
- catch(const CMIDIOutException &)
- {
- throw;
- }
- try
- {
- // Send system exclusive data
- Header->SendMsg();
- // Add header to queue
- m_HdrQueue.AddHeader(Header);
- }
- // If sending system exclusive msg failed, release header
- // and rethrow exception
- catch(const CMIDIOutException &)
- {
- delete Header;
- throw;
- }
- }
- }
- // Determines if the MIDI output device is opened
- bool CMIDIOutDevice::IsOpen() const
- {
- return (m_State == OPENED);
- }
- // Gets the Id for this device
- UINT CMIDIOutDevice::GetDevID() const
- {
- UINT DeviceID;
- MMRESULT Result = ::midiOutGetID(m_DevHandle, &DeviceID);
- if(Result != MMSYSERR_NOERROR)
- {
- throw CMIDIOutException(Result);
- }
- return DeviceID;
- }
- // Gets the capabilities of a particular MIDI output device
- void CMIDIOutDevice::GetDevCaps(UINT DeviceId, MIDIOUTCAPS &Caps)
- {
- MMRESULT Result = ::midiOutGetDevCaps(DeviceId, &Caps,
- sizeof Caps);
- // If we are not able to retrieve device capabilities, throw
- // exception
- if(Result != MMSYSERR_NOERROR)
- {
- throw CMIDIOutException(Result);
- }
- }
- // Creates event for signalling header thread
- bool CMIDIOutDevice::CreateEvent()
- {
- bool Result = true;
- m_Event = ::CreateEvent(NULL, FALSE, FALSE, NULL);
- // If event creation failed, record failure
- if(m_Event == NULL)
- {
- Result = false;
- }
- return Result;
- }
- // Called by Windows when a MIDI input event occurs
- void CALLBACK CMIDIOutDevice::MidiOutProc(HMIDIOUT MidiOut, UINT Msg,
- DWORD Instance, DWORD Param1,
- DWORD Param2)
- {
- CMIDIOutDevice *Device;
-
- Device = reinterpret_cast<CMIDIOutDevice *>(Instance);
- if(Msg == MOM_DONE)
- {
- ::SetEvent(Device->m_Event);
- }
- }
- // Header worker thread
- DWORD CMIDIOutDevice::HeaderProc(LPVOID Parameter)
- {
- CMIDIOutDevice *Device;
-
- Device = reinterpret_cast<CMIDIOutDevice *>(Parameter);
- // Continue while the MIDI output device is open
- while(Device->m_State == OPENED)
- {
- ::WaitForSingleObject(Device->m_Event, INFINITE);
- // Make sure the device is still open
- if(Device->m_State == OPENED)
- {
- // Remove the finished header
- Device->m_HdrQueue.RemoveHeader();
- }
- }
- return 0;
- }