Click here to Skip to main content
15,885,757 members
Articles / Artificial Intelligence

Developing MIDI applications with DirectMusic

Rate me:
Please Sign up or sign in to vote.
4.91/5 (45 votes)
11 Apr 2008LGPL325 min read 609.4K   9.5K   147  
A wrapper class library for the DirectMusic MIDI.
/*
 ____   _  ____  _____ _____ ______  __  __  _  ____   _
|  _ \ | ||  _ \|  __//  __//_   _/ |  \/  || ||  _ \ | |
| |_| || || |> /|  _| | <__   | |   | |\/| || || |_| || | 
|____/ |_||_|\_\|____\\____/  |_|   |_|  |_||_||____/ |_|			 

////////////////////////////////////////////////////////////////////////
  
  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
 
 
Copyright (c) 2002-2004 by Carlos Jim�nez de Parga  
All rights reserved.
For any suggestion or failure report, please contact me by:
e-mail: cjimenez@isometrica.net

Note: I would appreciate very much if you could provide a brief description of your project, 
as well as any report on bugs or errors. This will help me improve the code for the benefit of your
application and the other users  
  
///////////////////////////////////////////////////////////////////////
Version: 2.3b
Module : CMidiPart.h
Purpose: Defines the header implementation for the Midi part classes
Created: CJP / 02-08-2002
History: CJP / 20-02-2004 
Date format: Day-month-year
	
	Update: 20/09/2002

	1. Improved class destructors

	2. Check member variables for NULL values before performing an operation
		
	3. Restructured the class system
	
	4. Better method to enumerate and select MIDI ports
	
	5. Adapted the external thread to a  virtual function

	6. SysEx reception and sending enabled

	7. Added flexible conversion functions

	8. Find out how to activate the Microsoft software synth. 

	9. Added DLS support

  Update: 25/03/2003

	10. Added exception handling

    11. Fixed bugs with channel groups
  
    12. Redesigned class hierarchy
	
    13. DirectMidi wrapped in the directmidi namespace
  
    14. UNICODE/MBCS support for instruments and ports

	15. Added DELAY effect to software synthesizer ports
	
	16. Project released under GNU (General Public License) terms		 

  Update: 03/10/2003	

	17. Redesigned class interfaces

	18. Safer input port termination thread

	19. New CMasterClock class

	20. DLS files can be loaded from resources

	21. DLS instruments note range support

	22. New CSampleInstrument class added to the library

	23. Direct download of samples to wave-table memory
	
	24. .WAV file sample format supported	

	25. New methods added to the output port class

	26. Fixed small bugs

  Update: 20/02/2004

	27. Added new DirectMusic classes for Audio handling

	28. Improved CMidiPort class with internal buffer run-time resizing

	29. 3D audio positioning

*/

#ifndef CMIDIPART_H
#define CMIDIPART_H

#include "CDirectBase.h"
using namespace directmidi;

namespace directmidi
{	
	class CInstrument;
	class CCollection;
	class CDLSLoader;
	class CMidiPort;
	class CReceiver;
	class CInputPort;
	class COutputPort;
	class CDirectMusic;
	class CSampleInstrument;
	class CMasterClock;
	class CSegment;
	class CPerformance;
	class CAPathPerformance;
	class CPortPerformance;
	class CAudioPath;
	class CSegment;
	class C3DSegment;
	class C3DListener;
	class C3DBuffer;

	// Definition of the class instrument
	class CInstrument
	{
	friend CPerformance;
	friend CCollection;
	friend COutputPort;
		DMUS_NOTERANGE							m_NoteRange;
		// Copying and assignment not allowed
	    CInstrument(const CInstrument&);
        CInstrument &operator = (const CInstrument&);
	protected:
		IDirectMusicDownloadedInstrument8*		m_pDownLoadedInstrument; // Interface pointers
		IDirectMusicInstrument8*				m_pInstrument;	
		IDirectMusicPort8*						m_pPort;
	public:
		CInstrument();
		~CInstrument();
		HRESULT SetPatch(DWORD dwdstPatchMidi);	// Sets the instrument of the collection in a MIDI program
		void	SetNoteRange(DWORD dwLowNote,DWORD dwHighNote); // Sets the note range 
		void    GetNoteRange(LPDWORD pdwLowNote, LPDWORD pdwHighNote); // Gets the note range
		DWORD m_dwPatchInCollection;			// Information provided by the class
		DWORD m_dwPatchInMidi;					
		TCHAR m_strInstName[MAX_PATH];			// Instrument description in MBCS/UNICODE chars
	};


