345 lines
12 KiB
C++
345 lines
12 KiB
C++
/*********************************************************************************/
|
|
/*!
|
|
@file MidiEvent.h
|
|
|
|
@brief xxxxx.
|
|
|
|
@author L. J. Barman
|
|
|
|
Copyright (c) 2008-2013, L. J. Barman, all rights reserved
|
|
|
|
This file is part of the PianoBooster application
|
|
|
|
PianoBooster is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
PianoBooster 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with PianoBooster. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
/*********************************************************************************/
|
|
|
|
#ifndef __MIDI_EVENT_H__
|
|
#define __MIDI_EVENT_H__
|
|
|
|
#include <string>
|
|
#include "Util.h"
|
|
|
|
#define MIDI_NOTE_OFF 0x80 /* MIDI voice messages */
|
|
#define MIDI_NOTE_ON 0x90
|
|
#define MIDI_NOTE_PRESSURE 0xA0 //POLY_AFTERTOUCH: 3 bytes
|
|
#define MIDI_CONTROL_CHANGE 0xB0
|
|
#define MIDI_PROGRAM_CHANGE 0xC0
|
|
#define MIDI_CHANNEL_PRESSURE 0xD0 //AFTERTOUCH: 2 bytes
|
|
#define MIDI_PITCH_BEND 0xE0
|
|
#define MIDI_SYSTEM_EVENT 0xF0
|
|
#define MIDI_SUSTAIN 0x40
|
|
#define MIDI_MAIN_VOLUME 0x07
|
|
#define MIDI_RESET_ALL_CONTROLLERS 121
|
|
#define MIDI_ALL_SOUND_OFF 120
|
|
#define MIDI_ALL_NOTES_OFF 123 //0x7B channel mode message
|
|
|
|
// now define some of our own events
|
|
#define MIDI_NONE 0x0ff0
|
|
#define MIDI_ERROR 0x0ff1
|
|
#define MIDI_PB_EOF 0x0ff2
|
|
#define MIDI_PB_chordSeparator 0x0ff3 // All the notes (note on) between these counts as one chord
|
|
#define MIDI_PB_tempo 0x0ff4
|
|
#define MIDI_PB_timeSignature 0x0ff5
|
|
#define MIDI_PB_keySignature 0x0ff6
|
|
#define MIDI_PB_collateRawMidiData 0x0ff7
|
|
#define MIDI_PB_outputRawMidiData 0x0ff8 // Raw data is used for used for a SYSTEM_EVENT
|
|
|
|
/*===================================*/
|
|
/* */
|
|
/* Standard MIDI file events */
|
|
/* */
|
|
/*===================================*/
|
|
#define MIDI_SYSEXEVENT 0xF0
|
|
#define METAEVENT 0xFF
|
|
#define METASEQN 0
|
|
#define METATEXT 1
|
|
#define METACOPYR 2
|
|
#define METATNAME 3
|
|
#define METAINAME 4
|
|
#define METALYRIC 5
|
|
#define METAMARKER 6
|
|
#define METACUEPT 7
|
|
#define METACHANPFX 0x20
|
|
#define METAEOT 0x2F
|
|
#define METATEMPO 0x51
|
|
#define METASMPTEOFF 0x54
|
|
#define METATIMESIG 0x58
|
|
#define METAKEYSIG 0x59
|
|
#define METASEQEVENT 0x7F
|
|
|
|
#define GM_PIANO_PATCH 0 // The default grand piano sound
|
|
#define isPianoOrOrganPatch(p) (((p) >= 0 && (p) <=7) || ((p) >= 16 && (p) <= 23 ))
|
|
|
|
/*!
|
|
* @brief xxxxx.
|
|
*/
|
|
class CMidiEvent
|
|
{
|
|
public:
|
|
|
|
CMidiEvent()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
m_type = MIDI_NONE;
|
|
m_deltaTime = 0;
|
|
m_channel = 0;
|
|
m_note = 0;
|
|
m_velocity = 0;
|
|
m_duration = 0;
|
|
}
|
|
|
|
int deltaTime() const { return m_deltaTime; }
|
|
void addDeltaTime(int delta){m_deltaTime +=delta;}
|
|
void subtractDeltaTime(int delta){m_deltaTime -=delta;}
|
|
void setDeltaTime(int delta){m_deltaTime = delta;}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//@brief returns the midi note number
|
|
int note() const {return m_note;}
|
|
void setNote(int note){m_note = note;}
|
|
int programme() const {return m_note;}
|
|
int channel() const {return m_channel;} // can also contain the track number
|
|
void setChannel(int chan){m_channel = chan;}
|
|
int velocity() const {return m_velocity;}
|
|
void setVelocity(int value) {m_velocity = value;}
|
|
int type() const {return m_type;}
|
|
void setType(int type){m_type = type;}
|
|
void transpose(int amount) {m_note += amount;}
|
|
int data1() const {return m_note;} // Meta data is stored here
|
|
int data2() const {return m_velocity;}
|
|
void setDatat2(int value) {m_velocity = value;}
|
|
void setTrack(int track) {m_track = track;}
|
|
int track() {return m_track;}
|
|
|
|
void noteOffEvent( int deltaTime, int channel, int note, int velocity)
|
|
{
|
|
m_type = MIDI_NOTE_OFF;
|
|
m_deltaTime = deltaTime;
|
|
m_channel = channel;
|
|
m_note = note;
|
|
m_velocity = velocity;
|
|
}
|
|
|
|
void noteOnEvent( int deltaTime, int channel, int note, int velocity)
|
|
{
|
|
m_type = MIDI_NOTE_ON;
|
|
m_deltaTime = deltaTime;
|
|
m_channel = channel;
|
|
m_note = note;
|
|
m_velocity = velocity;
|
|
}
|
|
|
|
void notePressure( int deltaTime, int channel, int data1, int data2)
|
|
{
|
|
m_type = MIDI_NOTE_PRESSURE; //POLY_AFTERTOUCH: 3 bytes
|
|
m_deltaTime = deltaTime;
|
|
m_channel = channel;
|
|
m_note = data1;
|
|
m_velocity = data2;
|
|
}
|
|
|
|
void programChangeEvent( int deltaTime, int channel, int program)
|
|
{
|
|
m_type = MIDI_PROGRAM_CHANGE;
|
|
m_deltaTime = deltaTime;
|
|
m_channel = channel;
|
|
m_note = program;
|
|
m_velocity = 0;
|
|
}
|
|
|
|
void controlChangeEvent( int deltaTime, int channel, int data1, int data2)
|
|
{
|
|
m_type = MIDI_CONTROL_CHANGE;
|
|
m_deltaTime = deltaTime;
|
|
m_channel = channel;
|
|
m_note = data1;
|
|
m_velocity = data2;
|
|
}
|
|
|
|
void channelPressure( int deltaTime, int channel, int data1)
|
|
{
|
|
m_type = MIDI_CHANNEL_PRESSURE; //AFTERTOUCH: 2 bytes
|
|
m_deltaTime = deltaTime;
|
|
m_channel = channel;
|
|
m_note = data1;
|
|
m_velocity = 0;
|
|
}
|
|
|
|
void pitchBendEvent( int deltaTime, int channel, int data1, int data2)
|
|
{
|
|
m_type = MIDI_PITCH_BEND;
|
|
m_deltaTime = deltaTime;
|
|
m_channel = channel;
|
|
m_note = data1;
|
|
m_velocity = data2;
|
|
}
|
|
|
|
void chordSeparator(CMidiEvent &event)
|
|
{
|
|
m_type = MIDI_PB_chordSeparator;
|
|
m_note = 0;
|
|
m_channel = event.channel();
|
|
m_deltaTime = 0;
|
|
m_velocity = 0;
|
|
}
|
|
|
|
void metaEvent( int deltaTime, int type, int data1, int data2)
|
|
{
|
|
m_type = type;
|
|
m_deltaTime = deltaTime;
|
|
m_channel = 0;
|
|
m_note = data1;
|
|
m_velocity = data2;
|
|
}
|
|
|
|
// Raw data is used for used for a SYSTEM_EVENT
|
|
void collateRawByte( int deltaTime, int nextByte)
|
|
{
|
|
m_type = MIDI_PB_collateRawMidiData;
|
|
m_deltaTime = deltaTime;
|
|
m_note = nextByte;
|
|
m_velocity = 0;
|
|
}
|
|
|
|
// Raw data is used for used for a SYSTEM_EVENT
|
|
void outputCollatedRawBytes(int deltaTime)
|
|
{
|
|
m_type = MIDI_PB_outputRawMidiData;
|
|
m_deltaTime = deltaTime;
|
|
m_note = 0;
|
|
m_velocity = 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//@brief set the midi note duration
|
|
void setDuration(int duration) {m_duration = duration;}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//@brief how long the midi note was played for
|
|
int getDuration() const { return m_duration; }
|
|
|
|
/**
|
|
* This merges two MidiEvents (this and the other MidiEvent)
|
|
* The MidiEvent that happens first (has the lowest delta time)
|
|
* then a COPY of that MidiEvent is returned.
|
|
* The original is then cleared so that it type is set to MIDI_NONE
|
|
* The MidiEvent that happens second will have it delta time reduced
|
|
* using the delta time from the first MidiEvent.
|
|
* NOTE Both this and the otherMidiEvent will be altered when call this method.
|
|
*/
|
|
CMidiEvent getNextMergedEvent(CMidiEvent &otherMidiEvent)
|
|
{
|
|
CMidiEvent result;
|
|
int thisDelta = deltaTime();
|
|
int otherDelta = otherMidiEvent.deltaTime();
|
|
if ( thisDelta <= otherDelta ) {
|
|
result = *this;
|
|
otherMidiEvent.subtractDeltaTime(thisDelta);
|
|
clear();
|
|
} else {
|
|
result = otherMidiEvent;
|
|
subtractDeltaTime(otherDelta);
|
|
otherMidiEvent.clear();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string event_type_str(int atype)
|
|
{
|
|
std::string r;
|
|
switch (atype) {
|
|
case MIDI_NOTE_OFF: r = "MIDI_NOTE_OFF";break;
|
|
case MIDI_NOTE_ON: r = "MIDI_NOTE_ON";break;
|
|
case MIDI_NOTE_PRESSURE: r = "MIDI_NOTE_PRESSURE";break;
|
|
case MIDI_CONTROL_CHANGE: r = "MIDI_CONTROL_CHANGE";break;
|
|
case MIDI_PROGRAM_CHANGE: r = "MIDI_PROGRAM_CHANGE";break;
|
|
case MIDI_CHANNEL_PRESSURE: r = "MIDI_CHANNEL_PRESSURE";break;
|
|
case MIDI_PITCH_BEND: r = "MIDI_PITCH_BEND";break;
|
|
case MIDI_SYSTEM_EVENT: r = "MIDI_SYSTEM_EVENT";break;
|
|
case MIDI_SUSTAIN: r = "MIDI_SUSTAIN";break;
|
|
case MIDI_MAIN_VOLUME: r = "MIDI_MAIN_VOLUME";break;
|
|
case MIDI_RESET_ALL_CONTROLLERS:r = "MIDI_RESET_ALL_CONTROLLERS";break;
|
|
case MIDI_ALL_SOUND_OFF: r = "MIDI_ALL_SOUND_OFF";break;
|
|
case MIDI_ALL_NOTES_OFF: r = "MIDI_ALL_NOTES_OFF";break;
|
|
|
|
case MIDI_NONE: r = "MIDI_NONE";break;
|
|
case MIDI_ERROR: r = "MIDI_ERROR";break;
|
|
case MIDI_PB_EOF: r = "MIDI_PB_EOF";break;
|
|
case MIDI_PB_chordSeparator: r = "MIDI_PB_chordSeparator";break;
|
|
case MIDI_PB_tempo: r = "MIDI_PB_tempo";break;
|
|
case MIDI_PB_timeSignature: r = "MIDI_PB_timeSignature";break;
|
|
case MIDI_PB_keySignature: r = "MIDI_PB_keySignature";break;
|
|
case MIDI_PB_collateRawMidiData:r = "MIDI_PB_collateRawMidiData";break;
|
|
case MIDI_PB_outputRawMidiData: r = "MIDI_PB_outputRawMidiData";break;
|
|
|
|
// case MIDI_SYSEXEVENT: r = "MIDI_SYSEXEVENT";break;
|
|
case METAEVENT: r = "METAEVENT";break;
|
|
case METASEQN: r = "METASEQN";break;
|
|
case METATEXT: r = "METATEXT";break;
|
|
case METACOPYR: r = "METACOPYR";break;
|
|
case METATNAME: r = "METATNAME";break;
|
|
case METAINAME: r = "METAINAME";break;
|
|
case METALYRIC: r = "METALYRIC";break;
|
|
case METAMARKER: r = "METAMARKER";break;
|
|
// case METACUEPT: r = "METACUEPT";break;
|
|
case METACHANPFX: r = "METACHANPFX";break;
|
|
case METAEOT: r = "METAEOT";break;
|
|
case METATEMPO: r = "METATEMPO";break;
|
|
case METASMPTEOFF: r = "METASMPTEOFF";break;
|
|
case METATIMESIG: r = "METATIMESIG";break;
|
|
case METAKEYSIG: r = "METAKEYSIG";break;
|
|
case METASEQEVENT: r = "METASEQEVENT";break;
|
|
|
|
default:
|
|
{
|
|
char s[16];
|
|
sprintf(s, "%2x", atype);
|
|
r = s;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void printDetails()
|
|
{
|
|
if (type() == MIDI_NOTE_ON) {
|
|
ppTiming("chan %2d NOTE ON note %3d vel %3d", channel(), note(), velocity() );
|
|
}
|
|
else if (type() == MIDI_NOTE_OFF) {
|
|
ppTiming("chan %2d NOTE OFF note %3d vel %3d", channel(), note(), velocity() );
|
|
}
|
|
else {
|
|
ppTiming("chan %2d type %-20s note %3d velocity %3d deltaTime %3d",
|
|
channel(), event_type_str(type()).c_str(), note(), velocity(), deltaTime());
|
|
}
|
|
}
|
|
|
|
private:
|
|
int m_type;
|
|
int m_deltaTime;
|
|
int m_channel;
|
|
int m_note;
|
|
int m_velocity;
|
|
int m_duration;
|
|
int m_track;
|
|
};
|
|
|
|
#endif //__MIDI_EVENT_H__
|