Click here to Skip to main content
15,898,134 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 614.3K   9.5K   147  
A wrapper class library for the DirectMusic MIDI.
// Example_aud.cpp 
// Sample code explaining how to use the CDirectMidi class library (Audio part)
// Last update April 27th, 2004
// Programmed by Carlos Jim�nez de Parga
// Feel free to modify this code 
// Your comments and suggestions are always welcomed

// Main headers

// ANSI I/0 headers
#include <conio.h>
#include <iostream>
#include <math.h> 
// The class wrapper
#include ".\\DirectMidi\\CDirectMidi.h"

// Inline library inclusion

#pragma comment (lib,"dxguid.lib") // guid definitions 
#pragma comment (lib,"winmm.lib")
#pragma comment (lib,"dsound.lib")
#pragma comment (lib,"dxerr9.lib")

using namespace std;
using namespace directmidi;

int main(int argc, char* argv[])
{
	
	CDirectMusic	  CDMusic;
	CDLSLoader		  CLoader;
	COutputPort		  COutPort,COutPort2;
	CInputPort		  CInPort;
	CPortPerformance  CPortPerformance;
	CAPathPerformance CAPathPerformance;
	CCollection		  CCollectionA;
	CInstrument		  CInstrument1;
	CAudioPath		  CAudioPath1;
	CSegment		  CSegment1;
	C3DSegment		  C3DSegment1;
	C3DBuffer		  C3DBuffer1;

	try
	{
				
		/////////////////////////////// INITIALIZATION //////////////////////////

		// Initializes DirectMusic

		CDMusic.Initialize();
		
		// Initializes an audiopath performance

		CAPathPerformance.Initialize(CDMusic,NULL,NULL,DMUS_APATH_DYNAMIC_3D,128);
		
		// Initializes a port performance object

		CPortPerformance.Initialize(CDMusic,NULL,NULL);
		
		// Initializes loader object

		CLoader.Initialize();
		
		// Initializes output port

		COutPort.Initialize(CDMusic);
		
		// Selects the first software synthesizer port

		INFOPORT PortInfo;
		DWORD dwPortCount = 0;
			

		do
			COutPort.GetPortInfo(++dwPortCount,&PortInfo);
		while (!(PortInfo.dwFlags & DMUS_PC_SOFTWARESYNTH));

		
		cout << "Selected output port: " << PortInfo.szPortDescription << endl; 
	
		COutPort.SetPortParams(0,0,0,SET_REVERB | SET_CHORUS,44100);
		COutPort.ActivatePort(&PortInfo);
		
		////////////////////////////////// PLAYING A SEGMENT ////////////////////////////

		// Adds the selected port to the performance

		CPortPerformance.AddPort(COutPort,0,1);
		
		// Loads a MIDI file into the segment

		CLoader.LoadSegment(_T(".\\media\\laststar.mid"),CSegment1,TRUE);
		
		// Repeats the segment until infinite

		CSegment1.SetRepeats(DMUS_SEG_REPEAT_INFINITE); 
		
		// Downloads the segment to the performance

		CSegment1.Download(CPortPerformance);
		
		// Plays the segment

		CPortPerformance.PlaySegment(CSegment1);
		
		cout << "Playing a segment with the port performance. Press a key to continue...\n" << endl;

		getch();

		//////////////////////////////// CHANGING TEMPO //////////////////////////////

		cout << "Changing tempo to 1/2. Press a key to continue...\n" << endl;
		
		CPortPerformance.SetMasterTempo(0.5);

		getch();

		cout << "Changing tempo to 2x. Press a key to continue...\n" << endl;

		CPortPerformance.SetMasterTempo(2.0);

		getch(); 

		CPortPerformance.SetMasterTempo(1.0);

		/////////////////////////////// CHANGING VOLUME ////////////////////////////

		cout << "Changing volume" << endl;

		for (long lV = 0;lV >= -4000;lV-=4) 
		{	
			CPortPerformance.SetMasterVolume(lV);
			Sleep(1);
		}

		for (lV = -4000;lV <= 0;lV+=4) 
		{	
			CPortPerformance.SetMasterVolume(lV);
			Sleep(1);
		}

		cout << "Press a key to continue..." << endl;

		getch();

		////////////////////////// PLAYING A NOTE WITH A PORT PERFORMANCE /////////////////
	
		// Stops the playing segment

		CPortPerformance.Stop(CSegment1);

		// Sends a note-on to the port performance

		CPortPerformance.SendMidiMsg(NOTE_ON,64,127,1);

		cout << "Sending a MIDI note-on to the port performance on PChannel 1. Press a key to continue...\n" << endl;

		getch();

		CPortPerformance.SendMidiMsg(NOTE_OFF,64,127,1);

		////////////// PLAYING A SEGMENT WITH AN AUDIOPATH PERFORMANCE IN 3D ////////////

		// Downloads the segment to the audio path performance

		CSegment1.Download(CAPathPerformance);

		// Plays the segment in the performance

		CAPathPerformance.PlaySegment(CSegment1,NULL);

		cout << "Playing a segment with the audio path performance. Press a key to continue...\n" << endl;

		getch();

		// Stops the current playing segment

		CAPathPerformance.Stop(CSegment1);
		
		C3DSegment1.Initialize(CAPathPerformance);

		// Clones the normal segment to a 3D segment

		C3DSegment1 = CSegment1;

		// Plays the 3D segment in the audiopath performance

		CAPathPerformance.PlaySegment(C3DSegment1);

		// Positions the 3D buffer one unit in the negative X-axis

		C3DSegment1.SetBufferPosition(-1.0,0.0,0.0);

		cout << "Playing a 3D segment on your left. Press a key to continue...\n" << endl;

		getch();
		
		// Positions the 3D buffer one unit in the positive X-axis

		C3DSegment1.SetBufferPosition(1.0,0.0,0.0);

		cout << "Playing a 3D segment on your right. Press a key to continue...\n" << endl;

		getch();

		////////////////////////////// PLAYING A NOTE IN 3D ////////////////////////

		// Stops the playing 3D segment

		CAPathPerformance.Stop(C3DSegment1);
		
		// Sets the buffer position

		C3DSegment1.SetBufferPosition(-1.0,0.0,0.0);

		// Sends a note-on with the 3D segment audiopath configuration

		CAPathPerformance.SendMidiMsg(NOTE_ON,64,127,0,C3DSegment1.GetAudioPath());

		cout << "Playing a MIDI note-on with the audio path performance on your left. Press a key to continue...\n" << endl;
		
		getch();
	
		CAPathPerformance.SendMidiMsg(NOTE_OFF,64,127,0,C3DSegment1.GetAudioPath());

		///////////////////////////// PLAYING A DLS INSTRUMENT IN 3D /////////////////////

		// Gets the defult audiopath for the performance

		CAPathPerformance.GetDefaultAudioPath(CAudioPath1);
		
		// Gets a 3D buffer

		CAudioPath1.Get3DBuffer(C3DBuffer1);
		
		// Positions the 3D buffer one unit in the negative X-axis
		
		C3DBuffer1.SetBufferPosition(-1.0,0.0,0.0);

		// Unloads the segment from the audio path performance

		CSegment1.Unload(CAPathPerformance);

		// Loads the default GM/GS collection

		CLoader.LoadDLS(NULL,CCollectionA);
		
		// Gets the instrument 215

		CCollectionA.GetInstrument(CInstrument1,215);
		
		// Assigns the patch 0

		CInstrument1.SetPatch(0);
		
		// Set up the note range

		CInstrument1.SetNoteRange(0,127);
		
		DWORD dwGroup,dwMChannel;
		
		// Downloads the instrument to the performance channel 1

		CAPathPerformance.DownloadInstrument(CInstrument1,1,&dwGroup,&dwMChannel);
		
		// Selects the patch and plays the note on PChannel 1

		CAPathPerformance.SendMidiMsg(PATCH_CHANGE,0,0,1,CAudioPath1);
		CAPathPerformance.SendMidiMsg(NOTE_ON,64,127,1,CAudioPath1);
		
		cout << "Playing a GM/GS DLS instrument with the audio performance on your left. Press a key to coninue...\n" << endl;
		
		getch();

		///////////////////////// PLAYING A SAMPLE INSTRUMENT IN 3D ///////////////

	
		CAPathPerformance.SendMidiMsg(NOTE_OFF,64,0,1,CAudioPath1);		
		
		// Unloads the instrument from the audiopath
		CAPathPerformance.UnloadInstrument(CInstrument1);
		

		// Gets the port where the performance channel 2 resides

		IDirectMusicPort8* pPort = NULL;

		CAPathPerformance.PChannelInfo(2,&pPort,NULL,NULL);

		// Initializes output port

		COutPort2.Initialize(CDMusic);
		
		// Activates ouput port from the interface

		COutPort2.ActivatePortFromInterface(pPort);

		CSampleInstrument CSample1;
		
		// Loads the .wav file

		CDLSLoader::LoadWaveFile(_T(".\\media\\starbreeze.wav"),CSample1,DM_USE_MEMORY);
		
		// Assigns the patch

		CSample1.SetPatch(2);
		
		// Sets a continuous wave loop
		
		CSample1.SetLoop(TRUE);
		
		// Set additional wave parameters
		
		CSample1.SetWaveParams(0,0,68,F_WSMP_NO_TRUNCATION); 
		
		REGION region;
		ARTICPARAMS articparams;
		
		// Initializes structures

		ZeroMemory(&region,sizeof(REGION));
		ZeroMemory(&articparams,sizeof(ARTICPARAMS));
		
		
		// Sets the region parameters

		region.RangeKey.usHigh = 127;
		region.RangeKey.usLow = 0;
		region.RangeVelocity.usHigh = 127;
		
		// Adjust LFO
		
		articparams.LFO.tcDelay = TimeCents(10.0);
		articparams.LFO.pcFrequency = PitchCents(5.0);
		
		// Sets the pitch envelope

		articparams.PitchEG.tcAttack  = TimeCents(0.0);
		articparams.PitchEG.tcDecay   = TimeCents(0.0);
		articparams.PitchEG.ptSustain = PercentUnits(0.0);
		articparams.PitchEG.tcRelease = TimeCents(0.0);

		
		// Sets the volume envelope

		articparams.VolEG.tcAttack  = TimeCents(1.275);
		articparams.VolEG.tcDecay   = TimeCents(0.0);
		articparams.VolEG.ptSustain = PercentUnits(100.0);
		articparams.VolEG.tcRelease = TimeCents(10.157);
		
		
		// Sets the instrument parameters

		CSample1.SetRegion(&region);
		CSample1.SetArticulationParams(&articparams);
		
		// Allocate interface memory

		COutPort2.AllocateMemory(CSample1);
		
		// Download the sample instrument to the port

		COutPort2.DownloadInstrument(CSample1);


		// Positions the buffer

		C3DBuffer1.SetBufferPosition(1.0,0.0,0.0);

		// Selects patch and plays the note

		CAPathPerformance.SendMidiMsg(PATCH_CHANGE,2,0,2,CAudioPath1);
		
		CAPathPerformance.SendMidiMsg(NOTE_ON,64,127,2,CAudioPath1);
		
		
		cout << "Playing a downloaded WAV file with the audio path performance on the right. Press a key to continue... \n" << endl;
		
		getch();
		
		///////////// PLAYING A 3D SAMPLE INSTRUMENT WITH AN EXTERNAL KEYBOARD ///////////

		CAPathPerformance.SendMidiMsg(NOTE_OFF,64,127,2,CAudioPath1);
		
		// Initializes and activates default input MIDI port

		CInPort.Initialize(CDMusic);
		CInPort.GetPortInfo(1,&PortInfo);
		CInPort.ActivatePort(&PortInfo);

		// Finds out which group and MIDI channel are assigned to PChannel 2 
		
		CAPathPerformance.PChannelInfo(2,NULL,&dwGroup,&dwMChannel);
		
		// Activates the thru over the retrieved MIDI channel and group

		CInPort.SetThru(0,dwGroup,dwMChannel,COutPort2);

		cout << "Activating MIDI thru from input MIDI channel 0 to PChannel 2.\n" \
			"Play with an external keyboard. Press a key to continue... \n" << endl;
		getch();

		//////////////////////// RETRIEVING A STANDARD DMO OBJECT ///////////////////

		// Releases the old audiopath handler

		CAudioPath1.ReleaseAudioPath();
		
		CAPathPerformance.RemoveDefaultAudioPath();

		// Creates a new audiopath

		CAPathPerformance.CreateAudioPath(CAudioPath1,DMUS_APATH_SHARED_STEREOPLUSREVERB,64,TRUE);
		
		// Declares a DMO interface pointer
		
		CComPtr<IDirectSoundFXWavesReverb8> pEffectDMO;

		// Gets the DMO

		CAudioPath1.GetObjectInPath(DMUS_PCHANNEL_ALL,DMUS_PATH_BUFFER_DMO,
		1,GUID_All_Objects,0,IID_IDirectSoundFXWavesReverb8,(void**)&pEffectDMO);

		// Maximum reverberation     

		DSFXWavesReverb FX; 
		
		FX.fInGain			= DSFX_WAVESREVERB_INGAIN_MAX;    
		FX.fReverbMix		= DSFX_WAVESREVERB_REVERBMIX_MAX;    
		FX.fReverbTime		= DSFX_WAVESREVERB_REVERBTIME_MAX;    
		FX.fHighFreqRTRatio = DSFX_WAVESREVERB_HIGHFREQRTRATIO_MAX;    
		
		pEffectDMO->SetAllParameters(&FX);		    			
		
		cout << "Playing a sample on PChannel 2 with maximum reverberation.\n" \
			"Play with an external keyboard. Press a key to end the application...\n" << endl;
		
		getch();


	}
	catch (CDMusicException& DMExcp)
	{
		cout << "\n" << DMExcp.GetErrorDescription() << "\n" << endl;
	}

	return 0;
}


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