	// Definition of the collection class
	class CCollection
	{
	friend CDLSLoader;
	friend CSegment;
	
		// Copying and assignment not allowed
	    CCollection(const CCollection &);
        CCollection &operator = (const CCollection&);
	protected:	
		IDirectMusicCollection8*	m_pCollection;	// Interface pointer
	public:	
		CCollection();
		~CCollection();
		HRESULT EnumInstrument(DWORD dwIndex,LPINSTRUMENTINFO InstInfo);	// Enumerates instruments
		HRESULT GetInstrument(CInstrument &Instrument,LPINSTRUMENTINFO InstInfo);	// Gets the instrument
		HRESULT GetInstrument(CInstrument &Instrument,INT nIndex);
	};

	// Definition of the loader class

	class CDLSLoader
	{
		// Copying and assignment not allowed
	    CDLSLoader(const CDLSLoader&);
        CDLSLoader &operator = (const CDLSLoader&);
	protected:	
		IDirectMusicLoader8*		m_pLoader; // Interface pointer
	public:
		CDLSLoader();
		~CDLSLoader();
		HRESULT Initialize();	// Initialize the object
		HRESULT LoadDLS(LPTSTR lpFileName,CCollection &Collection);	// Loads a DLS file
		HRESULT LoadDLSFromResource(LPTSTR strResource,LPTSTR strResourceType,CCollection &Collection);
		static HRESULT LoadWaveFile(LPTSTR lpstrFileName,CSampleInstrument &SampleInstrument,BOOL bReadAlways);
		HRESULT SetSearchDirectory(LPTSTR  pszPath,BOOL fClear); // Sets the search directory
		HRESULT UnloadCollection(CCollection &Collection);	// Unload the collection from the loader
		HRESULT LoadSegment(LPTSTR lpstrFileName,CSegment &Segment,BOOL bIsMIDIFile = FALSE); // Loads a segment
		HRESULT LoadSegmentFromResource(TCHAR *strResource,TCHAR *strResourceType,CSegment &Segment,BOOL bIsMidiFile = FALSE);
		
	};

	// CDirectMusic main class definition

	class CDirectMusic
	{
	friend CMasterClock;
	friend CMidiPort; 
	friend CPortPerformance;
	friend CAPathPerformance;
		// Copying and assignment not allowed
	    CDirectMusic(const CDirectMusic&);
        CDirectMusic &operator = (const CDirectMusic&);
	protected:	
		IDirectMusic8*			    m_pMusic8; // DirectMusic interface pointer
	public:
		CDirectMusic();					// Constructor and the destructor of the class
		~CDirectMusic();
		HRESULT Initialize(HWND hWnd = NULL,IDirectSound8* pDirectSound = NULL);	// Initialize object and DirectSound
		
	};

	// CMasterClock class definition
	
	class CMasterClock
	{
		// Copying and assignment not allowed
	    CMasterClock(const CMasterClock&);
        CMasterClock &operator = (const CMasterClock&);
	protected:
		IReferenceClock*		    m_pReferenceClock;
		IDirectMusic8*				m_pMusic8;
	public:
		CMasterClock();
		~CMasterClock();

		HRESULT Initialize(CDirectMusic &DMusic); // Initialize the object
		HRESULT ReleaseMasterClock(); // Frees the resources
		DWORD	GetNumClocks();		  // Returns the number of clocks available in the system 
		HRESULT GetClockInfo(DWORD dwNumClock,LPCLOCKINFO ClockInfo); // Get clock info
		HRESULT ActivateMasterClock(LPCLOCKINFO ClockInfo);	// Activate clock
		IReferenceClock* GetReferenceClock(); // Returns the IReferenceClock Interface
	};
	
