1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Changed MidiMessage to avoid problems when moving them around in memory. Apart from being slightly cleaner code, this means that it can be used in Arrays.

This commit is contained in:
jules 2013-10-31 16:18:24 +00:00
parent 5639d1befd
commit 4d7323fe0d
2 changed files with 117 additions and 142 deletions

View file

@ -39,8 +39,7 @@ namespace MidiHelpers
int MidiMessage::readVariableLengthVal (const uint8* data, int& numBytesUsed) noexcept
{
numBytesUsed = 0;
int v = 0;
int i;
int v = 0, i;
do
{
@ -76,28 +75,9 @@ int MidiMessage::getMessageLengthFromFirstByte (const uint8 firstByte) noexcept
return messageLengths [firstByte & 0x7f];
}
//==============================================================================
inline void MidiMessage::setToUseInternalData() noexcept
{
data = static_cast <uint8*> (preallocatedData.asBytes);
}
inline bool MidiMessage::usesAllocatedData() const noexcept
{
return data != static_cast <const uint8*> (preallocatedData.asBytes);
}
inline void MidiMessage::freeData() noexcept
{
if (usesAllocatedData())
delete[] data;
}
//==============================================================================
MidiMessage::MidiMessage() noexcept
: timeStamp (0),
data (static_cast<uint8*> (preallocatedData.asBytes)),
size (2)
: timeStamp (0), size (2)
{
preallocatedData.asBytes[0] = 0xf0;
preallocatedData.asBytes[1] = 0xf7;
@ -109,21 +89,22 @@ MidiMessage::MidiMessage (const void* const d, const int dataSize, const double
{
jassert (dataSize > 0);
if (dataSize <= 4)
setToUseInternalData();
if (dataSize > 4)
{
allocatedData.malloc (dataSize);
memcpy (allocatedData, d, (size_t) dataSize);
}
else
data = new uint8 [dataSize];
memcpy (data, d, (size_t) dataSize);
{
memcpy (preallocatedData.asBytes, d, (size_t) dataSize);
}
// check that the length matches the data..
jassert (size > 3 || data[0] >= 0xf0 || getMessageLengthFromFirstByte (data[0]) == size);
jassert (size > 3 || *(uint8*)d >= 0xf0 || getMessageLengthFromFirstByte (*(uint8*)d) == size);
}
MidiMessage::MidiMessage (const int byte1, const double t) noexcept
: timeStamp (t),
data (static_cast<uint8*> (preallocatedData.asBytes)),
size (1)
: timeStamp (t), size (1)
{
preallocatedData.asBytes[0] = (uint8) byte1;
@ -132,9 +113,7 @@ MidiMessage::MidiMessage (const int byte1, const double t) noexcept
}
MidiMessage::MidiMessage (const int byte1, const int byte2, const double t) noexcept
: timeStamp (t),
data (static_cast<uint8*> (preallocatedData.asBytes)),
size (2)
: timeStamp (t), size (2)
{
preallocatedData.asBytes[0] = (uint8) byte1;
preallocatedData.asBytes[1] = (uint8) byte2;
@ -144,9 +123,7 @@ MidiMessage::MidiMessage (const int byte1, const int byte2, const double t) noex
}
MidiMessage::MidiMessage (const int byte1, const int byte2, const int byte3, const double t) noexcept
: timeStamp (t),
data (static_cast<uint8*> (preallocatedData.asBytes)),
size (3)
: timeStamp (t), size (3)
{
preallocatedData.asBytes[0] = (uint8) byte1;
preallocatedData.asBytes[1] = (uint8) byte2;
@ -157,42 +134,37 @@ MidiMessage::MidiMessage (const int byte1, const int byte2, const int byte3, con
}
MidiMessage::MidiMessage (const MidiMessage& other)
: timeStamp (other.timeStamp),
size (other.size)
: timeStamp (other.timeStamp), size (other.size)
{
if (other.usesAllocatedData())
if (size > 4)
{
data = new uint8 [size];
memcpy (data, other.data, (size_t) size);
allocatedData.malloc (size);
memcpy (allocatedData, other.allocatedData, (size_t) size);
}
else
{
setToUseInternalData();
preallocatedData.asInt32 = other.preallocatedData.asInt32;
}
}
MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp)
: timeStamp (newTimeStamp),
size (other.size)
: timeStamp (newTimeStamp), size (other.size)
{
if (other.usesAllocatedData())
if (size > 4)
{
data = new uint8 [size];
memcpy (data, other.data, (size_t) size);
allocatedData.malloc (size);
memcpy (allocatedData, other.allocatedData, (size_t) size);
}
else
{
setToUseInternalData();
preallocatedData.asInt32 = other.preallocatedData.asInt32;
}
}
MidiMessage::MidiMessage (const void* src_, int sz, int& numBytesUsed, const uint8 lastStatusByte, double t)
: timeStamp (t),
data (static_cast<uint8*> (preallocatedData.asBytes))
MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const uint8 lastStatusByte, double t)
: timeStamp (t)
{
const uint8* src = static_cast <const uint8*> (src_);
const uint8* src = static_cast <const uint8*> (srcData);
unsigned int byte = (unsigned int) *src;
if (byte < 0x80)
@ -242,11 +214,12 @@ MidiMessage::MidiMessage (const void* src_, int sz, int& numBytesUsed, const uin
++d;
}
src += numVariableLengthSysexBytes;
size = 1 + (int) (d - src);
data = new uint8 [size - numVariableLengthSysexBytes];
*data = (uint8) byte;
memcpy (data + 1, src + numVariableLengthSysexBytes, (size_t) (size - numVariableLengthSysexBytes - 1));
allocatedData.malloc (size);
*allocatedData = (uint8) byte;
memcpy (allocatedData + 1, src, (size_t) (size - 1));
}
else if (byte == 0xff)
{
@ -254,22 +227,22 @@ MidiMessage::MidiMessage (const void* src_, int sz, int& numBytesUsed, const uin
const int bytesLeft = readVariableLengthVal (src + 1, n);
size = jmin (sz + 1, n + 2 + bytesLeft);
data = new uint8 [size];
*data = (uint8) byte;
memcpy (data + 1, src, (size_t) size - 1);
allocatedData.malloc (size);
*allocatedData = (uint8) byte;
memcpy (allocatedData + 1, src, (size_t) size - 1);
}
else
{
preallocatedData.asInt32 = 0;
size = getMessageLengthFromFirstByte ((uint8) byte);
data[0] = (uint8) byte;
preallocatedData.asBytes[0] = (uint8) byte;
if (size > 1)
{
data[1] = src[0];
preallocatedData.asBytes[1] = src[0];
if (size > 2)
data[2] = src[1];
preallocatedData.asBytes[2] = src[1];
}
}
@ -289,16 +262,14 @@ MidiMessage& MidiMessage::operator= (const MidiMessage& other)
timeStamp = other.timeStamp;
size = other.size;
freeData();
if (other.usesAllocatedData())
if (size > 4)
{
data = new uint8 [size];
memcpy (data, other.data, (size_t) size);
allocatedData.malloc (size);
memcpy (allocatedData, other.allocatedData, (size_t) size);
}
else
{
setToUseInternalData();
allocatedData.free();
preallocatedData.asInt32 = other.preallocatedData.asInt32;
}
}
@ -308,19 +279,12 @@ MidiMessage& MidiMessage::operator= (const MidiMessage& other)
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
MidiMessage::MidiMessage (MidiMessage&& other) noexcept
: timeStamp (other.timeStamp),
size (other.size)
: timeStamp (other.timeStamp), size (other.size)
{
if (other.usesAllocatedData())
{
data = other.data;
other.setToUseInternalData();
}
if (other.allocatedData != nullptr)
allocatedData.swapWith (other.allocatedData);
else
{
setToUseInternalData();
preallocatedData.asInt32 = other.preallocatedData.asInt32;
}
}
MidiMessage& MidiMessage::operator= (MidiMessage&& other) noexcept
@ -329,31 +293,19 @@ MidiMessage& MidiMessage::operator= (MidiMessage&& other) noexcept
timeStamp = other.timeStamp;
size = other.size;
freeData();
if (other.usesAllocatedData())
{
data = other.data;
other.setToUseInternalData();
}
else
{
setToUseInternalData();
allocatedData.swapWith (other.allocatedData);
preallocatedData.asInt32 = other.preallocatedData.asInt32;
}
return *this;
}
#endif
MidiMessage::~MidiMessage()
{
freeData();
}
MidiMessage::~MidiMessage() {}
int MidiMessage::getChannel() const noexcept
{
const uint8* const data = getRawData();
if ((data[0] & 0xf0) != 0xf0)
return (data[0] & 0xf) + 1;
@ -364,6 +316,8 @@ bool MidiMessage::isForChannel (const int channel) const noexcept
{
jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
const uint8* const data = getRawData();
return ((data[0] & 0xf) == channel - 1)
&& ((data[0] & 0xf0) != 0xf0);
}
@ -372,6 +326,8 @@ void MidiMessage::setChannel (const int channel) noexcept
{
jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
uint8* const data = getData();
if ((data[0] & 0xf0) != (uint8) 0xf0)
data[0] = (uint8) ((data[0] & (uint8) 0xf0)
| (uint8)(channel - 1));
@ -379,37 +335,43 @@ void MidiMessage::setChannel (const int channel) noexcept
bool MidiMessage::isNoteOn (const bool returnTrueForVelocity0) const noexcept
{
const uint8* const data = getRawData();
return ((data[0] & 0xf0) == 0x90)
&& (returnTrueForVelocity0 || data[2] != 0);
}
bool MidiMessage::isNoteOff (const bool returnTrueForNoteOnVelocity0) const noexcept
{
const uint8* const data = getRawData();
return ((data[0] & 0xf0) == 0x80)
|| (returnTrueForNoteOnVelocity0 && (data[2] == 0) && ((data[0] & 0xf0) == 0x90));
}
bool MidiMessage::isNoteOnOrOff() const noexcept
{
const uint8* const data = getRawData();
const int d = data[0] & 0xf0;
return (d == 0x90) || (d == 0x80);
}
int MidiMessage::getNoteNumber() const noexcept
{
return data[1];
return getRawData()[1];
}
void MidiMessage::setNoteNumber (const int newNoteNumber) noexcept
{
if (isNoteOnOrOff())
data[1] = (uint8) (newNoteNumber & 127);
getData()[1] = (uint8) (newNoteNumber & 127);
}
uint8 MidiMessage::getVelocity() const noexcept
{
if (isNoteOnOrOff())
return data[2];
return getRawData()[2];
return 0;
}
@ -422,24 +384,27 @@ float MidiMessage::getFloatVelocity() const noexcept
void MidiMessage::setVelocity (const float newVelocity) noexcept
{
if (isNoteOnOrOff())
data[2] = MidiHelpers::validVelocity (roundToInt (newVelocity * 127.0f));
getData()[2] = MidiHelpers::validVelocity (roundToInt (newVelocity * 127.0f));
}
void MidiMessage::multiplyVelocity (const float scaleFactor) noexcept
{
if (isNoteOnOrOff())
{
uint8* const data = getData();
data[2] = MidiHelpers::validVelocity (roundToInt (scaleFactor * data[2]));
}
}
bool MidiMessage::isAftertouch() const noexcept
{
return (data[0] & 0xf0) == 0xa0;
return (getRawData()[0] & 0xf0) == 0xa0;
}
int MidiMessage::getAfterTouchValue() const noexcept
{
jassert (isAftertouch());
return data[2];
return getRawData()[2];
}
MidiMessage MidiMessage::aftertouchChange (const int channel,
@ -457,13 +422,13 @@ MidiMessage MidiMessage::aftertouchChange (const int channel,
bool MidiMessage::isChannelPressure() const noexcept
{
return (data[0] & 0xf0) == 0xd0;
return (getRawData()[0] & 0xf0) == 0xd0;
}
int MidiMessage::getChannelPressureValue() const noexcept
{
jassert (isChannelPressure());
return data[1];
return getRawData()[1];
}
MidiMessage MidiMessage::channelPressureChange (const int channel, const int pressure) noexcept
@ -474,25 +439,25 @@ MidiMessage MidiMessage::channelPressureChange (const int channel, const int pre
return MidiMessage (MidiHelpers::initialByte (0xd0, channel), pressure & 0x7f);
}
bool MidiMessage::isSustainPedalOn() const noexcept { return isControllerOfType (0x40) && data[2] >= 64; }
bool MidiMessage::isSustainPedalOff() const noexcept { return isControllerOfType (0x40) && data[2] < 64; }
bool MidiMessage::isSustainPedalOn() const noexcept { return isControllerOfType (0x40) && getRawData()[2] >= 64; }
bool MidiMessage::isSustainPedalOff() const noexcept { return isControllerOfType (0x40) && getRawData()[2] < 64; }
bool MidiMessage::isSostenutoPedalOn() const noexcept { return isControllerOfType (0x42) && data[2] >= 64; }
bool MidiMessage::isSostenutoPedalOff() const noexcept { return isControllerOfType (0x42) && data[2] < 64; }
bool MidiMessage::isSostenutoPedalOn() const noexcept { return isControllerOfType (0x42) && getRawData()[2] >= 64; }
bool MidiMessage::isSostenutoPedalOff() const noexcept { return isControllerOfType (0x42) && getRawData()[2] < 64; }
bool MidiMessage::isSoftPedalOn() const noexcept { return isControllerOfType (0x43) && data[2] >= 64; }
bool MidiMessage::isSoftPedalOff() const noexcept { return isControllerOfType (0x43) && data[2] < 64; }
bool MidiMessage::isSoftPedalOn() const noexcept { return isControllerOfType (0x43) && getRawData()[2] >= 64; }
bool MidiMessage::isSoftPedalOff() const noexcept { return isControllerOfType (0x43) && getRawData()[2] < 64; }
bool MidiMessage::isProgramChange() const noexcept
{
return (data[0] & 0xf0) == 0xc0;
return (getRawData()[0] & 0xf0) == 0xc0;
}
int MidiMessage::getProgramChangeNumber() const noexcept
{
jassert (isProgramChange());
return data[1];
return getRawData()[1];
}
MidiMessage MidiMessage::programChange (const int channel, const int programNumber) noexcept
@ -504,12 +469,13 @@ MidiMessage MidiMessage::programChange (const int channel, const int programNumb
bool MidiMessage::isPitchWheel() const noexcept
{
return (data[0] & 0xf0) == 0xe0;
return (getRawData()[0] & 0xf0) == 0xe0;
}
int MidiMessage::getPitchWheelValue() const noexcept
{
jassert (isPitchWheel());
const uint8* const data = getRawData();
return data[1] | (data[2] << 7);
}
@ -524,24 +490,25 @@ MidiMessage MidiMessage::pitchWheel (const int channel, const int position) noex
bool MidiMessage::isController() const noexcept
{
return (data[0] & 0xf0) == 0xb0;
return (getRawData()[0] & 0xf0) == 0xb0;
}
bool MidiMessage::isControllerOfType (const int controllerType) const noexcept
{
const uint8* const data = getRawData();
return (data[0] & 0xf0) == 0xb0 && data[1] == controllerType;
}
int MidiMessage::getControllerNumber() const noexcept
{
jassert (isController());
return data[1];
return getRawData()[1];
}
int MidiMessage::getControllerValue() const noexcept
{
jassert (isController());
return data[2];
return getRawData()[2];
}
MidiMessage MidiMessage::controllerEvent (const int channel, const int controllerType, const int value) noexcept
@ -583,6 +550,7 @@ MidiMessage MidiMessage::allNotesOff (const int channel) noexcept
bool MidiMessage::isAllNotesOff() const noexcept
{
const uint8* const data = getRawData();
return (data[0] & 0xf0) == 0xb0 && data[1] == 123;
}
@ -593,6 +561,7 @@ MidiMessage MidiMessage::allSoundOff (const int channel) noexcept
bool MidiMessage::isAllSoundOff() const noexcept
{
const uint8* const data = getRawData();
return (data[0] & 0xf0) == 0xb0 && data[1] == 120;
}
@ -616,7 +585,7 @@ MidiMessage MidiMessage::masterVolume (const float volume)
//==============================================================================
bool MidiMessage::isSysEx() const noexcept
{
return *data == 0xf0;
return *getRawData() == 0xf0;
}
MidiMessage MidiMessage::createSysExMessage (const void* sysexData, const int dataSize)
@ -641,16 +610,18 @@ int MidiMessage::getSysExDataSize() const noexcept
}
//==============================================================================
bool MidiMessage::isMetaEvent() const noexcept { return *data == 0xff; }
bool MidiMessage::isActiveSense() const noexcept { return *data == 0xfe; }
bool MidiMessage::isMetaEvent() const noexcept { return *getRawData() == 0xff; }
bool MidiMessage::isActiveSense() const noexcept { return *getRawData() == 0xfe; }
int MidiMessage::getMetaEventType() const noexcept
{
const uint8* const data = getRawData();
return *data != 0xff ? -1 : data[1];
}
int MidiMessage::getMetaEventLength() const noexcept
{
const uint8* const data = getRawData();
if (*data == 0xff)
{
int n;
@ -665,7 +636,7 @@ const uint8* MidiMessage::getMetaEventData() const noexcept
jassert (isMetaEvent());
int n;
const uint8* d = data + 2;
const uint8* d = getRawData() + 2;
readVariableLengthVal (d, n);
return d + n;
}
@ -686,14 +657,14 @@ String MidiMessage::getTextFromTextMetaEvent() const
CharPointer_UTF8 (textData + getMetaEventLength()));
}
bool MidiMessage::isTrackNameEvent() const noexcept { return (data[1] == 3) && (*data == 0xff); }
bool MidiMessage::isTempoMetaEvent() const noexcept { return (data[1] == 81) && (*data == 0xff); }
bool MidiMessage::isMidiChannelMetaEvent() const noexcept { return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); }
bool MidiMessage::isTrackNameEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 3) && (*data == 0xff); }
bool MidiMessage::isTempoMetaEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 81) && (*data == 0xff); }
bool MidiMessage::isMidiChannelMetaEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); }
int MidiMessage::getMidiChannelMetaEventChannel() const noexcept
{
jassert (isMidiChannelMetaEvent());
return data[3] + 1;
return getRawData()[3] + 1;
}
double MidiMessage::getTempoSecondsPerQuarterNote() const noexcept
@ -748,6 +719,7 @@ MidiMessage MidiMessage::tempoMetaEvent (int microsecondsPerQuarterNote) noexcep
bool MidiMessage::isTimeSignatureMetaEvent() const noexcept
{
const uint8* const data = getRawData();
return (data[1] == 0x58) && (*data == (uint8) 0xff);
}
@ -816,8 +788,8 @@ MidiMessage MidiMessage::endOfTrack() noexcept
}
//==============================================================================
bool MidiMessage::isSongPositionPointer() const noexcept { return *data == 0xf2; }
int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { return data[1] | (data[2] << 7); }
bool MidiMessage::isSongPositionPointer() const noexcept { return *getRawData() == 0xf2; }
int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { const uint8* data = getRawData(); return data[1] | (data[2] << 7); }
MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noexcept
{
@ -826,21 +798,21 @@ MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noe
(positionInMidiBeats >> 7) & 127);
}
bool MidiMessage::isMidiStart() const noexcept { return *data == 0xfa; }
bool MidiMessage::isMidiStart() const noexcept { return *getRawData() == 0xfa; }
MidiMessage MidiMessage::midiStart() noexcept { return MidiMessage (0xfa); }
bool MidiMessage::isMidiContinue() const noexcept { return *data == 0xfb; }
bool MidiMessage::isMidiContinue() const noexcept { return *getRawData() == 0xfb; }
MidiMessage MidiMessage::midiContinue() noexcept { return MidiMessage (0xfb); }
bool MidiMessage::isMidiStop() const noexcept { return *data == 0xfc; }
bool MidiMessage::isMidiStop() const noexcept { return *getRawData() == 0xfc; }
MidiMessage MidiMessage::midiStop() noexcept { return MidiMessage (0xfc); }
bool MidiMessage::isMidiClock() const noexcept { return *data == 0xf8; }
bool MidiMessage::isMidiClock() const noexcept { return *getRawData() == 0xf8; }
MidiMessage MidiMessage::midiClock() noexcept { return MidiMessage (0xf8); }
bool MidiMessage::isQuarterFrame() const noexcept { return *data == 0xf1; }
int MidiMessage::getQuarterFrameSequenceNumber() const noexcept { return ((int) data[1]) >> 4; }
int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) data[1]) & 0x0f; }
bool MidiMessage::isQuarterFrame() const noexcept { return *getRawData() == 0xf1; }
int MidiMessage::getQuarterFrameSequenceNumber() const noexcept { return ((int) getRawData()[1]) >> 4; }
int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) getRawData()[1]) & 0x0f; }
MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value) noexcept
{
@ -849,6 +821,8 @@ MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value
bool MidiMessage::isFullFrame() const noexcept
{
const uint8* const data = getRawData();
return data[0] == 0xf0
&& data[1] == 0x7f
&& size >= 10
@ -861,6 +835,7 @@ void MidiMessage::getFullFrameParameters (int& hours, int& minutes, int& seconds
{
jassert (isFullFrame());
const uint8* const data = getRawData();
timecodeType = (SmpteTimecodeType) (data[5] >> 5);
hours = data[5] & 0x1f;
minutes = data[6];
@ -884,6 +859,7 @@ MidiMessage MidiMessage::fullFrame (const int hours, const int minutes,
bool MidiMessage::isMidiMachineControlMessage() const noexcept
{
const uint8* const data = getRawData();
return data[0] == 0xf0
&& data[1] == 0x7f
&& data[3] == 0x06
@ -894,7 +870,7 @@ MidiMessage::MidiMachineControlCommand MidiMessage::getMidiMachineControlCommand
{
jassert (isMidiMachineControlMessage());
return (MidiMachineControlCommand) data[4];
return (MidiMachineControlCommand) getRawData()[4];
}
MidiMessage MidiMessage::midiMachineControlCommand (MidiMessage::MidiMachineControlCommand command)
@ -907,6 +883,7 @@ MidiMessage MidiMessage::midiMachineControlCommand (MidiMessage::MidiMachineCont
//==============================================================================
bool MidiMessage::isMidiMachineControlGoto (int& hours, int& minutes, int& seconds, int& frames) const noexcept
{
const uint8* const data = getRawData();
if (size >= 12
&& data[0] == 0xf0
&& data[1] == 0x7f

View file

@ -114,7 +114,7 @@ public:
/** Returns a pointer to the raw midi data.
@see getRawDataSize
*/
const uint8* getRawData() const noexcept { return data; }
const uint8* getRawData() const noexcept { return allocatedData != nullptr ? allocatedData : preallocatedData.asBytes; }
/** Returns the number of bytes of data in the message.
@see getRawData
@ -914,7 +914,7 @@ public:
private:
//==============================================================================
double timeStamp;
uint8* data;
HeapBlock<uint8> allocatedData;
int size;
#ifndef DOXYGEN
@ -925,9 +925,7 @@ private:
} preallocatedData;
#endif
void freeData() noexcept;
void setToUseInternalData() noexcept;
bool usesAllocatedData() const noexcept;
inline uint8* getData() noexcept { return allocatedData != nullptr ? allocatedData : preallocatedData.asBytes; }
};
#endif // JUCE_MIDIMESSAGE_H_INCLUDED