www.pudn.com > tetris_new.rar > MIDI.H


///////////////////////////////////////////////////////////////////////////// 
// Copyright (C) 1998 by Jörg König 
// All rights reserved 
// 
// This file is part of the completely free tetris clone "CGTetris". 
// 
// This is free software. 
// You may redistribute it by any means providing it is not sold for profit 
// without the authors written consent. 
// 
// No warrantee of any kind, expressed or implied, is included with this 
// software; use at your own risk, responsibility for damages (if any) to 
// anyone resulting from the use of this software rests entirely with the 
// user. 
// 
// Send bug reports, bug fixes, enhancements, requests, flames, etc., and 
// I'll try to keep a version up to date.  I can be reached as follows: 
//    J.Koenig@adg.de                 (company site) 
//    Joerg.Koenig@rhein-neckar.de    (private site) 
///////////////////////////////////////////////////////////////////////////// 
 
 
// Midi.h : main header file for the MIDI application 
// 
 
// This class is based on the DirectX sample "mstream". 
 
#ifndef MIDI_h 
#define MIDI_h 
 
#if _MSC_VER >= 1000 
#pragma once 
#endif // _MSC_VER >= 1000 
 
#include  
#pragma message("linking with multimedia library") 
#pragma comment(lib, "winmm.lib") 
 
#include  
using namespace std; 
 
 
// This message is sent to the controlling window, if the volume changes in 
// another way than explicitly set by the owner of the CMIDI object. 
// WPARAM	the pointer to the MIDI object 
// LPARAM	lo-word: the number of the channel that changed volume 
//			hi-word: the new volume in percent 
#define	WM_MIDI_VOLUMECHANGED	WM_USER+23 
 
 
#define MIDI_CTRLCHANGE			((BYTE)0xB0)		// + ctrlr + value 
#define MIDI_PRGMCHANGE			((BYTE)0xC0)		// + new patch 
#define MIDI_CHANPRESS			((BYTE)0xD0)		// + pressure (1 byte) 
 
#define MIDICTRL_VOLUME			((BYTE)0x07) 
 
#define MIDIEVENT_CHANNEL(dw)	(dw & 0x0000000F) 
#define MIDIEVENT_TYPE(dw)		(dw & 0x000000F0) 
#define MIDIEVENT_DATA1(dw)		((dw & 0x0000FF00) >> 8) 
#define MIDIEVENT_VOLUME(dw)	((dw & 0x007F0000) >> 16) 
 
#define MIDI_SYSEX				((BYTE)0xF0)		// SysEx begin 
#define MIDI_SYSEXEND			((BYTE)0xF7)		// SysEx end 
#define MIDI_META				((BYTE)0xFF)		// Meta event begin 
#define MIDI_META_TEMPO			((BYTE)0x51)		// Tempo change 
#define MIDI_META_EOT			((BYTE)0x2F)		// End-of-track 
 
 
// flags for the ConvertToBuffer() method 
#define CONVERTF_RESET				0x00000001 
#define CONVERTF_STATUS_DONE		0x00000001 
#define CONVERTF_STATUS_STUCK		0x00000002 
#define CONVERTF_STATUS_GOTEVENT	0x00000004 
 
// Return values from the ConvertToBuffer() method 
#define CONVERTERR_NOERROR		0		// No error occured 
#define CONVERTERR_CORRUPT		-101	// The input file is corrupt 
// The converter has already encountered a corrupt file and cannot convert any 
// more of this file -- must reset the converter 
#define CONVERTERR_STUCK		-102 
#define CONVERTERR_DONE			-103	// Converter is done 
#define CONVERTERR_BUFFERFULL	-104	// The buffer is full 
#define CONVERTERR_METASKIP		-105	// Skipping unknown meta event 
 
#define STATUS_KILLCALLBACK		100		// Signals that the callback should die 
#define STATUS_CALLBACKDEAD		200		// Signals callback is done processing 
#define STATUS_WAITINGFOREND	300		// Callback's waiting for buffers to play 
 