	class CMidiPort
	{
		DWORD					   m_dwPortType;
		// Copying and assignment not allowed
	 protected:
		IDirectMusicPort8*		   m_pPort;		// Pointer to IDirectMusicPort interface
		IDirectMusicBuffer8*	   m_pBuffer;	// Interface pointer to the buffer for incoming MIDI events 
		IDirectMusic8*			   m_pMusic8;	// Pointer to the DirectMusic interface
		IKsControl*				   m_pControl;	// Interace properties pointer
		DMUS_PORTPARAMS8		   m_PortParams; // Port features
		HRESULT ActivatePort(LPINFOPORT InfoPort,DWORD dwSysExSize,BOOL bFromInterface); // Activate the MIDI port
	public:
		CMidiPort(DWORD dwType);
		~CMidiPort();
		HRESULT	Initialize(CDirectMusic &DMusic); // Initialize the ports
		DWORD	GetNumPorts();	// Returns the number of midi ports
		HRESULT GetPortInfo(DWORD dwNumPort,LPINFOPORT lpInfoPort);	// Gets port info
		HRESULT GetActivatedPortInfo(LPINFOPORT lpInfoPort);
		HRESULT KsProperty(GUID Set,ULONG Id,ULONG Flags,LPVOID pvPropertyData,ULONG ulDataLength,PULONG pulBytesReturned);
		HRESULT SetBuffer(DWORD dwBufferSize);
		HRESULT RemoveBuffer();
	};

	// Receiver class

	class CReceiver
	{
	public:
		// Virtual functions to receive midi messages, structured and unstructured
		virtual void RecvMidiMsg(REFERENCE_TIME rt,DWORD dwChannel,DWORD dwBytesRead,BYTE *lpBuffer)=0; 
		virtual void RecvMidiMsg(REFERENCE_TIME rt,DWORD dwChannel,DWORD dwMsg)=0;
	};
	
	// CInputPort class definition

	class CInputPort:public CMidiPort
	{
		typedef	std::vector<WORD> VECTOR;	
		HANDLE					   m_hEvent,m_hTerminationEvent;	// Event handler	
		HANDLE					   m_hThread;
		BOOL					   m_ProcessActive;	// Thread exit condition
		std::list<VECTOR> m_ChannelList;	// Channel STL list	   
		std::list<VECTOR>::iterator m_ChannelIterator;	// STL list iterator
		// Copying and assignment not allowed
	    CInputPort(const CInputPort&);
        CInputPort &operator = (const CInputPort&);

	protected:	
		CReceiver*				   m_pReceiver; // Pointer to CReceiver object
		IDirectMusicThru8*         m_pThru;		// Pointer to IdirectMusicThru interface
		HRESULT ReadBuffer();					// Read the buffer
		HRESULT ResetBuffer();					// Reset the buffer pointer
		HRESULT GetMidiEvent(REFERENCE_TIME *lprt,DWORD *lpdwGroup,DWORD *lpcb,BYTE **lppb); // Extract an event
		HRESULT BreakAllThru();
	public:
		CInputPort();										// The constructor and the destructor of the class
		~CInputPort();									    // Public member functions exposed by the class 						
		HRESULT ActivatePort(LPINFOPORT InfoPort,DWORD dwSysExSize = 32);
		HRESULT ActivatePortFromInterface(IDirectMusicPort8* pPort,DWORD dwSysExSize = 32);
		HRESULT ActivateNotification();	// Activate the event notification 
		BOOL	SetThreadPriority(int nPriority); // Sets the thread priority 
		HRESULT SetReceiver(CReceiver &Receiver);
		HRESULT ReleasePort();			// Releases the references to the interfaces	
		HRESULT SetThru(DWORD dwSourceChannel,DWORD dwDestinationChannelGroup,DWORD dwDestinationChannel,COutputPort &dstMidiPort); //Activate Thru
		HRESULT BreakThru(DWORD dwSourceChannel,DWORD dwDestinationChannelGroup,DWORD dwDestinationChannel);	//Desactivate Thru
		HRESULT TerminateNotification();				// Terminate the event notification	
		static DWORD WINAPI WaitForEvent(LPVOID lpv);	// Main thread for reading events	
		static void DecodeMidiMsg(DWORD dwMsg,BYTE *Status,BYTE *DataByte1,BYTE *DataByte2); // Decode a Midi Message		
		static void DecodeMidiMsg(DWORD Msg,BYTE *Command,BYTE *Channel,BYTE *DataByte1,BYTE *DataByte2);
	};
													
