Browse Source

Cleanup

Signed-off-by: falkTX <falktx@falktx.com>
tags/v2.5.0
falkTX 3 years ago
parent
commit
c1ade7b329
7 changed files with 10 additions and 508 deletions
  1. +1
    -104
      source/modules/water/midi/MidiFile.cpp
  2. +2
    -14
      source/modules/water/midi/MidiFile.h
  3. +1
    -73
      source/modules/water/midi/MidiMessage.cpp
  4. +3
    -54
      source/modules/water/midi/MidiMessage.h
  5. +1
    -156
      source/modules/water/midi/MidiMessageSequence.cpp
  6. +0
    -105
      source/modules/water/midi/MidiMessageSequence.h
  7. +2
    -2
      source/native-plugins/midi-file.cpp

+ 1
- 104
source/modules/water/midi/MidiFile.cpp View File

@@ -3,7 +3,7 @@
This file is part of the Water library.
Copyright (c) 2016 ROLI Ltd.
Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
Copyright (C) 2017-2022 Filipe Coelho <falktx@falktx.com>
Permission is granted to use this software under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license/
@@ -32,27 +32,6 @@ namespace water {
namespace MidiFileHelpers
{
static void writeVariableLengthInt (OutputStream& out, unsigned int v)
{
unsigned int buffer = v & 0x7f;
while ((v >>= 7) != 0)
{
buffer <<= 8;
buffer |= ((v & 0x7f) | 0x80);
}
for (;;)
{
out.writeByte ((char) buffer);
if (buffer & 0x80)
buffer >>= 8;
else
break;
}
}
static bool parseMidiHeader (const uint8* &data, short& timeFormat, short& fileType, short& numberOfTracks) noexcept
{
unsigned int ch = ByteOrder::bigEndianInt (data);
@@ -372,86 +351,4 @@ void MidiFile::convertTimestampTicksToSeconds()
}
}
//==============================================================================
bool MidiFile::writeTo (OutputStream& out, int midiFileType)
{
wassert (midiFileType >= 0 && midiFileType <= 2);
if (! out.writeIntBigEndian ((int) ByteOrder::bigEndianInt ("MThd"))) return false;
if (! out.writeIntBigEndian (6)) return false;
if (! out.writeShortBigEndian ((short) midiFileType)) return false;
if (! out.writeShortBigEndian ((short) tracks.size())) return false;
if (! out.writeShortBigEndian (timeFormat)) return false;
for (size_t i = 0; i < tracks.size(); ++i)
if (! writeTrack (out, i))
return false;
out.flush();
return true;
}
bool MidiFile::writeTrack (OutputStream& mainOut, const int trackNum)
{
MemoryOutputStream out;
const MidiMessageSequence& ms = *tracks.getUnchecked (trackNum);
int lastTick = 0;
uint8 lastStatusByte = 0;
bool endOfTrackEventWritten = false;
for (int i = 0; i < ms.getNumEvents(); ++i)
{
const MidiMessage& mm = ms.getEventPointer(i)->message;
if (mm.isEndOfTrackMetaEvent())
endOfTrackEventWritten = true;
const int tick = roundToInt (mm.getTimeStamp());
const int delta = jmax (0, tick - lastTick);
MidiFileHelpers::writeVariableLengthInt (out, (uint32) delta);
lastTick = tick;
const uint8* data = mm.getRawData();
int dataSize = mm.getRawDataSize();
const uint8 statusByte = data[0];
if (statusByte == lastStatusByte
&& (statusByte & 0xf0) != 0xf0
&& dataSize > 1
&& i > 0)
{
++data;
--dataSize;
}
else if (statusByte == 0xf0) // Write sysex message with length bytes.
{
out.writeByte ((char) statusByte);
++data;
--dataSize;
MidiFileHelpers::writeVariableLengthInt (out, (uint32) dataSize);
}
out.write (data, (size_t) dataSize);
lastStatusByte = statusByte;
}
if (! endOfTrackEventWritten)
{
out.writeByte (0); // (tick delta)
const MidiMessage m (MidiMessage::endOfTrack());
out.write (m.getRawData(), (size_t) m.getRawDataSize());
}
if (! mainOut.writeIntBigEndian ((int) ByteOrder::bigEndianInt ("MTrk"))) return false;
if (! mainOut.writeIntBigEndian ((int) out.getDataSize())) return false;
mainOut << out;
return true;
}
}

