📄 midi.h
字号:
/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1998 by J鰎g K鰊ig
// 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 <mmsystem.h>
#pragma message("linking with multimedia library")
#pragma comment(lib, "winmm.lib")
#include <vector>
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<TRACK> TrackArray_t;
typedef vector<DWORD> VolumeArray_t;
typedef vector<CONVERTINFO> 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 // == 100%
};
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;
// Set the tempo of the playback. Default: 100%
void SetTempo(DWORD percent);
// Get the current tempo in percent (usually 100)
DWORD GetTempo() const;
// You can (un)set an infinite loop during playback.
// Note that "Play()" resets this setting!
void SetInfinitePlay(BOOL bSet = TRUE);
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -