You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
7.5 KiB
289 lines
7.5 KiB
/*
|
|
Rosegarden
|
|
A sequencer and musical notation editor.
|
|
|
|
This program is Copyright 2000-2008
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <bownie@bownie.com>
|
|
|
|
The moral right of the authors to claim authorship of this work
|
|
has been asserted.
|
|
|
|
This program 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 2 of the
|
|
License, or (at your option) any later version. See the file
|
|
COPYING included with this distribution for more information.
|
|
*/
|
|
|
|
#include "Midi.h"
|
|
#include "MidiEvent.h"
|
|
#include <iostream>
|
|
|
|
// MidiEvent is a representation of MIDI which we use
|
|
// for the import/export of MidiFiles. It uses std::strings for
|
|
// meta event messages which makes them nice and easy to handle.
|
|
//
|
|
//
|
|
namespace Rosegarden
|
|
{
|
|
|
|
using std::string;
|
|
using std::cout;
|
|
using std::endl;
|
|
|
|
MidiEvent::MidiEvent()
|
|
{}
|
|
|
|
MidiEvent::MidiEvent(timeT deltaTime,
|
|
MidiByte eventCode):
|
|
m_deltaTime(deltaTime),
|
|
m_duration(0),
|
|
m_eventCode(eventCode),
|
|
m_data1(0),
|
|
m_data2(0),
|
|
m_metaEventCode(0),
|
|
m_metaMessage("")
|
|
{}
|
|
|
|
MidiEvent::MidiEvent(timeT deltaTime,
|
|
MidiByte eventCode,
|
|
MidiByte data1):
|
|
m_deltaTime(deltaTime),
|
|
m_duration(0),
|
|
m_eventCode(eventCode),
|
|
m_data1(data1),
|
|
m_data2(0),
|
|
m_metaEventCode(0),
|
|
m_metaMessage("")
|
|
{}
|
|
|
|
MidiEvent::MidiEvent(timeT deltaTime,
|
|
MidiByte eventCode,
|
|
MidiByte data1,
|
|
MidiByte data2):
|
|
m_deltaTime(deltaTime),
|
|
m_duration(0),
|
|
m_eventCode(eventCode),
|
|
m_data1(data1),
|
|
m_data2(data2),
|
|
m_metaEventCode(0),
|
|
m_metaMessage("")
|
|
|
|
{}
|
|
|
|
MidiEvent::MidiEvent(timeT deltaTime,
|
|
MidiByte eventCode,
|
|
MidiByte metaEventCode,
|
|
const string &metaMessage):
|
|
m_deltaTime(deltaTime),
|
|
m_duration(0),
|
|
m_eventCode(eventCode),
|
|
m_data1(0),
|
|
m_data2(0),
|
|
m_metaEventCode(metaEventCode),
|
|
m_metaMessage(metaMessage)
|
|
{}
|
|
|
|
MidiEvent::MidiEvent(timeT deltaTime,
|
|
MidiByte eventCode,
|
|
const string &sysEx):
|
|
m_deltaTime(deltaTime),
|
|
m_duration(0),
|
|
m_eventCode(eventCode),
|
|
m_data1(0),
|
|
m_data2(0),
|
|
m_metaEventCode(0),
|
|
m_metaMessage(sysEx)
|
|
{}
|
|
|
|
MidiEvent::~MidiEvent()
|
|
{}
|
|
|
|
// Show a representation of our MidiEvent purely for information
|
|
// purposes (also demos how we decode them)
|
|
//
|
|
//
|
|
void
|
|
MidiEvent::print()
|
|
{
|
|
timeT tempo;
|
|
int tonality;
|
|
string sharpflat;
|
|
|
|
if (m_metaEventCode) {
|
|
switch (m_metaEventCode) {
|
|
case MIDI_SEQUENCE_NUMBER:
|
|
cout << "MIDI SEQUENCE NUMBER" << endl;
|
|
break;
|
|
|
|
case MIDI_TEXT_EVENT:
|
|
cout << "MIDI TEXT:\t\"" << m_metaMessage << "\"" << endl;
|
|
break;
|
|
|
|
case MIDI_COPYRIGHT_NOTICE:
|
|
cout << "COPYRIGHT:\t\"" << m_metaMessage << "\"" << endl;
|
|
|
|
case MIDI_TRACK_NAME:
|
|
cout << "TRACK NAME:\t\"" << m_metaMessage << "\"" << endl;
|
|
break;
|
|
|
|
case MIDI_INSTRUMENT_NAME:
|
|
cout << "INSTRUMENT NAME:\t\"" << m_metaMessage << "\"" << endl;
|
|
break;
|
|
|
|
case MIDI_LYRIC:
|
|
cout << "LYRIC:\t\"" << m_metaMessage << "\"" << endl;
|
|
break;
|
|
|
|
case MIDI_TEXT_MARKER:
|
|
cout << "MARKER:\t\"" << m_metaMessage << "\"" << endl;
|
|
break;
|
|
|
|
case MIDI_CUE_POINT:
|
|
cout << "CUE POINT:\t\"" << m_metaMessage << "\"" << endl;
|
|
break;
|
|
|
|
// Sets a Channel number for a TRACK before it starts
|
|
case MIDI_CHANNEL_PREFIX:
|
|
cout << "CHANNEL PREFIX:\t"
|
|
<< (timeT)m_metaMessage[0]
|
|
<< endl;
|
|
break;
|
|
|
|
// These are actually the same case but this is not an
|
|
// official META event - it just crops up a lot. We
|
|
// assume it's a MIDI_CHANNEL_PREFIX though
|
|
//
|
|
case MIDI_CHANNEL_PREFIX_OR_PORT:
|
|
cout << "FIXED CHANNEL PREFIX:\t"
|
|
<< (timeT)m_metaMessage[0] << endl;
|
|
break;
|
|
|
|
case MIDI_END_OF_TRACK:
|
|
cout << "END OF TRACK" << endl;
|
|
break;
|
|
|
|
case MIDI_SET_TEMPO:
|
|
tempo =
|
|
((timeT)(((MidiByte)m_metaMessage[0]) << 16)) +
|
|
((timeT)(((MidiByte)m_metaMessage[1]) << 8)) +
|
|
(short)(MidiByte)m_metaMessage[2];
|
|
|
|
tempo = 60000000 / tempo;
|
|
cout << "SET TEMPO:\t" << tempo << endl;
|
|
break;
|
|
|
|
case MIDI_SMPTE_OFFSET:
|
|
cout << "SMPTE TIME CODE:\t"
|
|
<< (timeT)m_metaMessage[0]
|
|
<< ":" << (timeT)m_metaMessage[1]
|
|
<< ":" << (timeT)m_metaMessage[2]
|
|
<< " - fps = " << (timeT)m_metaMessage[3]
|
|
<< " - subdivsperframe = "
|
|
<< (timeT)m_metaMessage[4]
|
|
<< endl;
|
|
break;
|
|
|
|
case MIDI_TIME_SIGNATURE:
|
|
cout << "TIME SIGNATURE:\t"
|
|
<< (timeT)m_metaMessage[0]
|
|
<< "/"
|
|
<< (1 << (timeT)m_metaMessage[1]) << endl;
|
|
break;
|
|
|
|
case MIDI_KEY_SIGNATURE:
|
|
tonality = (int)m_metaMessage[0];
|
|
|
|
if (tonality < 0) {
|
|
sharpflat = -tonality + " flat";
|
|
} else {
|
|
sharpflat = tonality;
|
|
sharpflat += " sharp";
|
|
}
|
|
|
|
cout << "KEY SIGNATURE:\t" << sharpflat << " "
|
|
<< (((int)m_metaMessage[1]) == 0 ? "major" : "minor")
|
|
<< endl;
|
|
|
|
break;
|
|
|
|
case MIDI_SEQUENCER_SPECIFIC:
|
|
cout << "SEQUENCER SPECIFIC:\t\"" << m_metaMessage << endl;
|
|
break;
|
|
|
|
|
|
default:
|
|
cout << "Undefined MIDI META event - "
|
|
<< (timeT)m_metaEventCode << endl;
|
|
break;
|
|
}
|
|
} else {
|
|
switch (m_eventCode & MIDI_MESSAGE_TYPE_MASK) {
|
|
case MIDI_NOTE_ON:
|
|
cout << "NOTE ON:\t" << (int)m_data1 << " - "
|
|
<< (int)m_data2 << endl;
|
|
break;
|
|
|
|
case MIDI_NOTE_OFF:
|
|
cout << "NOTE OFF:\t" << (int)m_data1 << " - "
|
|
<< (int)m_data2 << endl;
|
|
break;
|
|
|
|
case MIDI_POLY_AFTERTOUCH:
|
|
cout << "POLY AFTERTOUCH:\t" << (int)m_data1
|
|
<< " - " << (int)m_data2 << endl;
|
|
break;
|
|
|
|
case MIDI_CTRL_CHANGE:
|
|
cout << "CTRL CHANGE:\t" << (int)m_data1
|
|
<< " - " << (int)m_data2 << endl;
|
|
break;
|
|
|
|
case MIDI_PITCH_BEND:
|
|
cout << "PITCH BEND:\t" << (int)m_data1
|
|
<< " - " << (int)m_data2 << endl;
|
|
break;
|
|
|
|
case MIDI_PROG_CHANGE:
|
|
cout << "PROG CHANGE:\t" << (int)m_data1 << endl;
|
|
break;
|
|
|
|
case MIDI_CHNL_AFTERTOUCH:
|
|
cout << "CHNL AFTERTOUCH\t" << (int)m_data1 << endl;
|
|
break;
|
|
|
|
default:
|
|
cout << "Undefined MIDI event" << endl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
return ;
|
|
}
|
|
|
|
// Adds the argument to _deltaTime and returns the result
|
|
// thus aggregating the times as we go aint
|
|
timeT
|
|
MidiEvent::addTime(const timeT &time)
|
|
{
|
|
m_deltaTime += time;
|
|
return m_deltaTime;
|
|
}
|
|
|
|
|
|
// Compare based on time
|
|
//
|
|
bool
|
|
operator<(const MidiEvent &a, const MidiEvent &b)
|
|
{
|
|
return a.getTime() < b.getTime();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|