	// COutputPort class definition

	class COutputPort:public CMidiPort
	{
	friend CInputPort;
	friend CPortPerformance;
		// Copying and assignment not allowed
	    COutputPort(const COutputPort&);
        COutputPort &operator = (const COutputPort&);
	protected:	
		IReferenceClock*					m_pClock;	// Pointer to the Reference Clock
		IDirectMusicPortDownload8*			m_pPortDownload;
	public:
		COutputPort();										// Constructor and the destructor of the class
		~COutputPort();   											
		HRESULT ActivatePort(LPINFOPORT InfoPort,DWORD dwSysExSize = 32);
		HRESULT ActivatePortFromInterface(IDirectMusicPort8* pPort,DWORD dwSysExSize = 32);
		void	SetPortParams(DWORD dwVoices,DWORD dwAudioChannels,DWORD dwChannelGroups,DWORD dwEffectFlags,DWORD dwSampleRate);
		HRESULT ReleasePort();	// Releases the references to the interfaces
		HRESULT AllocateMemory(CSampleInstrument &SampleInstrument);
		HRESULT DownloadInstrument(CInstrument &Instrument);	// Download an instrument to the port
		HRESULT DownloadInstrument(CSampleInstrument &SampleInstrument);
		HRESULT UnloadInstrument(CInstrument &Instrument);	// Unload an instrument from the port
		HRESULT UnloadInstrument(CSampleInstrument &SampleInstrument); // Unload a sample instrument
		HRESULT DeallocateMemory(CSampleInstrument &SampleInstrument); // Frees the memory reserved by the interfaces
		HRESULT CompactMemory(); // Compact wave-table memory
		HRESULT GetChannelPriority(DWORD dwChannelGroup,DWORD dwChannel,LPDWORD pdwPriority);
		HRESULT SetChannelPriority(DWORD dwChannelGroup,DWORD dwChannel,DWORD dwPriority);
		HRESULT GetSynthStats(LPSYNTHSTATS SynthStats);
		HRESULT GetFormat(LPWAVEFORMATEX pWaveFormatEx,LPDWORD pdwWaveFormatExSize,LPDWORD pdwBufferSize);
		HRESULT GetNumChannelGroups(LPDWORD pdwChannelGroups);
		HRESULT SetNumChannelGroups(DWORD dwChannelGroups);
		HRESULT SetEffect(BYTE bEffect);	// Activate midi effects
		HRESULT SendMidiMsg(DWORD dwMsg,DWORD dwChannelGroup);	// Sends a message to the port in DWORD format
		HRESULT SendMidiMsg(LPBYTE lpMsg,DWORD dwLength,DWORD dwChannelGroup);	// Sends an unstrucuted message to the port
		IReferenceClock* GetReferenceClock(); // Returns the IReferenceClock interface
		static DWORD EncodeMidiMsg(BYTE Status,BYTE DataByte1,BYTE DataByte2); // Conversion functions	
		static DWORD EncodeMidiMsg(BYTE Command,BYTE Channel,BYTE DataByte1,BYTE DataByte2);
	};
													
	// CSampleInstrument class definition
	
	class CSampleInstrument
	{
	friend CDLSLoader;
	friend COutputPort;	
		
		// Internal DLS 1.0 structures 
	