// Description of a track 
// 
struct TRACK 
{ 
	DWORD	fdwTrack;		// Track's flags 
	DWORD	dwTrackLength;	// Total bytes in track 
	LPBYTE	pTrackStart;	// -> start of track data buffer 
	LPBYTE	pTrackCurrent;	// -> next byte to read in buffer 
	DWORD	tkNextEventDue;	// Absolute time of next event in track 
	BYTE	byRunningStatus;// Running status from last channel msg 
 
	TRACK() 
		: fdwTrack(0) 
		, dwTrackLength(0) 
		, pTrackStart(0) 
		, pTrackCurrent(0) 
		, tkNextEventDue(0) 
		, byRunningStatus(0) 
	{ 
	} 
}; 
 
#define ITS_F_ENDOFTRK		0x00000001 
 
 
// This structure is used to pass information to the ConvertToBuffer() 
// system and then internally by that function to send information about the 
// target stream buffer and current state of the conversion process to internal 
// lower level conversion routines. 
struct CONVERTINFO 
{ 
    MIDIHDR	mhBuffer;			// Standard Windows stream buffer header 
    DWORD	dwStartOffset;		// Start offset from mhStreamBuffer.lpStart 
    DWORD	dwMaxLength;		// Max length to convert on this pass 
    DWORD	dwBytesRecorded; 
    DWORD	tkStart; 
    BOOL	bTimesUp; 
 
	CONVERTINFO() 
		: dwStartOffset(0) 
		, dwMaxLength(0) 
		, dwBytesRecorded(0) 
		, tkStart(0) 
		, bTimesUp(FALSE) 
	{ 
		memset(&mhBuffer, 0, sizeof(MIDIHDR)); 
	} 
}; 
 
// Temporary event structure which stores event data until we're ready to 
// dump it into a stream buffer 
struct TEMPEVENT 
{ 
	DWORD	tkEvent;		// Absolute time of event 
	BYTE	byShortData[4];	// Event type and parameters if channel msg 
	DWORD	dwEventLength;	// Length of data which follows if meta or sysex 
	LPBYTE	pLongData;		// -> Event data if applicable 
}; 
 
class CMIDI   
{ 
protected: 
	typedef vector		TrackArray_t; 
	typedef vector		VolumeArray_t; 
	typedef vector	ConvertArray_t; 
 
	enum { 
		NUM_CHANNELS = 16,		// 16 volume channels 
		VOLUME_INIT = 100,		// 100% volume by default 
		NUM_STREAM_BUFFERS = 2, 
		OUT_BUFFER_SIZE = 1024,	// Max stream buffer size in bytes 
		DEBUG_CALLBACK_TIMEOUT = 2000, 
		VOLUME_MIN = 0, 
		VOLUME_MAX = 127 
	}; 
 
public: 
	CMIDI(); 
	virtual ~CMIDI(); 
 
	BOOL	Create(LPVOID pSoundData, DWORD dwSize, CWnd * pParent = 0); 
	BOOL	Create(LPCTSTR pszResID, CWnd * pParent = 0); 
	BOOL	Create(UINT uResID, CWnd * pParent = 0); 
 
	BOOL	Play(BOOL bInfinite = FALSE); 
	BOOL	Stop(BOOL bReOpen = TRUE); 
	BOOL	IsPlaying() const { return m_bPlaying; } 
 
	BOOL	Pause(); 
	BOOL	Continue(); 
	BOOL	IsPaused() const { return m_bPaused; } 
 
		// Set playback position back to the start 
	BOOL	Rewind(); 
 
		// Get the number of volume channels 
	DWORD	GetChannelCount() const; 
 
		// Set the volume of a channel in percent. Channels are from 0 to (GetChannelCount()-1) 
	void	SetChannelVolume(DWORD channel, DWORD percent); 
 
		// Get the volume of a channel in percent 
	DWORD	GetChannelVolume(DWORD channel) const; 
	 
		// Set the volume for all channels in percent 
	void	SetVolume(DWORD percent); 
 
		// Get the average volume for all channels 
	DWORD	GetVolume() const; 
 
protected:	// implementation 
		// This function converts MIDI data from the track buffers. 
	int		ConvertToBuffer(DWORD dwFlags, CONVERTINFO * lpciInfo); 
 
		// Fills in the event struct with the next event from the track 
	BOOL	GetTrackEvent(TRACK * ptsTrack, TEMPEVENT * pteTemp); 
 