+ 2
- 14
source/modules/water/midi/MidiFile.h View File

@@ -3,7 +3,7 @@
This file is part of the Water library.
Copyright (c) 2016 ROLI Ltd.
Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
Copyright (C) 2017-2022 Filipe Coelho <falktx@falktx.com>
Permission is granted to use this software under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license/
@@ -32,15 +32,11 @@ namespace water {
//==============================================================================
/**
Reads/writes standard midi format files.
Reads standard midi format files.
To read a midi file, create a MidiFile object and call its readFrom() method. You
can then get the individual midi tracks from it using the getTrack() method.
To write a file, create a MidiFile object, add some MidiMessageSequence objects
to it using the addTrack() method, and then call its writeTo() method to stream
it out.
@see MidiMessageSequence
*/
class MidiFile
@@ -160,13 +156,6 @@ public:
*/
bool readFrom (InputStream& sourceStream);
/** Writes the midi tracks as a standard midi file.
The midiFileType value is written as the file's format type, which can be 0, 1
or 2 - see the midi file spec for more info about that.
@returns true if the operation succeeded.
*/
bool writeTo (OutputStream& destStream, int midiFileType = 1);
/** Converts the timestamp of all the midi events from midi ticks to seconds.
This will use the midi time format and tempo/time signature info in the
@@ -181,7 +170,6 @@ private:
short timeFormat;
void readNextTrack (const uint8*, int size);
bool writeTrack (OutputStream&, int trackNum);
};
}


+ 1
- 73
source/modules/water/midi/MidiMessage.cpp View File

@@ -3,7 +3,7 @@
This file is part of the Water library.
Copyright (c) 2016 ROLI Ltd.
Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
Copyright (C) 2017-2022 Filipe Coelho <falktx@falktx.com>
Permission is granted to use this software under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license/
@@ -657,54 +657,6 @@ const uint8* MidiMessage::getMetaEventData() const noexcept
return d + n;
}
bool MidiMessage::isTrackMetaEvent() const noexcept { return getMetaEventType() == 0; }
bool MidiMessage::isEndOfTrackMetaEvent() const noexcept { return getMetaEventType() == 47; }
bool MidiMessage::isTextMetaEvent() const noexcept
{
const int t = getMetaEventType();
return t > 0 && t < 16;
}
String MidiMessage::getTextFromTextMetaEvent() const
{
const char* const textData = reinterpret_cast<const char*> (getMetaEventData());
return String (CharPointer_UTF8 (textData),
CharPointer_UTF8 (textData + getMetaEventLength()));
}
MidiMessage MidiMessage::textMetaEvent (int type, StringRef text)
{
wassert (type > 0 && type < 16);
MidiMessage result;
const size_t textSize = text.text.sizeInBytes() - 1;
uint8 header[8];
size_t n = sizeof (header);
header[--n] = (uint8) (textSize & 0x7f);
for (size_t i = textSize; (i >>= 7) != 0;)
header[--n] = (uint8) ((i & 0x7f) | 0x80);
header[--n] = (uint8) type;
header[--n] = 0xff;
const size_t headerLen = sizeof (header) - n;
const int totalSize = (int) (headerLen + textSize);
uint8* const dest = result.allocateSpace (totalSize);
result.size = totalSize;
memcpy (dest, header + n, headerLen);
memcpy (dest + headerLen, text.text.getAddress(), textSize);
return result;
}
bool MidiMessage::isTrackNameEvent() const noexcept { const uint8* data = getData(); return (data[1] == 3) && (*data == 0xff); }
bool MidiMessage::isTempoMetaEvent() const noexcept { const uint8* data = getData(); return (data[1] == 81) && (*data == 0xff); }
bool MidiMessage::isMidiChannelMetaEvent() const noexcept { const uint8* data = getData(); return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); }
@@ -829,11 +781,6 @@ MidiMessage MidiMessage::keySignatureMetaEvent (int numberOfSharpsOrFlats, bool
return MidiMessage (d, 5, 0.0);
}
MidiMessage MidiMessage::endOfTrack() noexcept
{
return MidiMessage (0xff, 0x2f, 0, 0.0);
}
//==============================================================================
bool MidiMessage::isSongPositionPointer() const noexcept { return *getData() == 0xf2; }
int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { const uint8* data = getData(); return data[1] | (data[2] << 7); }
@@ -963,25 +910,6 @@ MidiMessage MidiMessage::midiMachineControlGoto (int hours, int minutes, int sec
}
//==============================================================================
String MidiMessage::getMidiNoteName (int note, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
{
static const char* const sharpNoteNames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
static const char* const flatNoteNames[] = { "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B" };
if (isPositiveAndBelow (note, (int) 128))
{
String s (useSharps ? sharpNoteNames [note % 12]
: flatNoteNames [note % 12]);
if (includeOctaveNumber)
s << (note / 12 + (octaveNumForMiddleC - 5));
return s;
}
return String();
}
double MidiMessage::getMidiNoteInHertz (const int noteNumber, const double frequencyOfA) noexcept
{
return frequencyOfA * pow (2.0, (noteNumber - 69) / 12.0);


+ 3
- 54
source/modules/water/midi/MidiMessage.h View File

@@ -3,7 +3,7 @@
This file is part of the Water library.
Copyright (c) 2016 ROLI Ltd.
Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
Copyright (C) 2017-2022 Filipe Coelho <falktx@falktx.com>
Permission is granted to use this software under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license/
@@ -505,8 +505,7 @@ public:
Meta-events are things like tempo changes, track names, etc.
@see getMetaEventType, isTrackMetaEvent, isEndOfTrackMetaEvent,
isTextMetaEvent, isTrackNameEvent, isTempoMetaEvent, isTimeSignatureMetaEvent,
@see getMetaEventType, isTempoMetaEvent, isTimeSignatureMetaEvent,
isKeySignatureMetaEvent, isMidiChannelMetaEvent
*/
bool isMetaEvent() const noexcept;
@@ -515,8 +514,7 @@ public:
If the message isn't a meta-event, this will return -1.
@see isMetaEvent, isTrackMetaEvent, isEndOfTrackMetaEvent,
isTextMetaEvent, isTrackNameEvent, isTempoMetaEvent, isTimeSignatureMetaEvent,
@see isMetaEvent, isTempoMetaEvent, isTimeSignatureMetaEvent,
isKeySignatureMetaEvent, isMidiChannelMetaEvent
*/
int getMetaEventType() const noexcept;
@@ -531,36 +529,6 @@ public:
*/
int getMetaEventLength() const noexcept;
//==============================================================================
/** Returns true if this is a 'track' meta-event. */
bool isTrackMetaEvent() const noexcept;
/** Returns true if this is an 'end-of-track' meta-event. */
bool isEndOfTrackMetaEvent() const noexcept;
/** Creates an end-of-track meta-event.
@see isEndOfTrackMetaEvent
*/
static MidiMessage endOfTrack() noexcept;
/** Returns true if this is an 'track name' meta-event.
You can use the getTextFromTextMetaEvent() method to get the track's name.
*/
bool isTrackNameEvent() const noexcept;
/** Returns true if this is a 'text' meta-event.
@see getTextFromTextMetaEvent
*/
bool isTextMetaEvent() const noexcept;
/** Returns the text from a text meta-event.
@see isTextMetaEvent
*/
String getTextFromTextMetaEvent() const;
/** Creates a text meta-event. */
static MidiMessage textMetaEvent (int type, StringRef text);
//==============================================================================
/** Returns true if this is a 'tempo' meta-event.
@see getTempoMetaEventTickLength, getTempoSecondsPerQuarterNote
@@ -847,25 +815,6 @@ public:
static int getMessageLengthFromFirstByte (uint8 firstByte) noexcept;
//==============================================================================
/** Returns the name of a midi note number.
E.g "C", "D#", etc.
@param noteNumber the midi note number, 0 to 127
@param useSharps if true, sharpened notes are used, e.g. "C#", otherwise
they'll be flattened, e.g. "Db"
@param includeOctaveNumber if true, the octave number will be appended to the string,
e.g. "C#4"
@param octaveNumForMiddleC if an octave number is being appended, this indicates the
number that will be used for middle C's octave
@see getMidiNoteInHertz
*/
static String getMidiNoteName (int noteNumber,
bool useSharps,
bool includeOctaveNumber,
int octaveNumForMiddleC);
/** Returns the frequency of a midi note number.
The frequencyOfA parameter is an optional frequency for 'A', normally 440-444Hz for concert pitch.


+ 1
- 156
source/modules/water/midi/MidiMessageSequence.cpp View File

@@ -3,7 +3,7 @@
This file is part of the Water library.
Copyright (c) 2016 ROLI Ltd.
Copyright (C) 2017-2019 Filipe Coelho <falktx@falktx.com>
Copyright (C) 2017-2022 Filipe Coelho <falktx@falktx.com>
Permission is granted to use this software under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license/
@@ -68,40 +68,6 @@ MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (cons
return list [index];
}
double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const noexcept
{
if (const MidiEventHolder* const meh = list [index])
if (meh->noteOffObject != nullptr)
return meh->noteOffObject->message.getTimeStamp();
return 0.0;
}
int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const noexcept
{
if (const MidiEventHolder* const meh = list [index])
return list.indexOf (meh->noteOffObject);
return -1;
}
int MidiMessageSequence::getIndexOf (const MidiEventHolder* const event) const noexcept
{
return list.indexOf (event);
}
int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const noexcept
{
const int numEvents = list.size();
int i;
for (i = 0; i < numEvents; ++i)
if (list.getUnchecked(i)->message.getTimeStamp() >= timeStamp)
break;
return i;
}
//==============================================================================
double MidiMessageSequence::getStartTime() const noexcept
{
@@ -139,18 +105,6 @@ MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (const MidiM
return newOne;
}
void MidiMessageSequence::deleteEvent (const int index,
const bool deleteMatchingNoteUp)
{
if (isPositiveAndBelow (index, static_cast<int>(list.size())))
{
if (deleteMatchingNoteUp)
deleteEvent (getIndexOfMatchingKeyUp (index), false);
list.remove (index);
}
}
struct MidiMessageSequenceSorter
{
static int compareElements (const MidiMessageSequence::MidiEventHolder* const first,
@@ -175,28 +129,6 @@ void MidiMessageSequence::addSequence (const MidiMessageSequence& other, double
sort();
}
void MidiMessageSequence::addSequence (const MidiMessageSequence& other,
double timeAdjustment,
double firstAllowableTime,
double endOfAllowableDestTimes)
{
for (int i = 0; i < static_cast<int>(other.list.size()); ++i)
{
const MidiMessage& m = other.list.getUnchecked(i)->message;
const double t = m.getTimeStamp() + timeAdjustment;
if (t >= firstAllowableTime && t < endOfAllowableDestTimes)
{
MidiEventHolder* const newOne = new MidiEventHolder (m);
newOne->message.setTimeStamp (t);
list.add (newOne);
}
}
sort();
}
//==============================================================================
void MidiMessageSequence::sort() noexcept
{
@@ -243,93 +175,6 @@ void MidiMessageSequence::updateMatchedPairs() noexcept
}
}
void MidiMessageSequence::addTimeToMessages (const double delta) noexcept
{
for (int i = static_cast<int>(list.size()); --i >= 0;)
{
MidiMessage& mm = list.getUnchecked(i)->message;
mm.setTimeStamp (mm.getTimeStamp() + delta);
}
}
//==============================================================================
void MidiMessageSequence::extractMidiChannelMessages (const int channelNumberToExtract,
MidiMessageSequence& destSequence,
const bool alsoIncludeMetaEvents) const
{
for (int i = 0; i < static_cast<int>(list.size()); ++i)
{
const MidiMessage& mm = list.getUnchecked(i)->message;
if (mm.isForChannel (channelNumberToExtract) || (alsoIncludeMetaEvents && mm.isMetaEvent()))
destSequence.addEvent (mm);
}
}
void MidiMessageSequence::extractSysExMessages (MidiMessageSequence& destSequence) const
{
for (int i = 0; i < static_cast<int>(list.size()); ++i)
{
const MidiMessage& mm = list.getUnchecked(i)->message;
if (mm.isSysEx())
destSequence.addEvent (mm);
}
}
void MidiMessageSequence::deleteMidiChannelMessages (const int channelNumberToRemove)
{
for (int i = list.size(); --i >= 0;)
if (list.getUnchecked(i)->message.isForChannel (channelNumberToRemove))
list.remove(i);
}
void MidiMessageSequence::deleteSysExMessages()
{
for (int i = list.size(); --i >= 0;)
if (list.getUnchecked(i)->message.isSysEx())
list.remove(i);
}
//==============================================================================
void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumber, const double time, Array<MidiMessage>& dest)
{
bool doneProg = false;
bool donePitchWheel = false;
bool doneControllers[128] = { 0 };
for (int i = list.size(); --i >= 0;)
{
const MidiMessage& mm = list.getUnchecked(i)->message;
if (mm.isForChannel (channelNumber) && mm.getTimeStamp() <= time)
{
if (mm.isProgramChange() && ! doneProg)
{
doneProg = true;
dest.add (MidiMessage (mm, 0.0));
}
else if (mm.isPitchWheel() && ! donePitchWheel)
{
donePitchWheel = true;
dest.add (MidiMessage (mm, 0.0));
}
else if (mm.isController())
{
const int controllerNumber = mm.getControllerNumber();
wassert (isPositiveAndBelow (controllerNumber, 128));
if (! doneControllers[controllerNumber])
{
doneControllers[controllerNumber] = true;
dest.add (MidiMessage (mm, 0.0));
}
}
}
}
}
//==============================================================================
MidiMessageSequence::MidiEventHolder::MidiEventHolder (const MidiMessage& mm)
: message (mm), noteOffObject (nullptr)


+ 0
- 105
source/modules/water/midi/MidiMessageSequence.h View File

@@ -103,27 +103,6 @@ public:
/** Returns a pointer to one of the events. */
MidiEventHolder* getEventPointer (int index) const noexcept;
/** Returns the time of the note-up that matches the note-on at this index.
If the event at this index isn't a note-on, it'll just return 0.
@see MidiMessageSequence::MidiEventHolder::noteOffObject
*/
double getTimeOfMatchingKeyUp (int index) const noexcept;
/** Returns the index of the note-up that matches the note-on at this index.
If the event at this index isn't a note-on, it'll just return -1.
@see MidiMessageSequence::MidiEventHolder::noteOffObject
*/
int getIndexOfMatchingKeyUp (int index) const noexcept;
/** Returns the index of an event. */
int getIndexOf (const MidiEventHolder* event) const noexcept;
/** Returns the index of the first event on or after the given timestamp.
If the time is beyond the end of the sequence, this will return the
number of events.
*/
int getNextIndexAtTime (double timeStamp) const noexcept;
//==============================================================================
/** Returns the timestamp of the first event in the sequence.
@see getEndTime
@@ -156,34 +135,6 @@ public:
MidiEventHolder* addEvent (const MidiMessage& newMessage,
double timeAdjustment = 0);
/** Deletes one of the events in the sequence.
Remember to call updateMatchedPairs() after removing events.
@param index the index of the event to delete
@param deleteMatchingNoteUp whether to also remove the matching note-off
if the event you're removing is a note-on
*/
void deleteEvent (int index, bool deleteMatchingNoteUp);
/** Merges another sequence into this one.
Remember to call updateMatchedPairs() after using this method.
@param other the sequence to add from
@param timeAdjustmentDelta an amount to add to the timestamps of the midi events
as they are read from the other sequence
@param firstAllowableDestTime events will not be added if their time is earlier
than this time. (This is after their time has been adjusted
by the timeAdjustmentDelta)
@param endOfAllowableDestTimes events will not be added if their time is equal to
or greater than this time. (This is after their time has
been adjusted by the timeAdjustmentDelta)
*/
void addSequence (const MidiMessageSequence& other,
double timeAdjustmentDelta,
double firstAllowableDestTime,
double endOfAllowableDestTimes);
/** Merges another sequence into this one.
Remember to call updateMatchedPairs() after using this method.
@@ -209,62 +160,6 @@ public:
*/
void sort() noexcept;
//==============================================================================
/** Copies all the messages for a particular midi channel to another sequence.
@param channelNumberToExtract the midi channel to look for, in the range 1 to 16
@param destSequence the sequence that the chosen events should be copied to
@param alsoIncludeMetaEvents if true, any meta-events (which don't apply to a specific
channel) will also be copied across.
@see extractSysExMessages
*/
void extractMidiChannelMessages (int channelNumberToExtract,
MidiMessageSequence& destSequence,
bool alsoIncludeMetaEvents) const;
/** Copies all midi sys-ex messages to another sequence.
@param destSequence this is the sequence to which any sys-exes in this sequence
will be added
@see extractMidiChannelMessages
*/
void extractSysExMessages (MidiMessageSequence& destSequence) const;
/** Removes any messages in this sequence that have a specific midi channel.
@param channelNumberToRemove the midi channel to look for, in the range 1 to 16
*/
void deleteMidiChannelMessages (int channelNumberToRemove);
/** Removes any sys-ex messages from this sequence. */
void deleteSysExMessages();
/** Adds an offset to the timestamps of all events in the sequence.
@param deltaTime the amount to add to each timestamp.
*/
void addTimeToMessages (double deltaTime) noexcept;
//==============================================================================
/** Scans through the sequence to determine the state of any midi controllers at
a given time.
This will create a sequence of midi controller changes that can be
used to set all midi controllers to the state they would be in at the
specified time within this sequence.
As well as controllers, it will also recreate the midi program number
and pitch bend position.
@param channelNumber the midi channel to look for, in the range 1 to 16. Controllers
for other channels will be ignored.
@param time the time at which you want to find out the state - there are
no explicit units for this time measurement, it's the same units
as used for the timestamps of the messages
@param resultMessages an array to which midi controller-change messages will be added. This
will be the minimum number of controller changes to recreate the
state at the required time.
*/
void createControllerUpdatesForTime (int channelNumber, double time,
Array<MidiMessage>& resultMessages);
//==============================================================================
/** Swaps this sequence with another one. */
void swapWith (MidiMessageSequence&) noexcept;


+ 2
- 2
source/native-plugins/midi-file.cpp View File

@@ -384,12 +384,12 @@ private:

for (size_t i=0; i<numTracks; ++i)
{
const MidiMessageSequence* const track(midiFile.getTrack(i));
const MidiMessageSequence* const track = midiFile.getTrack(i);
CARLA_SAFE_ASSERT_CONTINUE(track != nullptr);

for (int j=0, numEvents = track->getNumEvents(); j<numEvents; ++j)
{
const MidiMessageSequence::MidiEventHolder* const midiEventHolder(track->getEventPointer(j));
const MidiMessageSequence::MidiEventHolder* const midiEventHolder = track->getEventPointer(j);
CARLA_SAFE_ASSERT_CONTINUE(midiEventHolder != nullptr);

const MidiMessage& midiMessage(midiEventHolder->message);


Loading…
Cancel
Save