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.
318 lines
7.6 KiB
318 lines
7.6 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 "MidiTypes.h"
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
static MidiByte getByte(const Event &e, const PropertyName &name) {
|
|
long value = -1;
|
|
try {
|
|
value = e.get<Int>(name);
|
|
} catch (...) { }
|
|
if (value < 0 || value > 255) throw MIDIValueOutOfRange(name.getName());
|
|
return MidiByte(value);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// PitchBend
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
const std::string PitchBend::EventType = "pitchbend";
|
|
const int PitchBend::EventSubOrdering = -5;
|
|
|
|
const PropertyName PitchBend::MSB = "msb";
|
|
const PropertyName PitchBend::LSB = "lsb";
|
|
|
|
PitchBend::PitchBend(Rosegarden::MidiByte msb,
|
|
Rosegarden::MidiByte lsb) :
|
|
m_msb(msb),
|
|
m_lsb(lsb)
|
|
{
|
|
}
|
|
|
|
PitchBend::PitchBend(const Event &e)
|
|
{
|
|
if (e.getType() != EventType) {
|
|
throw Event::BadType("PitchBend model event", EventType, e.getType());
|
|
}
|
|
m_msb = getByte(e, MSB);
|
|
m_lsb = getByte(e, LSB);
|
|
}
|
|
|
|
PitchBend::~PitchBend()
|
|
{
|
|
}
|
|
|
|
Event*
|
|
PitchBend::getAsEvent(timeT absoluteTime) const
|
|
{
|
|
Event *e = new Event(EventType, absoluteTime, 0, EventSubOrdering);
|
|
e->set<Int>(MSB, (long)m_msb);
|
|
e->set<Int>(LSB, (long)m_lsb);
|
|
return e;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Controller
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
const std::string Controller::EventType = "controller";
|
|
const int Controller::EventSubOrdering = -5;
|
|
|
|
const PropertyName Controller::NUMBER = "number";
|
|
const PropertyName Controller::VALUE = "value";
|
|
|
|
Controller::Controller(Rosegarden::MidiByte number,
|
|
Rosegarden::MidiByte value):
|
|
m_number(number),
|
|
m_value(value)
|
|
{
|
|
}
|
|
|
|
Controller::Controller(const Event &e)
|
|
{
|
|
if (e.getType() != EventType) {
|
|
throw Event::BadType("Controller model event", EventType, e.getType());
|
|
}
|
|
m_number = getByte(e, NUMBER);
|
|
m_value = getByte(e, VALUE);
|
|
}
|
|
|
|
Controller::~Controller()
|
|
{
|
|
}
|
|
|
|
Event*
|
|
Controller::getAsEvent(timeT absoluteTime) const
|
|
{
|
|
Event *e = new Event(EventType, absoluteTime, 0, EventSubOrdering);
|
|
e->set<Int>(NUMBER, (long)m_number);
|
|
e->set<Int>(VALUE, (long)m_value);
|
|
return e;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Key Pressure
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
const std::string KeyPressure::EventType = "keypressure";
|
|
const int KeyPressure::EventSubOrdering = -5;
|
|
|
|
const PropertyName KeyPressure::PITCH = "pitch";
|
|
const PropertyName KeyPressure::PRESSURE = "pressure";
|
|
|
|
KeyPressure::KeyPressure(Rosegarden::MidiByte pitch,
|
|
Rosegarden::MidiByte pressure):
|
|
m_pitch(pitch),
|
|
m_pressure(pressure)
|
|
{
|
|
}
|
|
|
|
KeyPressure::KeyPressure(const Event &e)
|
|
{
|
|
if (e.getType() != EventType) {
|
|
throw Event::BadType("KeyPressure model event", EventType, e.getType());
|
|
}
|
|
m_pitch = getByte(e, PITCH);
|
|
m_pressure = getByte(e, PRESSURE);
|
|
}
|
|
|
|
KeyPressure::~KeyPressure()
|
|
{
|
|
}
|
|
|
|
Event*
|
|
KeyPressure::getAsEvent(timeT absoluteTime) const
|
|
{
|
|
Event *e = new Event(EventType, absoluteTime, 0, EventSubOrdering);
|
|
e->set<Int>(PITCH, (long)m_pitch);
|
|
e->set<Int>(PRESSURE, (long)m_pressure);
|
|
return e;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Channel Pressure
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
const std::string ChannelPressure::EventType = "channelpressure";
|
|
const int ChannelPressure::EventSubOrdering = -5;
|
|
|
|
const PropertyName ChannelPressure::PRESSURE = "pressure";
|
|
|
|
ChannelPressure::ChannelPressure(Rosegarden::MidiByte pressure):
|
|
m_pressure(pressure)
|
|
{
|
|
}
|
|
|
|
ChannelPressure::ChannelPressure(const Event &e)
|
|
{
|
|
if (e.getType() != EventType) {
|
|
throw Event::BadType("ChannelPressure model event", EventType, e.getType());
|
|
}
|
|
m_pressure = getByte(e, PRESSURE);
|
|
}
|
|
|
|
ChannelPressure::~ChannelPressure()
|
|
{
|
|
}
|
|
|
|
Event*
|
|
ChannelPressure::getAsEvent(timeT absoluteTime) const
|
|
{
|
|
Event *e = new Event(EventType, absoluteTime, 0, EventSubOrdering);
|
|
e->set<Int>(PRESSURE, (long)m_pressure);
|
|
return e;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// ProgramChange
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
const std::string ProgramChange::EventType = "programchange";
|
|
const int ProgramChange::EventSubOrdering = -5;
|
|
|
|
const PropertyName ProgramChange::PROGRAM = "program";
|
|
|
|
ProgramChange::ProgramChange(Rosegarden::MidiByte program):
|
|
m_program(program)
|
|
{
|
|
}
|
|
|
|
ProgramChange::ProgramChange(const Event &e)
|
|
{
|
|
if (e.getType() != EventType) {
|
|
throw Event::BadType("ProgramChange model event", EventType, e.getType());
|
|
}
|
|
m_program = getByte(e, PROGRAM);
|
|
}
|
|
|
|
ProgramChange::~ProgramChange()
|
|
{
|
|
}
|
|
|
|
Event*
|
|
ProgramChange::getAsEvent(timeT absoluteTime) const
|
|
{
|
|
Event *e = new Event(EventType, absoluteTime, 0, EventSubOrdering);
|
|
e->set<Int>(PROGRAM, (long)m_program);
|
|
return e;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// SystemExclusive
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
const std::string SystemExclusive::EventType = "systemexclusive";
|
|
const int SystemExclusive::EventSubOrdering = -5;
|
|
|
|
const PropertyName SystemExclusive::DATABLOCK = "datablock";
|
|
|
|
SystemExclusive::SystemExclusive(std::string rawData) :
|
|
m_rawData(rawData)
|
|
{
|
|
}
|
|
|
|
SystemExclusive::SystemExclusive(const Event &e)
|
|
{
|
|
if (e.getType() != EventType) {
|
|
throw Event::BadType("SystemExclusive model event", EventType, e.getType());
|
|
}
|
|
std::string datablock;
|
|
e.get<String>(DATABLOCK, datablock);
|
|
m_rawData = toRaw(datablock);
|
|
}
|
|
|
|
SystemExclusive::~SystemExclusive()
|
|
{
|
|
}
|
|
|
|
Event*
|
|
SystemExclusive::getAsEvent(timeT absoluteTime) const
|
|
{
|
|
Event *e = new Event(EventType, absoluteTime, 0, EventSubOrdering);
|
|
std::string hex(toHex(m_rawData));
|
|
e->set<String>(DATABLOCK, hex);
|
|
return e;
|
|
}
|
|
|
|
std::string
|
|
SystemExclusive::toHex(std::string r)
|
|
{
|
|
static char hexchars[] = "0123456789ABCDEF";
|
|
std::string h;
|
|
for (unsigned int i = 0; i < r.size(); ++i) {
|
|
if (i > 0) h += ' ';
|
|
unsigned char b = (unsigned char)r[i];
|
|
h += hexchars[(b / 16) % 16];
|
|
h += hexchars[b % 16];
|
|
}
|
|
return h;
|
|
}
|
|
|
|
std::string
|
|
SystemExclusive::toRaw(std::string rh)
|
|
{
|
|
std::string r;
|
|
std::string h;
|
|
|
|
// remove whitespace
|
|
for (unsigned int i = 0; i < rh.size(); ++i) {
|
|
if (!isspace(rh[i])) h += rh[i];
|
|
}
|
|
|
|
for (unsigned int i = 0; i < h.size()/2; ++i) {
|
|
unsigned char b = toRawNibble(h[2*i]) * 16 + toRawNibble(h[2*i+1]);
|
|
r += b;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
unsigned char
|
|
SystemExclusive::toRawNibble(char c)
|
|
{
|
|
if (islower(c)) c = toupper(c);
|
|
if (isdigit(c)) return c - '0';
|
|
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
|
throw BadEncoding();
|
|
}
|
|
|
|
bool
|
|
SystemExclusive::isHex(std::string rh)
|
|
{
|
|
// arf
|
|
try {
|
|
std::string r = toRaw(rh);
|
|
} catch (BadEncoding) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
}
|
|
|