30 auto buffer =
v & 0x7f;
32 while ((
v >>= 7) != 0)
35 buffer |= ((
v & 0x7f) | 0x80);
40 out.writeByte ((
char) buffer);
49 template <
typename Integral>
58 template <
typename Integral>
62 constexpr auto size =
sizeof (Integral);
86 auto*
data = initialData;
87 auto remaining = maxSize;
100 for (
int i = 0;
i < 8; ++
i)
121 if (! bytesRemaining.hasValue() || *bytesRemaining > remaining)
126 if (! optFileType.hasValue() || 2 < *optFileType)
131 if (! optNumTracks.hasValue() || (*optFileType == 0 && *optNumTracks != 1))
136 if (! optTimeFormat.hasValue())
141 result.fileType = (short) *optFileType;
142 result.timeFormat = (short) *optTimeFormat;
143 result.numberOfTracks = (short) *optNumTracks;
144 result.bytesRead = maxSize - remaining;
154 return time / (-(timeFormat >> 8) * (timeFormat & 0xff));
156 double lastTime = 0, correctedTime = 0;
157 auto tickLen = 1.0 / (timeFormat & 0x7fff);
158 auto secsPerTick = 0.5 * tickLen;
161 for (
int i = 0;
i < numEvents; ++
i)
164 auto eventTime =
m.getTimeStamp();
166 if (eventTime >= time)
169 correctedTime += (eventTime - lastTime) * secsPerTick;
170 lastTime = eventTime;
172 if (
m.isTempoMetaEvent())
173 secsPerTick = tickLen *
m.getTempoSecondsPerQuarterNote();
175 while (
i + 1 < numEvents)
179 if (m2.getTimeStamp() != eventTime)
182 if (m2.isTempoMetaEvent())
189 return correctedTime + (time - lastTime) * secsPerTick;
192 template <
typename MethodType>
197 for (
auto* track : tracks)
199 auto numEvents = track->getNumEvents();
201 for (
int j = 0;
j < numEvents; ++
j)
203 auto&
m = track->getEventPointer(
j)->message;
214 uint8 lastStatusByte = 0;
222 if (! delay.isValid())
225 data += delay.bytesUsed;
226 size -= delay.bytesUsed;
243 auto firstByte = *(
mm.getRawData());
245 if ((firstByte & 0xf0) != 0xf0)
246 lastStatusByte = firstByte;
277 tracks = std::move (other.tracks);
316 timeFormat = (short) (((-framesPerSecond) << 8) | subframeResolution);
340 t =
jmax (
t, ms->getEndTime());
347 bool createMatchingNoteOffs,
353 const int maxSensibleMidiFileSize = 200 * 1024 * 1024;
360 auto d =
static_cast<const uint8*
> (
data.getData());
364 if (! optHeader.hasValue())
367 const auto header = *optHeader;
370 d += header.bytesRead;
371 size -= (size_t) header.bytesRead;
373 for (
int track = 0; track < header.numberOfTracks; ++track)
377 if (! optChunkType.hasValue())
382 if (! optChunkSize.hasValue())
385 const auto chunkSize = *optChunkSize;
387 if (
size < chunkSize)
397 const auto successful = (
size == 0);
399 if (successful && fileType !=
nullptr)
400 *fileType = header.fileType;
410 std::stable_sort (sequence.list.begin(), sequence.list.end(),
414 auto t1 = a->message.getTimeStamp();
415 auto t2 = b->message.getTimeStamp();
417 if (t1 < t2) return true;
418 if (t2 < t1) return false;
420 return a->message.isNoteOff() && b->message.isNoteOn();
423 if (createMatchingNoteOffs)
424 sequence.updateMatchedPairs();
440 for (
int j = ms->getNumEvents(); --
j >= 0;)
442 auto&
m = ms->getEventPointer(
j)->message;
452 jassert (midiFileType >= 0 && midiFileType <= 2);
455 if (!
out.writeIntBigEndian (6))
return false;
456 if (!
out.writeShortBigEndian ((
short) midiFileType))
return false;
457 if (!
out.writeShortBigEndian ((
short)
tracks.size()))
return false;
473 uint8 lastStatusByte = 0;
474 bool endOfTrackEventWritten =
false;
480 if (
mm.isEndOfTrackMetaEvent())
481 endOfTrackEventWritten =
true;
484 auto delta =
jmax (0, tick - lastTick);
488 auto*
data =
mm.getRawData();
489 auto dataSize =
mm.getRawDataSize();
490 auto statusByte =
data[0];
492 if (statusByte == lastStatusByte
493 && (statusByte & 0xf0) != 0xf0
500 else if (statusByte == 0xf0)
502 out.writeByte ((
char) statusByte);
510 out.write (
data, (
size_t) dataSize);
511 lastStatusByte = statusByte;
514 if (! endOfTrackEventWritten)
518 out.write (
m.getRawData(), (
size_t)
m.getRawDataSize());
533struct MidiFileTest :
public UnitTest
539 void runTest()
override
541 beginTest (
"ReadTrack respects running status");
543 const auto sequence = parseSequence ([] (OutputStream&
os)
545 MidiFileHelpers::writeVariableLengthInt (
os, 100);
546 writeBytes (
os, { 0x90, 0x40, 0x40 });
547 MidiFileHelpers::writeVariableLengthInt (
os, 200);
548 writeBytes (
os, { 0x40, 0x40 });
549 MidiFileHelpers::writeVariableLengthInt (
os, 300);
550 writeBytes (
os, { 0xff, 0x2f, 0x00 });
553 expectEquals (sequence.getNumEvents(), 3);
554 expect (sequence.getEventPointer (0)->message.isNoteOn());
555 expect (sequence.getEventPointer (1)->message.isNoteOn());
556 expect (sequence.getEventPointer (2)->message.isEndOfTrackMetaEvent());
559 beginTest (
"ReadTrack returns available messages if input is truncated");
562 const auto sequence = parseSequence ([] (OutputStream&
os)
565 writeBytes (
os, { 0xff });
568 expectEquals (sequence.getNumEvents(), 0);
572 const auto sequence = parseSequence ([] (OutputStream&
os)
575 MidiFileHelpers::writeVariableLengthInt (
os, 0xffff);
578 expectEquals (sequence.getNumEvents(), 0);
582 const auto sequence = parseSequence ([] (OutputStream&
os)
585 MidiFileHelpers::writeVariableLengthInt (
os, 0xffff);
586 writeBytes (
os, { 0x90, 0x40 });
589 expectEquals (sequence.getNumEvents(), 1);
590 expect (sequence.getEventPointer (0)->message.isNoteOff());
591 expectEquals (sequence.getEventPointer (0)->message.getNoteNumber(), 0x40);
592 expectEquals (sequence.getEventPointer (0)->message.getVelocity(), (
uint8) 0x00);
596 beginTest (
"Header parsing works");
600 const auto header = parseHeader ([] (OutputStream&) {});
601 expect (! header.hasValue());
606 const auto header = parseHeader ([] (OutputStream&
os)
608 writeBytes (
os, { 0xff });
611 expect (! header.hasValue());
616 const auto header = parseHeader ([] (OutputStream&
os)
618 writeBytes (
os, {
'M',
'T',
'h',
'd' });
621 expect (! header.hasValue());
626 const auto header = parseHeader ([] (OutputStream&
os)
628 writeBytes (
os, {
'M',
'T',
'h',
'd', 0, 0, 0, 6, 0, 0, 0, 16, 0, 1 });
631 expect (! header.hasValue());
636 const auto header = parseHeader ([] (OutputStream&
os)
638 writeBytes (
os, {
'M',
'T',
'h',
'd', 0, 0, 0, 6, 0, 5, 0, 16, 0, 1 });
641 expect (! header.hasValue());
646 const auto header = parseHeader ([] (OutputStream&
os)
648 writeBytes (
os, {
'M',
'T',
'h',
'd', 0, 0, 0, 6, 0, 1, 0, 16, 0, 1 });
651 expect (header.hasValue());
653 expectEquals (header->fileType, (
short) 1);
654 expectEquals (header->numberOfTracks, (
short) 16);
655 expectEquals (header->timeFormat, (
short) 1);
656 expectEquals ((
int) header->bytesRead, 14);
660 beginTest (
"Read from stream");
664 const auto file = parseFile ([] (OutputStream&) {});
665 expect (!
file.hasValue());
670 const auto file = parseFile ([] (OutputStream&
os)
672 writeBytes (
os, {
'M',
'T',
'h',
'd' });
675 expect (!
file.hasValue());
680 const auto file = parseFile ([] (OutputStream&
os)
682 writeBytes (
os, {
'M',
'T',
'h',
'd', 0, 0, 0, 6, 0, 1, 0, 0, 0, 1 });
685 expect (
file.hasValue());
686 expectEquals (
file->getNumTracks(), 0);
691 const auto file = parseFile ([] (OutputStream&
os)
693 writeBytes (
os, {
'M',
'T',
'h',
'd', 0, 0, 0, 6, 0, 1, 0, 1, 0, 1 });
694 writeBytes (
os, {
'M',
'T',
'r',
'?' });
697 expect (!
file.hasValue());
702 const auto file = parseFile ([] (OutputStream&
os)
704 writeBytes (
os, {
'M',
'T',
'h',
'd', 0, 0, 0, 6, 0, 1, 0, 1, 0, 1 });
705 writeBytes (
os, {
'M',
'T',
'r',
'k', 0, 0, 0, 1, 0xff });
708 expect (
file.hasValue());
709 expectEquals (
file->getNumTracks(), 1);
710 expectEquals (
file->getTrack (0)->getNumEvents(), 0);
715 const auto file = parseFile ([] (OutputStream&
os)
717 writeBytes (
os, {
'M',
'T',
'h',
'd', 0, 0, 0, 6, 0, 1, 0, 1, 0, 1 });
718 writeBytes (
os, {
'M',
'T',
'r',
'k', 0x0f, 0, 0, 0, 0xff });
721 expect (!
file.hasValue());
726 const auto file = parseFile ([] (OutputStream&
os)
728 writeBytes (
os, {
'M',
'T',
'h',
'd', 0, 0, 0, 6, 0, 1, 0, 1, 0, 1 });
729 writeBytes (
os, {
'M',
'T',
'r',
'k', 0, 0, 0, 4 });
731 MidiFileHelpers::writeVariableLengthInt (
os, 0x0f);
732 writeBytes (
os, { 0x80, 0x00, 0x00 });
735 expect (
file.hasValue());
736 expectEquals (
file->getNumTracks(), 1);
738 auto& track = *
file->getTrack (0);
739 expectEquals (track.getNumEvents(), 1);
740 expect (track.getEventPointer (0)->message.isNoteOff());
741 expectEquals (track.getEventPointer (0)->message.getTimeStamp(), (
double) 0x0f);
746 template <
typename Fn>
747 static MidiMessageSequence parseSequence (Fn&&
fn)
749 MemoryOutputStream
os;
752 return MidiFileHelpers::readTrack (
reinterpret_cast<const uint8*
> (
os.getData()),
753 (
int)
os.getDataSize());
756 template <
typename Fn>
757 static Optional<MidiFileHelpers::HeaderDetails> parseHeader (Fn&&
fn)
759 MemoryOutputStream
os;
762 return MidiFileHelpers::parseMidiHeader (
reinterpret_cast<const uint8*
> (
os.getData()),
766 template <
typename Fn>
767 static Optional<MidiFile> parseFile (Fn&&
fn)
769 MemoryOutputStream
os;
772 MemoryInputStream is (
os.getData(),
os.getDataSize(),
false);
777 if (mf.readFrom (is,
true, &fileType))
783 static void writeBytes (OutputStream&
os,
const std::vector<uint8>& bytes)
785 for (
const auto&
byte : bytes)
786 os.writeByte ((
char)
byte);
790static MidiFileTest midiFileTests;
Type jmax(const Type a, const Type b)
Definition MathsFunctions.h:48
#define noexcept
Definition DistrhoDefines.h:72
uint8_t a
Definition Spc_Cpu.h:141
uint8_t uint8
Definition basics.h:86
static constexpr uint32 bigEndianInt(const void *bytes) noexcept
Definition juce_ByteOrder.h:211
static constexpr uint16 bigEndianShort(const void *bytes) noexcept
Definition juce_ByteOrder.h:210
Definition juce_MemoryBlock.h:33
Definition juce_MemoryOutputStream.h:36
void convertTimestampTicksToSeconds()
Definition juce_MidiFile.cpp:430
void addTrack(const MidiMessageSequence &trackSequence)
Definition juce_MidiFile.cpp:298
void setTicksPerQuarterNote(int ticksPerQuarterNote) noexcept
Definition juce_MidiFile.cpp:309
int getNumTracks() const noexcept
Definition juce_MidiFile.cpp:288
short getTimeFormat() const noexcept
Definition juce_MidiFile.cpp:304
void setSmpteTimeFormat(int framesPerSecond, int subframeResolution) noexcept
Definition juce_MidiFile.cpp:314
double getLastTimestamp() const
Definition juce_MidiFile.cpp:335
bool readFrom(InputStream &sourceStream, bool createMatchingNoteOffs=true, int *midiFileType=nullptr)
Definition juce_MidiFile.cpp:346
bool writeTrack(OutputStream &, const MidiMessageSequence &) const
Definition juce_MidiFile.cpp:468
MidiFile()
Definition juce_MidiFile.cpp:254
void findAllTimeSigEvents(MidiMessageSequence &timeSigEvents) const
Definition juce_MidiFile.cpp:325
void findAllKeySigEvents(MidiMessageSequence &keySigEvents) const
Definition juce_MidiFile.cpp:330
void findAllTempoEvents(MidiMessageSequence &tempoChangeEvents) const
Definition juce_MidiFile.cpp:320
void readNextTrack(const uint8 *, int, bool)
Definition juce_MidiFile.cpp:405
void clear()
Definition juce_MidiFile.cpp:282
const MidiMessageSequence * getTrack(int index) const noexcept
Definition juce_MidiFile.cpp:293
OwnedArray< MidiMessageSequence > tracks
Definition juce_MidiFile.h:189
short timeFormat
Definition juce_MidiFile.h:190
bool writeTo(OutputStream &destStream, int midiFileType=1) const
Definition juce_MidiFile.cpp:450
Definition juce_MidiMessage.h:35
bool isKeySignatureMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:874
bool isTimeSignatureMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:834
bool isTempoMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:779
double getTempoSecondsPerQuarterNote() const noexcept
Definition juce_MidiMessage.cpp:788
static MidiMessage endOfTrack() noexcept
Definition juce_MidiMessage.cpp:896
static VariableLengthValue readVariableLengthValue(const uint8 *data, int maxBytesToUse) noexcept
Definition juce_MidiMessage.cpp:60
Definition juce_MidiMessageSequence.h:65
MidiMessage message
Definition juce_MidiMessageSequence.h:69
Definition juce_MidiMessageSequence.h:38
MidiEventHolder * addEvent(const MidiMessage &newMessage, double timeAdjustment=0)
Definition juce_MidiMessageSequence.cpp:167
MidiEventHolder * getEventPointer(int index) const noexcept
Definition juce_MidiMessageSequence.cpp:80
int getNumEvents() const noexcept
Definition juce_MidiMessageSequence.cpp:75
Definition juce_Optional.h:74
Definition juce_OutputStream.h:38
virtual bool writeIntBigEndian(int value)
Definition juce_OutputStream.cpp:115
Definition juce_OwnedArray.h:51
Definition juce_UnitTest.h:70
unsigned * m
Definition inflate.c:1559
struct huft * t
Definition inflate.c:943
register unsigned j
Definition inflate.c:1576
unsigned v[N_MAX]
Definition inflate.c:1584
unsigned d
Definition inflate.c:940
register unsigned i
Definition inflate.c:1575
JSAMPIMAGE data
Definition jpeglib.h:945
float out
Definition lilv_test.c:1461
Definition juce_MidiFile.cpp:27
static void writeVariableLengthInt(OutputStream &out, uint32 v)
Definition juce_MidiFile.cpp:28
static double convertTicksToSeconds(double time, const MidiMessageSequence &tempoEvents, int timeFormat)
Definition juce_MidiFile.cpp:149
static void findAllMatchingEvents(const OwnedArray< MidiMessageSequence > &tracks, MidiMessageSequence &results, MethodType method)
Definition juce_MidiFile.cpp:193
static Optional< HeaderDetails > parseMidiHeader(const uint8 *const initialData, const size_t maxSize)
Definition juce_MidiFile.cpp:83
Optional< Integral > tryRead(const uint8 *&data, size_t &remaining)
Definition juce_MidiFile.cpp:59
static MidiMessageSequence readTrack(const uint8 *data, int size)
Definition juce_MidiFile.cpp:211
Definition juce_UnitTestCategories.h:27
Definition carla_juce.cpp:31
unsigned short uint16
Definition juce_MathsFunctions.h:41
unsigned int uint32
Definition juce_MathsFunctions.h:45
unsigned char uint8
Definition juce_MathsFunctions.h:37
int roundToInt(const FloatType value) noexcept
Definition juce_MathsFunctions.h:465
Definition juce_Uuid.h:141
static constexpr auto read
Definition juce_MidiFile.cpp:56
static constexpr auto read
Definition juce_MidiFile.cpp:53
Definition juce_MidiFile.cpp:50
const char const char const char const char char * fn
Definition swell-functions.h:168
int result
Definition process.c:1455
struct zdirent * file
Definition win32.c:1500
static ZCONST char Far * method[NUM_METHODS]
Definition zipinfo.c:1008
static ZCONST char Far * os[NUM_HOSTS]
Definition zipinfo.c:1001
mm
Definition zipinfo.c:2291
#define const
Definition zconf.h:137