		// Retrieve the next byte from the track buffer, refilling the buffer from 
		// disk if necessary. 
	BOOL	GetTrackByte(TRACK * ptsTrack, LPBYTE lpbyByte) { 
				if( DWORD(ptsTrack->pTrackCurrent - ptsTrack->pTrackStart) == ptsTrack->dwTrackLength ) 
					return FALSE; 
				*lpbyByte = *ptsTrack->pTrackCurrent++; 
				return TRUE; 
			} 
 
		// Attempts to parse a variable length DWORD from the given track. 
	BOOL	GetTrackVDWord(TRACK * ptsTrack, LPDWORD lpdw); 
 
		// Put the given event into the given stream buffer at the given location. 
	int		AddEventToStreamBuffer( TEMPEVENT * pteTemp, CONVERTINFO * lpciInfo ); 
 
		// Opens a MIDI stream. Then it goes about converting the data into a midiStream buffer for playback. 
	BOOL	StreamBufferSetup(); 
 
	void	FreeBuffers(); 
 
 
protected:	// error handling 
		// The default implementation writes the error message in the 
		// debuggers output window. Override if you want a different 
		// behavior. 
	virtual void	MidiError(MMRESULT Result); 
 
		// Failure in converting track into stream. 
		// The default implementation displays the offset and the total 
		// number of bytes of the failed track and the error message in 
		// the debuggers output window.  
	virtual void	TrackError(TRACK *, LPSTR ErrMsg); 
 
 
protected:	// overridables 
		// NOTE THAT, IF YOU OVERRIDE ONE OF THESE METHODS, YOU MUST CALL 
		// THE BASE CLASS IMPLEMENTATION TOO! 
 
		// called when a MIDI output device is opened 
	virtual void	OnMidiOutOpen(); 
	 
		// called when the MIDI output device is closed 
	virtual void	OnMidiOutClose(); 
 
		// called when the specified system-exclusive or stream buffer 
		// has been played and is being returned to the application 
	virtual void	OnMidiOutDone(MIDIHDR &); 
 
		// called when a MEVT_F_CALLBACK event is reached in the MIDI output stream 
	virtual void	OnMidiOutPositionCB(MIDIHDR &, MIDIEVENT &); 
 
 
private:	// callback procedure 
		// This procedure calls the overridables above. 
	static void	CALLBACK	MidiProc(HMIDIOUT, UINT, DWORD, DWORD, DWORD); 
 
 
protected:	// data members 
	DWORD			m_dwSoundSize; 
	LPVOID			m_pSoundData; 
	DWORD			m_dwFormat; 
	DWORD			m_dwTrackCount; 
	DWORD			m_dwTimeDivision; 
	BOOL			m_bPlaying; 
	HMIDISTRM		m_hStream; 
	DWORD			m_dwProgressBytes; 
	BOOL			m_bLooped; 
	DWORD			m_tkCurrentTime; 
	DWORD			m_dwBufferTickLength; 
	DWORD			m_dwCurrentTempo; 
	DWORD			m_dwTempoMultiplier; 
	BOOL			m_bInsertTempo; 
	BOOL			m_bBuffersPrepared; 
	int				m_nCurrentBuffer; 
	UINT			m_uMIDIDeviceID; 
	int				m_nEmptyBuffers; 
	BOOL			m_bPaused; 
	UINT			m_uCallbackStatus; 
	HANDLE			m_hBufferReturnEvent; 
	CWnd *			m_pWndParent; 
	TrackArray_t	m_Tracks; 
	VolumeArray_t	m_Volumes; 
	ConvertArray_t	m_StreamBuffers; 
 
	// data members especially for ConvertToBuffer() 
    TRACK *			m_ptsTrack; 
	TRACK *			m_ptsFound; 
    DWORD			m_dwStatus; 
    DWORD			m_tkNext; 
	DWORD			m_dwMallocBlocks; 
    TEMPEVENT		m_teTemp; 
}; 
 
//{{AFX_INSERT_LOCATION}} 
// Microsoft Developer Studio will insert additional declarations immediately before the previous line. 
 
#endif // MIDI_h