#include #include #include "Message.h" namespace midi { Message* Message::parse(std::vector &messageBytes) { // msg[0] has 8 bits // - 4 higher significant bits: message type // - 4 lower significant bits: channel (0 - 15) unsigned char messageType = messageBytes[0] >> 4; if(messageType == 0xF) { // system message throw "Message::parseMessage() does not support system messages yet."; } else { // channel message ChannelMessage::Channel channel = messageBytes[0] & 0xF; switch(messageType) { case NoteOnMessage::messageType: case NoteOffMessage::messageType: { unsigned char pitch = messageBytes[1]; unsigned char velocity = messageBytes[2]; if(messageType == NoteOffMessage::messageType || velocity == 0) { return new NoteOffMessage(channel, pitch, velocity); } else { return new NoteOnMessage(channel, pitch, velocity); } } case ControlChangeMessage::messageType: return new ControlChangeMessage(channel, messageBytes[1], messageBytes[2]); case ProgramChangeMessage::messageType: return new ProgramChangeMessage(channel, messageBytes[1]); case PitchBendChangeMessage::messageType: // messageBytes[1] are the least significant 7 bits. // messageBytes[2] are the most significant 7 bits. return new PitchBendChangeMessage( channel, (messageBytes[2] << 7) + messageBytes[1] ); default: throw "Message::parseMessage() does not support the given type of channel message yet."; } } } bool Message::operator==(const Message& message) const { return getBytes() == message.getBytes(); } std::vector NoteOnMessage::getBytes() const { std::vector bytes(3); bytes[0] = messageType << 4 | channel; bytes[1] = pitch; bytes[2] = velocity; return bytes; } std::vector NoteOffMessage::getBytes() const { std::vector bytes(3); bytes[0] = messageType << 4 | channel; bytes[1] = pitch; bytes[2] = velocity; return bytes; } std::vector ControlChangeMessage::getBytes() const { std::vector bytes(3); bytes[0] = messageType << 4 | channel; bytes[1] = control; bytes[2] = value; return bytes; } std::vector ProgramChangeMessage::getBytes() const { std::vector bytes(2); bytes[0] = messageType << 4 | channel; bytes[1] = program; return bytes; } std::vector PitchBendChangeMessage::getBytes() const { std::vector bytes(3); bytes[0] = messageType << 4 | channel; // bytes[1] are the seven least significant bits. // bytes[2] are the seven most significant bits. bytes[1] = value & ((1 << 7) - 1); bytes[2] = value >> 7; return bytes; } std::ostream& operator<<(std::ostream& stream, const Message& message) { message.print(stream); return stream; } void NoteOnMessage::print(std::ostream& stream) const { stream << "channel #" << (unsigned short)(channel + 1) << ": " << "note " << (unsigned short)pitch << " with velocity " << (unsigned short)velocity << " on\n"; } void NoteOffMessage::print(std::ostream& stream) const { stream << "channel #" << (unsigned short)(channel + 1) << ": " << "note " << (unsigned short)pitch << " off\n"; } void ControlChangeMessage::print(std::ostream& stream) const { stream << "channel #" << (unsigned short)(channel + 1) << ": " << "change value of control #" << (unsigned short)(control + 1) << " to " << (unsigned short)value << "\n"; } void ProgramChangeMessage::print(std::ostream& stream) const { stream << "channel #" << (unsigned short)(channel + 1) << ": " << "switch to program # " << (unsigned short)(program + 1) << "\n"; } void PitchBendChangeMessage::print(std::ostream& stream) const { stream << "channel #" << (unsigned short)(channel + 1) << ": " << "pitch bended to " << value << "\n"; } } // namespace