		struct INSTRUMENT_DOWNLOAD
		{	
			DMUS_DOWNLOADINFO dlInfo;
			ULONG			  ulOffsetTable[4];
			DMUS_INSTRUMENT   dmInstrument;
			DMUS_REGION		  dmRegion;
			DMUS_ARTICULATION dmArticulation;
			DMUS_ARTICPARAMS  dmArticParams;
		};
		
		struct WAVE_DOWNLOAD
		{
			DMUS_DOWNLOADINFO dlInfo;
			ULONG			  ulOffsetTable[2];
			DMUS_WAVE		  dmWave;
			DMUS_WAVEDATA	  dmWaveData;
		};

		// Private member variables

		REGION								m_Region;
		ARTICPARAMS							m_Articparams;
		WAVEFORMATEX						m_wfex;
		BYTE*								m_pRawData;
		DWORD								m_dwSize;
		DWORD								m_dwPatch;
		BOOL								m_bReadAlways;
		BOOL								m_bFileRead;
		BOOL								m_bWaveFormSet;
		BOOL								m_bLoop;
		LONG								m_lAttenuation;
		SHORT								m_sFineTune;
		USHORT								m_usUnityNote;
		ULONG								m_fulOptions;
		TCHAR								m_lpstrFileName[_MAX_FNAME];

		// Private internal member functions

		BOOL InitializeInstDownload(INSTRUMENT_DOWNLOAD *pInstDownload,DWORD dwDLId,DWORD dwDLIdWave);
		BOOL InitializeWaveDownload(WAVE_DOWNLOAD *pWaveDownload,DWORD dwDLId,WAVEFORMATEX *pwfex,DWORD dwWaveSize,DWORD dwOverallSize);
		HRESULT AllocateInstBuffer();
		HRESULT AllocateWaveBuffer(DWORD dwAppend);
		HRESULT GetWaveBuffer(DWORD dwDLId);
		HRESULT GetInstBuffer(DWORD dwDLId);
		
		// Copying and assignment not allowed
	    
		CSampleInstrument(const CSampleInstrument&);
        CSampleInstrument &operator = (const CSampleInstrument&);

		
	protected:
		// DLS interfaces 
		IDirectMusicDownload8*				m_pArticulationDownload;
		IDirectMusicDownload8*				m_pWaveDownload;
		
		// Port download required interface
		IDirectMusicPortDownload8*			m_pPortDownload;
	public:
		CSampleInstrument();		// Constructor/Destructor	
		~CSampleInstrument();
		void SetPatch(DWORD dwPatch);	// Sets the patch in a MIDI program
		void SetWaveForm(BYTE *pRawData,WAVEFORMATEX *pwfex,DWORD dwSize); // Sets s waveform data
		void GetWaveForm(BYTE **pRawData,WAVEFORMATEX *pwfex,DWORD *dwSize); // Returns a pointer to waveform data
		void SetLoop(BOOL bLoop); // Loops a sample 
		void SetWaveParams(LONG lAttenuation,SHORT sFineTune,USHORT usUnityNote,ULONG fulOptions);
		void GetWaveParams(LONG *plAttenuation,SHORT *psFineTune,USHORT *pusUnityNote,ULONG *pfulOptions);
		DWORD GetWaveFormSize(); 
		void SetRegion(REGION *pRegion);
		void SetArticulationParams(ARTICPARAMS *pArticParams);
		void GetRegion(REGION *pRegion);
		void GetArticulationParams(ARTICPARAMS *pArticParams);
		HRESULT ReleaseSample(); // Frees the resources adquired by the sample
				
	};
}

#endif												// End of class definitions

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Software Developer
Spain Spain
I obtained my PhD degree in Computer Graphics at the National Distance Education University (UNED) in October 2019. I also hold a Ms. degree in Software Engineering and Computer Systems and a Bs. degree in Computer Science from the National Distance Education University (UNED).
I have been employed as a C++ software developer in several companies since year 2000.
I currently work as a Tutor-Professor of Symbolic Logic, Discrete Math and Java Object-Oriented Programming at UNED-Cartagena (Spain) since 2015.

Comments and Discussions