diff --git a/build/linux/JUCE.make b/build/linux/JUCE.make index 955149c72b..9e57ad9c78 100644 --- a/build/linux/JUCE.make +++ b/build/linux/JUCE.make @@ -161,6 +161,7 @@ OBJECTS := \ $(OBJDIR)/juce_AudioDeviceManager.o \ $(OBJDIR)/juce_AudioIODevice.o \ $(OBJDIR)/juce_AudioIODeviceType.o \ + $(OBJDIR)/juce_MidiOutput.o \ $(OBJDIR)/juce_Sampler.o \ $(OBJDIR)/juce_Synthesiser.o \ $(OBJDIR)/juce_FileBasedDocument.o \ @@ -1062,6 +1063,11 @@ $(OBJDIR)/juce_AudioIODeviceType.o: ../../src/juce_appframework/audio/devices/ju @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o $@ -c $< +$(OBJDIR)/juce_MidiOutput.o: ../../src/juce_appframework/audio/devices/juce_MidiOutput.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o $@ -c $< + $(OBJDIR)/juce_Sampler.o: ../../src/juce_appframework/audio/synthesisers/juce_Sampler.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) diff --git a/build/linux/platform_specific_code/juce_linux_Midi.cpp b/build/linux/platform_specific_code/juce_linux_Midi.cpp index 682d1cf021..02071afcde 100644 --- a/build/linux/platform_specific_code/juce_linux_Midi.cpp +++ b/build/linux/platform_specific_code/juce_linux_Midi.cpp @@ -264,11 +264,6 @@ MidiOutput* MidiOutput::createNewDevice (const String& deviceName) return newDevice; } -MidiOutput::MidiOutput() - : internal (0) -{ -} - MidiOutput::~MidiOutput() { MidiOutputDevice* const device = (MidiOutputDevice*) internal; diff --git a/build/macosx/Juce.xcodeproj/project.pbxproj b/build/macosx/Juce.xcodeproj/project.pbxproj index 8999b07627..8ecc025440 100644 --- a/build/macosx/Juce.xcodeproj/project.pbxproj +++ b/build/macosx/Juce.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 84052DE408D095D200BEC0F0 /* juce_ToneGeneratorAudioSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84052DE208D095D200BEC0F0 /* juce_ToneGeneratorAudioSource.cpp */; }; 84052DE508D095D200BEC0F0 /* juce_ToneGeneratorAudioSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 84052DE308D095D200BEC0F0 /* juce_ToneGeneratorAudioSource.h */; }; + 8406AA5A0C4BDF90003A0D6A /* juce_MidiOutput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8406AA590C4BDF90003A0D6A /* juce_MidiOutput.cpp */; }; 8406C44609642CE100C99145 /* juce_LowLevelGraphicsContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 8406C44309642CE100C99145 /* juce_LowLevelGraphicsContext.h */; }; 8406C44709642CE100C99145 /* juce_LowLevelGraphicsSoftwareRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8406C44409642CE100C99145 /* juce_LowLevelGraphicsSoftwareRenderer.cpp */; settings = {COMPILER_FLAGS = "-O3"; }; }; 8406C44809642CE100C99145 /* juce_LowLevelGraphicsSoftwareRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8406C44509642CE100C99145 /* juce_LowLevelGraphicsSoftwareRenderer.h */; }; @@ -650,6 +651,7 @@ /* Begin PBXFileReference section */ 84052DE208D095D200BEC0F0 /* juce_ToneGeneratorAudioSource.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_ToneGeneratorAudioSource.cpp; sourceTree = ""; }; 84052DE308D095D200BEC0F0 /* juce_ToneGeneratorAudioSource.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_ToneGeneratorAudioSource.h; sourceTree = ""; }; + 8406AA590C4BDF90003A0D6A /* juce_MidiOutput.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_MidiOutput.cpp; sourceTree = ""; }; 8406C44309642CE100C99145 /* juce_LowLevelGraphicsContext.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_LowLevelGraphicsContext.h; sourceTree = ""; }; 8406C44409642CE100C99145 /* juce_LowLevelGraphicsSoftwareRenderer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_LowLevelGraphicsSoftwareRenderer.cpp; sourceTree = ""; }; 8406C44509642CE100C99145 /* juce_LowLevelGraphicsSoftwareRenderer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_LowLevelGraphicsSoftwareRenderer.h; sourceTree = ""; }; @@ -1355,6 +1357,7 @@ 84198B0A096D8E2B0022A439 /* juce_AudioDeviceManager.cpp */, 84198B0B096D8E2B0022A439 /* juce_AudioDeviceManager.h */, 84198B0D096D8E2B0022A439 /* juce_MidiInput.h */, + 8406AA590C4BDF90003A0D6A /* juce_MidiOutput.cpp */, 84198B0E096D8E2B0022A439 /* juce_MidiOutput.h */, ); path = devices; @@ -3114,6 +3117,7 @@ 842D3D0E0C0D7CF200E9FFE4 /* juce_MenuBarModel.cpp in Sources */, 847F72DB0C2702A000CBECEC /* juce_DirectoryContentsDisplayComponent.cpp in Sources */, 847F72DD0C2702A000CBECEC /* juce_FileTreeComponent.cpp in Sources */, + 8406AA5A0C4BDF90003A0D6A /* juce_MidiOutput.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/build/macosx/platform_specific_code/juce_mac_CoreMidi.cpp b/build/macosx/platform_specific_code/juce_mac_CoreMidi.cpp index e151bd025b..08a025b110 100644 --- a/build/macosx/platform_specific_code/juce_mac_CoreMidi.cpp +++ b/build/macosx/platform_specific_code/juce_mac_CoreMidi.cpp @@ -285,10 +285,6 @@ MidiOutput* MidiOutput::openDevice (int index) return mo; } -MidiOutput::MidiOutput() -{ -} - MidiOutput::~MidiOutput() { MidiPortAndEndpoint* const mpe = (MidiPortAndEndpoint*)internal; diff --git a/build/win32/platform_specific_code/juce_win32_Midi.cpp b/build/win32/platform_specific_code/juce_win32_Midi.cpp index 07154898dd..fcaab29d12 100644 --- a/build/win32/platform_specific_code/juce_win32_Midi.cpp +++ b/build/win32/platform_specific_code/juce_win32_Midi.cpp @@ -551,10 +551,6 @@ MidiOutput* MidiOutput::openDevice (int index) return 0; } -MidiOutput::MidiOutput() -{ -} - MidiOutput::~MidiOutput() { MidiOutHandle* const h = (MidiOutHandle*) internal; diff --git a/build/win32/vc8/JUCE.vcproj b/build/win32/vc8/JUCE.vcproj index cad8575920..784a750543 100644 --- a/build/win32/vc8/JUCE.vcproj +++ b/build/win32/vc8/JUCE.vcproj @@ -1057,6 +1057,10 @@ RelativePath="..\..\..\src\juce_appframework\audio\devices\juce_MidiInput.h" > + + diff --git a/docs/JUCE changelist.txt b/docs/JUCE changelist.txt index 3692a98db7..eaceb90820 100644 --- a/docs/JUCE changelist.txt +++ b/docs/JUCE changelist.txt @@ -15,6 +15,7 @@ Changelist for version 1.44 - added some virtual methods to TextEditor to allow customisation of its popup menu. - added a Component::setExplicitFocusOrder() method for specifying the order in which components have their focus traversed, and added Jucer support for setting this value. - made slider skew factor editable in the jucer +- added a background thread to the MidiOutput class, so it can be given a batch of midi events and will dispatch them itself based on their timestamps. ============================================================================== Changelist for version 1.43 diff --git a/src/juce_appframework/audio/devices/juce_MidiOutput.cpp b/src/juce_appframework/audio/devices/juce_MidiOutput.cpp new file mode 100644 index 0000000000..e2e3ea2edb --- /dev/null +++ b/src/juce_appframework/audio/devices/juce_MidiOutput.cpp @@ -0,0 +1,178 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + JUCE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +#include "../../../juce_core/basics/juce_StandardHeader.h" + +BEGIN_JUCE_NAMESPACE + +#include "juce_MidiOutput.h" +#include "../../../juce_core/threads/juce_ScopedLock.h" +#include "../../../juce_core/basics/juce_Time.h" + + +//============================================================================== +MidiOutput::MidiOutput() throw() + : Thread ("midi out"), + internal (0), + firstMessage (0) +{ +} + +MidiOutput::PendingMessage::PendingMessage (const uint8* const data, + const int len, + const double sampleNumber) throw() + : message (data, len, sampleNumber) +{ +} + +void MidiOutput::sendBlockOfMessages (const MidiBuffer& buffer, + const double millisecondCounterToStartAt, + double samplesPerSecondForBuffer) throw() +{ + // You've got to call startBackgroundThread() for this to actually work.. + jassert (isThreadRunning()); + + // this needs to be a value in the future - RTFM for this method! + jassert (millisecondCounterToStartAt > 0); + + samplesPerSecondForBuffer *= 0.001; + + MidiBuffer::Iterator i (buffer); + + const uint8* data; + int len, time; + + while (i.getNextEvent (data, len, time)) + { + const double eventTime = millisecondCounterToStartAt + samplesPerSecondForBuffer * time; + + PendingMessage* const m + = new PendingMessage (data, len, eventTime); + + const ScopedLock sl (lock); + + if (firstMessage == 0) + { + firstMessage = m; + m->next = 0; + } + else + { + PendingMessage* mm = firstMessage; + + while (mm->next != 0 && mm->next->message.getTimeStamp() <= eventTime) + mm = mm->next; + + m->next = mm->next; + mm->next = m; + } + } + + notify(); +} + +void MidiOutput::clearAllPendingMessages() throw() +{ + const ScopedLock sl (lock); + + while (firstMessage != 0) + { + PendingMessage* const m = firstMessage; + firstMessage = firstMessage->next; + delete m; + } +} + +void MidiOutput::startBackgroundThread() throw() +{ + startThread (9); +} + +void MidiOutput::stopBackgroundThread() throw() +{ + stopThread (5000); +} + +void MidiOutput::run() +{ + while (! threadShouldExit()) + { + uint32 now = Time::getMillisecondCounter(); + uint32 eventTime = 0; + uint32 timeToWait = 500; + + lock.enter(); + PendingMessage* message = firstMessage; + + if (message != 0) + { + eventTime = roundDoubleToInt (message->message.getTimeStamp()); + + if (eventTime > now + 20) + { + timeToWait = jmax (10, eventTime - now - 100); + message = 0; + } + else + { + firstMessage = message->next; + } + } + + lock.exit(); + + if (message != 0) + { + if (eventTime > now) + { + Time::waitForMillisecondCounter (eventTime); + + if (threadShouldExit()) + break; + } + + if (eventTime > now - 200) + sendMessageNow (message->message); + + delete message; + } + else + { + jassert (timeToWait < 1000 * 30); + wait (timeToWait); + } + } + + clearAllPendingMessages(); +} + + +END_JUCE_NAMESPACE diff --git a/src/juce_appframework/audio/devices/juce_MidiOutput.h b/src/juce_appframework/audio/devices/juce_MidiOutput.h index 74e3259ddd..796f6cbdd2 100644 --- a/src/juce_appframework/audio/devices/juce_MidiOutput.h +++ b/src/juce_appframework/audio/devices/juce_MidiOutput.h @@ -33,7 +33,9 @@ #define __JUCE_MIDIOUTPUT_JUCEHEADER__ #include "../../../juce_core/text/juce_StringArray.h" +#include "../../../juce_core/threads/juce_Thread.h" #include "../midi/juce_MidiMessage.h" +#include "../midi/juce_MidiBuffer.h" //============================================================================== @@ -45,7 +47,7 @@ @see MidiInput */ -class JUCE_API MidiOutput +class JUCE_API MidiOutput : private Thread { public: //============================================================================== @@ -103,6 +105,7 @@ public: /** Sends a midi reset to the device. */ void reset(); + //============================================================================== /** Returns the current volume setting for this device. */ bool getVolume (float& leftVol, @@ -112,6 +115,44 @@ public: void setVolume (float leftVol, float rightVol); + //============================================================================== + /** This lets you supply a block of messages that will be sent out at some point + in the future. + + The MidiOutput class has an internal thread that can send out timestamped + messages - this appends a set of messages to its internal buffer, ready for + sending. + + This will only work if you've already started the thread with startBackgroundThread(). + + A time is supplied, at which the block of messages should be sent. This time uses + the same time base as Time::getMillisecondCounter(), and must be in the future. + + The samplesPerSecondForBuffer parameter indicates the number of samples per second + used by the MidiBuffer. Each event in a MidiBuffer has a sample position, and the + samplesPerSecondForBuffer value is needed to convert this sample position to a + real time. + */ + void sendBlockOfMessages (const MidiBuffer& buffer, + const double millisecondCounterToStartAt, + double samplesPerSecondForBuffer) throw(); + + /** Gets rid of any midi messages that had been added by sendBlockOfMessages(). + */ + void clearAllPendingMessages() throw(); + + /** Starts up a background thread so that the device can send blocks of data. + + Call this to get the device ready, before using sendBlockOfMessages(). + */ + void startBackgroundThread() throw(); + + /** Stops the background thread, and clears any pending midi events. + + @see startBackgroundThread + */ + void stopBackgroundThread() throw(); + //============================================================================== juce_UseDebuggingNewOperator @@ -119,8 +160,23 @@ public: private: void* internal; - MidiOutput(); + struct PendingMessage + { + PendingMessage (const uint8* const data, const int len, const double sampleNumber) throw(); + + MidiMessage message; + PendingMessage* next; + + juce_UseDebuggingNewOperator + }; + + CriticalSection lock; + PendingMessage* firstMessage; + + MidiOutput() throw(); MidiOutput (const MidiOutput&); + + void run(); }; diff --git a/src/juce_appframework/audio/midi/juce_MidiBuffer.cpp b/src/juce_appframework/audio/midi/juce_MidiBuffer.cpp index 93cb664c8a..7de9bff904 100644 --- a/src/juce_appframework/audio/midi/juce_MidiBuffer.cpp +++ b/src/juce_appframework/audio/midi/juce_MidiBuffer.cpp @@ -37,13 +37,13 @@ BEGIN_JUCE_NAMESPACE //============================================================================== -MidiBuffer::MidiBuffer() +MidiBuffer::MidiBuffer() throw() : ArrayAllocationBase (32), bytesUsed (0) { } -MidiBuffer::MidiBuffer (const MidiBuffer& other) +MidiBuffer::MidiBuffer (const MidiBuffer& other) throw() : ArrayAllocationBase (32), bytesUsed (other.bytesUsed) { @@ -51,7 +51,7 @@ MidiBuffer::MidiBuffer (const MidiBuffer& other) memcpy (elements, other.elements, bytesUsed); } -const MidiBuffer& MidiBuffer::operator= (const MidiBuffer& other) +const MidiBuffer& MidiBuffer::operator= (const MidiBuffer& other) throw() { bytesUsed = other.bytesUsed; ensureAllocatedSize (bytesUsed); @@ -60,17 +60,17 @@ const MidiBuffer& MidiBuffer::operator= (const MidiBuffer& other) return *this; } -MidiBuffer::~MidiBuffer() +MidiBuffer::~MidiBuffer() throw() { } -void MidiBuffer::clear() +void MidiBuffer::clear() throw() { bytesUsed = 0; } void MidiBuffer::clear (const int startSample, - const int numSamples) + const int numSamples) throw() { uint8* const start = findEventAfter (elements, startSample - 1); uint8* const end = findEventAfter (start, startSample + numSamples - 1); @@ -87,13 +87,13 @@ void MidiBuffer::clear (const int startSample, } void MidiBuffer::addEvent (const MidiMessage& m, - const int sampleNumber) + const int sampleNumber) throw() { addEvent (m.getRawData(), m.getRawDataSize(), sampleNumber); } static int findActualEventLength (const uint8* const data, - const int maxBytes) + const int maxBytes) throw() { unsigned int byte = (unsigned int) *data; @@ -125,7 +125,7 @@ static int findActualEventLength (const uint8* const data, void MidiBuffer::addEvent (const uint8* const newData, const int maxBytes, - const int sampleNumber) + const int sampleNumber) throw() { const int numBytes = findActualEventLength (newData, maxBytes); @@ -155,7 +155,7 @@ void MidiBuffer::addEvent (const uint8* const newData, void MidiBuffer::addEvents (const MidiBuffer& otherBuffer, const int startSample, const int numSamples, - const int sampleDeltaToAdd) + const int sampleDeltaToAdd) throw() { Iterator i (otherBuffer); i.setNextSamplePosition (startSample); @@ -170,12 +170,12 @@ void MidiBuffer::addEvents (const MidiBuffer& otherBuffer, } } -bool MidiBuffer::isEmpty() const +bool MidiBuffer::isEmpty() const throw() { return bytesUsed == 0; } -int MidiBuffer::getNumEvents() const +int MidiBuffer::getNumEvents() const throw() { int n = 0; const uint8* d = elements; @@ -191,12 +191,12 @@ int MidiBuffer::getNumEvents() const return n; } -int MidiBuffer::getFirstEventTime() const +int MidiBuffer::getFirstEventTime() const throw() { return (bytesUsed > 0) ? *(const int*) elements : 0; } -int MidiBuffer::getLastEventTime() const +int MidiBuffer::getLastEventTime() const throw() { if (bytesUsed == 0) return 0; @@ -215,7 +215,7 @@ int MidiBuffer::getLastEventTime() const } } -uint8* MidiBuffer::findEventAfter (uint8* d, const int samplePosition) const +uint8* MidiBuffer::findEventAfter (uint8* d, const int samplePosition) const throw() { const uint8* const endData = elements + bytesUsed; @@ -229,18 +229,18 @@ uint8* MidiBuffer::findEventAfter (uint8* d, const int samplePosition) const } //============================================================================== -MidiBuffer::Iterator::Iterator (const MidiBuffer& buffer) +MidiBuffer::Iterator::Iterator (const MidiBuffer& buffer) throw() : buffer (buffer), data (buffer.elements) { } -MidiBuffer::Iterator::~Iterator() +MidiBuffer::Iterator::~Iterator() throw() { } //============================================================================== -void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) +void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) throw() { data = buffer.elements; const uint8* dataEnd = buffer.elements + buffer.bytesUsed; @@ -254,7 +254,7 @@ void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, int& numBytes, - int& samplePosition) + int& samplePosition) throw() { if (data >= buffer.elements + buffer.bytesUsed) return false; @@ -270,7 +270,7 @@ bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, } bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, - int& samplePosition) + int& samplePosition) throw() { if (data >= buffer.elements + buffer.bytesUsed) return false; diff --git a/src/juce_appframework/audio/midi/juce_MidiBuffer.h b/src/juce_appframework/audio/midi/juce_MidiBuffer.h index 07d3050d83..5216008ae6 100644 --- a/src/juce_appframework/audio/midi/juce_MidiBuffer.h +++ b/src/juce_appframework/audio/midi/juce_MidiBuffer.h @@ -50,20 +50,20 @@ class JUCE_API MidiBuffer : private ArrayAllocationBase public: //============================================================================== /** Creates an empty MidiBuffer. */ - MidiBuffer(); + MidiBuffer() throw(); /** Creates a copy of another MidiBuffer. */ - MidiBuffer (const MidiBuffer& other); + MidiBuffer (const MidiBuffer& other) throw(); /** Makes a copy of another MidiBuffer. */ - const MidiBuffer& operator= (const MidiBuffer& other); + const MidiBuffer& operator= (const MidiBuffer& other) throw(); /** Destructor */ - ~MidiBuffer(); + ~MidiBuffer() throw(); //============================================================================== /** Removes all events from the buffer. */ - void clear(); + void clear() throw(); /** Removes all events between two times from the buffer. @@ -71,13 +71,13 @@ public: be removed. */ void clear (const int start, - const int numSamples); + const int numSamples) throw(); /** Returns true if the buffer is empty. To actually retrieve the events, use a MidiBuffer::Iterator object */ - bool isEmpty() const; + bool isEmpty() const throw(); /** Counts the number of events in the buffer. @@ -85,7 +85,7 @@ public: the events, so you might prefer to call isEmpty() if that's all you need to know. */ - int getNumEvents() const; + int getNumEvents() const throw(); /** Adds an event to the buffer. @@ -99,7 +99,7 @@ public: To retrieve events, use a MidiBuffer::Iterator object */ void addEvent (const MidiMessage& midiMessage, - const int sampleNumber); + const int sampleNumber) throw(); /** Adds an event to the buffer from raw midi data. @@ -119,7 +119,7 @@ public: */ void addEvent (const uint8* const rawMidiData, const int maxBytesOfMidiData, - const int sampleNumber); + const int sampleNumber) throw(); /** Adds some events from another buffer to this one. @@ -138,19 +138,19 @@ public: void addEvents (const MidiBuffer& otherBuffer, const int startSample, const int numSamples, - const int sampleDeltaToAdd); + const int sampleDeltaToAdd) throw(); /** Returns the sample number of the first event in the buffer. If the buffer's empty, this will just return 0. */ - int getFirstEventTime() const; + int getFirstEventTime() const throw(); /** Returns the sample number of the last event in the buffer. If the buffer's empty, this will just return 0. */ - int getLastEventTime() const; + int getLastEventTime() const throw(); //============================================================================== /** @@ -166,16 +166,16 @@ public: public: //============================================================================== /** Creates an Iterator for this MidiBuffer. */ - Iterator (const MidiBuffer& buffer); + Iterator (const MidiBuffer& buffer) throw(); /** Destructor. */ - ~Iterator(); + ~Iterator() throw(); //============================================================================== /** Repositions the iterator so that the next event retrieved will be the first one whose sample position is at greater than or equal to the given position. */ - void setNextSamplePosition (const int samplePosition); + void setNextSamplePosition (const int samplePosition) throw(); /** Retrieves a copy of the next event from the buffer. @@ -186,7 +186,7 @@ public: the end of the buffer */ bool getNextEvent (MidiMessage& result, - int& samplePosition); + int& samplePosition) throw(); /** Retrieves the next event from the buffer. @@ -202,7 +202,7 @@ public: */ bool getNextEvent (const uint8* &midiData, int& numBytesOfMidiData, - int& samplePosition); + int& samplePosition) throw(); //============================================================================== juce_UseDebuggingNewOperator @@ -223,7 +223,7 @@ private: friend class MidiBuffer::Iterator; int bytesUsed; - uint8* findEventAfter (uint8* d, const int samplePosition) const; + uint8* findEventAfter (uint8* d, const int samplePosition) const throw(); }; diff --git a/src/juce_appframework/audio/midi/juce_MidiMessage.cpp b/src/juce_appframework/audio/midi/juce_MidiMessage.cpp index 68c7c3be53..6b80406a46 100644 --- a/src/juce_appframework/audio/midi/juce_MidiMessage.cpp +++ b/src/juce_appframework/audio/midi/juce_MidiMessage.cpp @@ -100,7 +100,7 @@ MidiMessage::MidiMessage (const uint8* const d, memcpy (data, d, dataSize); // check that the length matches the data.. - jassert (size > 3 || getMessageLengthFromFirstByte (*d) == size); + jassert (size > 3 || *d >= 0xf0 || getMessageLengthFromFirstByte (*d) == size); } MidiMessage::MidiMessage (const int byte1, @@ -473,6 +473,7 @@ const MidiMessage MidiMessage::controllerEvent (const int channel, const int controllerType, const int value) throw() { + // the channel must be between 1 and 16 inclusive jassert (channel > 0 && channel <= 16); return MidiMessage (0xb0 | jlimit (0, 15, channel - 1),