1797
1797
return extensions.masterTunePitchDelta;
1800
MidiEvent::~MidiEvent() {
1801
if (sysexData != NULL) {
1806
void MidiEvent::setShortMessage(Bit32u useShortMessageData, Bit32u useTimestamp) {
1807
if (sysexData != NULL) {
1810
shortMessageData = useShortMessageData;
1811
timestamp = useTimestamp;
1816
void MidiEvent::setSysex(const Bit8u *useSysexData, Bit32u useSysexLength, Bit32u useTimestamp) {
1817
if (sysexData != NULL) {
1820
shortMessageData = 0;
1821
timestamp = useTimestamp;
1822
sysexLength = useSysexLength;
1823
Bit8u *dstSysexData = new Bit8u[sysexLength];
1824
sysexData = dstSysexData;
1825
memcpy(dstSysexData, useSysexData, sysexLength);
1828
MidiEventQueue::MidiEventQueue(Bit32u useRingBufferSize) : ringBuffer(new MidiEvent[useRingBufferSize]), ringBufferMask(useRingBufferSize - 1) {
1829
memset(ringBuffer, 0, useRingBufferSize * sizeof(MidiEvent));
1800
/** Defines an interface of a class that maintains storage of variable-sized data of SysEx messages. */
1801
class MidiEventQueue::SysexDataStorage {
1803
static MidiEventQueue::SysexDataStorage &create(Bit32u storageBufferSize);
1805
virtual ~SysexDataStorage() {}
1806
virtual Bit8u *allocate(Bit32u sysexLength) = 0;
1807
virtual void reclaimUnused(const Bit8u *sysexData, Bit32u sysexLength) = 0;
1808
virtual void dispose(const Bit8u *sysexData, Bit32u sysexLength) = 0;
1811
/** Storage space for SysEx data is allocated dynamically on demand and is disposed lazily. */
1812
class DynamicSysexDataStorage : public MidiEventQueue::SysexDataStorage {
1814
Bit8u *allocate(Bit32u sysexLength) {
1815
return new Bit8u[sysexLength];
1818
void reclaimUnused(const Bit8u *, Bit32u) {}
1820
void dispose(const Bit8u *sysexData, Bit32u) {
1826
* SysEx data is stored in a preallocated buffer, that makes this kind of storage safe
1827
* for use in a realtime thread. Additionally, the space retained by a SysEx event,
1828
* that has been processed and thus is no longer necessary, is disposed instantly.
1830
class BufferedSysexDataStorage : public MidiEventQueue::SysexDataStorage {
1832
explicit BufferedSysexDataStorage(Bit32u useStorageBufferSize) :
1833
storageBuffer(new Bit8u[useStorageBufferSize]),
1834
storageBufferSize(useStorageBufferSize),
1839
~BufferedSysexDataStorage() {
1840
delete[] storageBuffer;
1843
Bit8u *allocate(Bit32u sysexLength) {
1844
Bit32u myStartPosition = startPosition;
1845
Bit32u myEndPosition = endPosition;
1847
// When the free space isn't contiguous, the data is allocated either right after the end position
1848
// or at the buffer beginning, wherever it fits.
1849
if (myStartPosition > myEndPosition) {
1850
if (myStartPosition - myEndPosition <= sysexLength) return NULL;
1851
} else if (storageBufferSize - myEndPosition < sysexLength) {
1852
// There's not enough free space at the end to place the data block.
1853
if (myStartPosition == myEndPosition) {
1854
// The buffer is empty -> reset positions to the buffer beginning.
1855
if (storageBufferSize <= sysexLength) return NULL;
1856
if (myStartPosition != 0) {
1857
myStartPosition = 0;
1858
startPosition = myStartPosition;
1860
} else if (myStartPosition <= sysexLength) return NULL;
1863
endPosition = myEndPosition + sysexLength;
1864
return storageBuffer + myEndPosition;
1867
void reclaimUnused(const Bit8u *sysexData, Bit32u sysexLength) {
1868
if (sysexData == NULL) return;
1869
Bit32u allocatedPosition = startPosition;
1870
if (storageBuffer + allocatedPosition == sysexData) {
1871
startPosition = allocatedPosition + sysexLength;
1872
} else if (storageBuffer == sysexData) {
1873
// Buffer wrapped around.
1874
startPosition = sysexLength;
1878
void dispose(const Bit8u *, Bit32u) {}
1881
Bit8u * const storageBuffer;
1882
const Bit32u storageBufferSize;
1884
volatile Bit32u startPosition;
1885
volatile Bit32u endPosition;
1888
MidiEventQueue::SysexDataStorage &MidiEventQueue::SysexDataStorage::create(Bit32u storageBufferSize) {
1889
if (storageBufferSize > 0) {
1890
return *new BufferedSysexDataStorage(storageBufferSize);
1892
return *new DynamicSysexDataStorage;
1896
MidiEventQueue::MidiEventQueue(Bit32u useRingBufferSize, Bit32u storageBufferSize) :
1897
sysexDataStorage(SysexDataStorage::create(storageBufferSize)),
1898
ringBuffer(new MidiEvent[useRingBufferSize]), ringBufferMask(useRingBufferSize - 1)
1900
for (Bit32u i = 0; i <= ringBufferMask; i++) {
1901
ringBuffer[i].sysexData = NULL;
1833
1906
MidiEventQueue::~MidiEventQueue() {
1907
for (Bit32u i = 0; i <= ringBufferMask; i++) {
1908
volatile MidiEvent ¤tEvent = ringBuffer[endPosition];
1909
sysexDataStorage.dispose(currentEvent.sysexData, currentEvent.sysexLength);
1834
1911
delete[] ringBuffer;
1842
1919
bool MidiEventQueue::pushShortMessage(Bit32u shortMessageData, Bit32u timestamp) {
1843
1920
Bit32u newEndPosition = (endPosition + 1) & ringBufferMask;
1844
// Is ring buffer full?
1921
// If ring buffer is full, bail out.
1845
1922
if (startPosition == newEndPosition) return false;
1846
ringBuffer[endPosition].setShortMessage(shortMessageData, timestamp);
1923
volatile MidiEvent &newEvent = ringBuffer[endPosition];
1924
sysexDataStorage.dispose(newEvent.sysexData, newEvent.sysexLength);
1925
newEvent.sysexData = NULL;
1926
newEvent.shortMessageData = shortMessageData;
1927
newEvent.timestamp = timestamp;
1847
1928
endPosition = newEndPosition;
1851
1932
bool MidiEventQueue::pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp) {
1852
1933
Bit32u newEndPosition = (endPosition + 1) & ringBufferMask;
1853
// Is ring buffer full?
1934
// If ring buffer is full, bail out.
1854
1935
if (startPosition == newEndPosition) return false;
1855
ringBuffer[endPosition].setSysex(sysexData, sysexLength, timestamp);
1936
volatile MidiEvent &newEvent = ringBuffer[endPosition];
1937
sysexDataStorage.dispose(newEvent.sysexData, newEvent.sysexLength);
1938
Bit8u *dstSysexData = sysexDataStorage.allocate(sysexLength);
1939
if (dstSysexData == NULL) return false;
1940
memcpy(dstSysexData, sysexData, sysexLength);
1941
newEvent.sysexData = dstSysexData;
1942
newEvent.sysexLength = sysexLength;
1943
newEvent.timestamp = timestamp;
1856
1944
endPosition = newEndPosition;
1860
const MidiEvent *MidiEventQueue::peekMidiEvent() {
1948
const volatile MidiEventQueue::MidiEvent *MidiEventQueue::peekMidiEvent() {
1861
1949
return isEmpty() ? NULL : &ringBuffer[startPosition];
1864
1952
void MidiEventQueue::dropMidiEvent() {
1865
// Is ring buffer empty?
1866
if (startPosition != endPosition) {
1867
startPosition = (startPosition + 1) & ringBufferMask;
1871
bool MidiEventQueue::isFull() const {
1872
return startPosition == ((endPosition + 1) & ringBufferMask);
1953
if (isEmpty()) return;
1954
volatile MidiEvent &unusedEvent = ringBuffer[startPosition];
1955
sysexDataStorage.reclaimUnused(unusedEvent.sysexData, unusedEvent.sysexLength);
1956
startPosition = (startPosition + 1) & ringBufferMask;
1875
1959
bool MidiEventQueue::isEmpty() const {