diff --git a/modules/juce_audio_basics/midi/juce_MidiFile.cpp b/modules/juce_audio_basics/midi/juce_MidiFile.cpp index adeb4fff73..238bc4f9c8 100644 --- a/modules/juce_audio_basics/midi/juce_MidiFile.cpp +++ b/modules/juce_audio_basics/midi/juce_MidiFile.cpp @@ -146,6 +146,26 @@ namespace MidiFileHelpers return 0; } }; + + template + static void findAllMatchingEvents (const OwnedArray& tracks, + MidiMessageSequence& results, + MethodType method) + { + for (int i = 0; i < tracks.size(); ++i) + { + const MidiMessageSequence& track = *tracks.getUnchecked(i); + const int numEvents = track.getNumEvents(); + + for (int j = 0; j < numEvents; ++j) + { + const MidiMessage& m = track.getEventPointer(j)->message; + + if ((m.*method)()) + results.addEvent (m); + } + } + } } //============================================================================== @@ -197,36 +217,19 @@ void MidiFile::setSmpteTimeFormat (const int framesPerSecond, } //============================================================================== -void MidiFile::findAllTempoEvents (MidiMessageSequence& tempoChangeEvents) const +void MidiFile::findAllTempoEvents (MidiMessageSequence& results) const { - for (int i = tracks.size(); --i >= 0;) - { - const int numEvents = tracks.getUnchecked(i)->getNumEvents(); - - for (int j = 0; j < numEvents; ++j) - { - const MidiMessage& m = tracks.getUnchecked(i)->getEventPointer (j)->message; - - if (m.isTempoMetaEvent()) - tempoChangeEvents.addEvent (m); - } - } + MidiFileHelpers::findAllMatchingEvents (tracks, results, &MidiMessage::isTempoMetaEvent); } -void MidiFile::findAllTimeSigEvents (MidiMessageSequence& timeSigEvents) const +void MidiFile::findAllTimeSigEvents (MidiMessageSequence& results) const { - for (int i = tracks.size(); --i >= 0;) - { - const int numEvents = tracks.getUnchecked(i)->getNumEvents(); + MidiFileHelpers::findAllMatchingEvents (tracks, results, &MidiMessage::isTimeSignatureMetaEvent); +} - for (int j = 0; j < numEvents; ++j) - { - const MidiMessage& m = tracks.getUnchecked(i)->getEventPointer (j)->message; - - if (m.isTimeSignatureMetaEvent()) - timeSigEvents.addEvent (m); - } - } +void MidiFile::findAllKeySigEvents (MidiMessageSequence& results) const +{ + MidiFileHelpers::findAllMatchingEvents (tracks, results, &MidiMessage::isKeySignatureMetaEvent); } double MidiFile::getLastTimestamp() const @@ -340,10 +343,7 @@ void MidiFile::convertTimestampTicksToSeconds() for (int j = ms.getNumEvents(); --j >= 0;) { MidiMessage& m = ms.getEventPointer(j)->message; - - m.setTimeStamp (MidiFileHelpers::convertTicksToSeconds (m.getTimeStamp(), - tempoEvents, - timeFormat)); + m.setTimeStamp (MidiFileHelpers::convertTicksToSeconds (m.getTimeStamp(), tempoEvents, timeFormat)); } } } diff --git a/modules/juce_audio_basics/midi/juce_MidiFile.h b/modules/juce_audio_basics/midi/juce_MidiFile.h index 53476a87ed..b9456a1247 100644 --- a/modules/juce_audio_basics/midi/juce_MidiFile.h +++ b/modules/juce_audio_basics/midi/juce_MidiFile.h @@ -120,23 +120,23 @@ public: //============================================================================== /** Makes a list of all the tempo-change meta-events from all tracks in the midi file. - Useful for finding the positions of all the tempo changes in a file. - @param tempoChangeEvents a list to which all the events will be added */ void findAllTempoEvents (MidiMessageSequence& tempoChangeEvents) const; /** Makes a list of all the time-signature meta-events from all tracks in the midi file. - Useful for finding the positions of all the tempo changes in a file. - @param timeSigEvents a list to which all the events will be added */ void findAllTimeSigEvents (MidiMessageSequence& timeSigEvents) const; - /** Returns the latest timestamp in any of the tracks. + /** Makes a list of all the time-signature meta-events from all tracks in the midi file. + @param keySigEvents a list to which all the events will be added + */ + void findAllKeySigEvents (MidiMessageSequence& keySigEvents) const; + /** Returns the latest timestamp in any of the tracks. (Useful for finding the length of the file). */ double getLastTimestamp() const; @@ -171,7 +171,7 @@ public: private: //============================================================================== - OwnedArray tracks; + OwnedArray tracks; short timeFormat; void readNextTrack (const uint8* data, int size); diff --git a/modules/juce_audio_basics/midi/juce_MidiMessage.cpp b/modules/juce_audio_basics/midi/juce_MidiMessage.cpp index 7091eb7716..5657a4436e 100644 --- a/modules/juce_audio_basics/midi/juce_MidiMessage.cpp +++ b/modules/juce_audio_basics/midi/juce_MidiMessage.cpp @@ -797,7 +797,12 @@ bool MidiMessage::isKeySignatureMetaEvent() const noexcept int MidiMessage::getKeySignatureNumberOfSharpsOrFlats() const noexcept { - return (int) *getMetaEventData(); + return (int) getMetaEventData()[0]; +} + +bool MidiMessage::isKeySignatureMajorKey() const noexcept +{ + return getMetaEventData()[1] == 0; } MidiMessage MidiMessage::endOfTrack() noexcept diff --git a/modules/juce_audio_basics/midi/juce_MidiMessage.h b/modules/juce_audio_basics/midi/juce_MidiMessage.h index 40bce10c75..6582a9cbd7 100644 --- a/modules/juce_audio_basics/midi/juce_MidiMessage.h +++ b/modules/juce_audio_basics/midi/juce_MidiMessage.h @@ -112,13 +112,11 @@ public: //============================================================================== /** Returns a pointer to the raw midi data. - @see getRawDataSize */ const uint8* getRawData() const noexcept { return data; } /** Returns the number of bytes of data in the message. - @see getRawData */ int getRawDataSize() const noexcept { return size; } @@ -143,15 +141,12 @@ public: double getTimeStamp() const noexcept { return timeStamp; } /** Changes the message's associated timestamp. - The units for the timestamp will be application-specific - see the notes for getTimeStamp(). - @see addToTimeStamp, getTimeStamp */ void setTimeStamp (double newTimestamp) noexcept { timeStamp = newTimestamp; } /** Adds a value to the message's timestamp. - The units for the timestamp will be application-specific. */ void addToTimeStamp (double delta) noexcept { timeStamp += delta; } @@ -569,7 +564,6 @@ public: //============================================================================== /** Returns true if this is a 'tempo' meta-event. - @see getTempoMetaEventTickLength, getTempoSecondsPerQuarterNote */ bool isTempoMetaEvent() const noexcept; @@ -583,49 +577,51 @@ public: double getTempoMetaEventTickLength (short timeFormat) const noexcept; /** Calculates the seconds-per-quarter-note from a tempo meta-event. - @see isTempoMetaEvent, getTempoMetaEventTickLength */ double getTempoSecondsPerQuarterNote() const noexcept; /** Creates a tempo meta-event. - @see isTempoMetaEvent */ static MidiMessage tempoMetaEvent (int microsecondsPerQuarterNote) noexcept; //============================================================================== /** Returns true if this is a 'time-signature' meta-event. - @see getTimeSignatureInfo */ bool isTimeSignatureMetaEvent() const noexcept; /** Returns the time-signature values from a time-signature meta-event. - @see isTimeSignatureMetaEvent */ void getTimeSignatureInfo (int& numerator, int& denominator) const noexcept; /** Creates a time-signature meta-event. - @see isTimeSignatureMetaEvent */ static MidiMessage timeSignatureMetaEvent (int numerator, int denominator); //============================================================================== /** Returns true if this is a 'key-signature' meta-event. - - @see getKeySignatureNumberOfSharpsOrFlats + @see getKeySignatureNumberOfSharpsOrFlats, isKeySignatureMajorKey */ bool isKeySignatureMetaEvent() const noexcept; /** Returns the key from a key-signature meta-event. - - @see isKeySignatureMetaEvent + This method must only be called if isKeySignatureMetaEvent() is true. + A positive number here indicates the number of sharps in the key signature, + and a negative number indicates a number of flats. So e.g. 3 = F# + C# + G#, + -2 = Bb + Eb + @see isKeySignatureMetaEvent, isKeySignatureMajorKey */ int getKeySignatureNumberOfSharpsOrFlats() const noexcept; + /** Returns true if this key-signature event is major, or false if it's minor. + This method must only be called if isKeySignatureMetaEvent() is true. + */ + bool isKeySignatureMajorKey() const noexcept; + //============================================================================== /** Returns true if this is a 'channel' meta-event. @@ -807,14 +803,11 @@ public: */ MidiMachineControlCommand getMidiMachineControlCommand() const noexcept; - /** Creates an MMC message. - */ + /** Creates an MMC message. */ static MidiMessage midiMachineControlCommand (MidiMachineControlCommand command); /** Checks whether this is an MMC "goto" message. - If it is, the parameters passed-in are set to the time that the message contains. - @see midiMachineControlGoto */ bool isMidiMachineControlGoto (int& hours, @@ -823,9 +816,7 @@ public: int& frames) const noexcept; /** Creates an MMC "goto" message. - This messages tells the device to go to a specific frame. - @see isMidiMachineControlGoto */ static MidiMessage midiMachineControlGoto (int hours, @@ -835,14 +826,12 @@ public: //============================================================================== /** Creates a master-volume change message. - @param volume the volume, 0 to 1.0 */ static MidiMessage masterVolume (float volume); //============================================================================== /** Creates a system-exclusive message. - The data passed in is wrapped with header and tail bytes of 0xf0 and 0xf7. */ static MidiMessage createSysExMessage (const void* sysexData,