diff options
Diffstat (limited to 'src/midiio')
65 files changed, 20406 insertions, 0 deletions
diff --git a/src/midiio/include/Array.cpp b/src/midiio/include/Array.cpp new file mode 100644 index 0000000..044ed2d --- /dev/null +++ b/src/midiio/include/Array.cpp @@ -0,0 +1,378 @@ +// +// Copyright 1997-1999 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed Feb 5 19:42:53 PST 1997 +// Last Modified: Sun May 11 20:41:28 GMT-0800 1997 +// Last Modified: Wed Jul 7 11:44:50 PDT 1999 (added setAll() function) +// Filename: ...sig/maint/code/base/Array/Array.cpp +// Web Address: http://sig.sapp.org/src/sigBase/Array.cpp +// Syntax: C++ +// +// Description: An array which can grow dynamically. Array is derived from +// the Collection class and adds various mathematical operators +// to the Collection class. The Array template class is used for +// storing numbers of any type which can be added, multiplied +// and divided into one another. +// + +#ifndef _ARRAY_CPP_INCLUDED +#define _ARRAY_CPP_INCLUDED + +#include "Array.h" +#include <iostream> +#include <stdlib.h> + + +////////////////////////////// +// +// Array::Array +// + +template<class type> +Array<type>::Array(void) : Collection<type>(4) { } + +template<class type> +Array<type>::Array(int arraySize) : Collection<type>(arraySize) { } + +template<class type> +Array<type>::Array(Array<type>& anArray) : Collection<type>(anArray) { } + +template<class type> +Array<type>::Array(int arraySize, type *anArray) : + Collection<type>(arraySize, anArray) { } + + + + +////////////////////////////// +// +// Array::~Array +// + +template<class type> +Array<type>::~Array() { } + + + +////////////////////////////// +// +// Array::setAll -- sets the contents of each element to the +// specified value +// + +template<class type> +void Array<type>::setAll(type aValue) { + for (int i=0; i<getSize(); i++) { + array[i] = aValue; + } +} + + + +////////////////////////////// +// +// Array::sum +// + +template<class type> +type Array<type>::sum(void) { + type theSum = 0; + for (int i=0; i<getSize(); i++) { + theSum += array[i]; + } + return theSum; +} + +template<class type> +type Array<type>::sum(int loIndex, int hiIndex) { + type theSum = 0; + for (int i=loIndex; i<=hiIndex; i++) { + theSum += array[i]; + } + return theSum; +} + + + +////////////////////////////// +// +// Array::zero(-1, -1) +// + +template<class type> +void Array<type>::zero(int minIndex, int maxIndex) { + if (size == 0) return; + if (minIndex == -1) minIndex = 0; + if (maxIndex == -1) maxIndex = size-1; + + if (minIndex < 0 || maxIndex < 0 || minIndex > maxIndex || + maxIndex >= size) { + cerr << "Error in zero function: min = " << minIndex + << " max = " << maxIndex << " size = " << size << endl; + exit(1); + } + + for (int i=minIndex; i<=maxIndex; i++) { + array[i] = 0; + } +} + + +//////////////////////////////////////////////////////////////////////////// +// +// operators +// + + +template<class type> +int Array<type>::operator==(const Array<type>& aArray) { + if (getSize() != aArray.getSize()) { + return 0; + } + Array<type>& t = *this; + int i; + for (i=0; i<getSize(); i++) { + if (t[i] != aArray[i]) { + return 0; + } + } + return 1; +} + + + +////////////////////////////// +// +// Array::operator= +// + +template<class type> +Array<type>& Array<type>::operator=(const Array<type>& anArray) { + if (allocSize < anArray.size) { + if (allocSize != 0) { + delete [] array; + } + allocSize = anArray.size; + size = anArray.size; + array = new type[size]; + allowGrowthQ = anArray.allowGrowthQ; + growthAmount = anArray.growthAmount; + maxSize = anArray.maxSize; + } + size = anArray.size; + for (int i=0; i<size; i++) { + array[i] = anArray.array[i]; + } + + return *this; +} + + + +////////////////////////////// +// +// Array::operator+= +// + +template<class type> +Array<type>& Array<type>::operator+=(const Array<type>& anArray) { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + for (int i=0; i<size; i++) { + array[i] += anArray.array[i]; + } + + return *this; +} + + + +////////////////////////////// +// +// Array::operator+ +// + +template<class type> +Array<type> Array<type>::operator+(const Array<type>& anArray) const { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + Array<type> bArray(*this); + bArray += anArray; + return bArray; +} + + +template<class type> +Array<type> Array<type>::operator+(type aNumber) const { + Array<type> anArray(*this); + for (int i=0; i<size; i++) { + anArray[i] += aNumber; + } + return anArray; +} + + + +////////////////////////////// +// +// Array::operator-= +// + +template<class type> +Array<type>& Array<type>::operator-=(const Array<type>& anArray) { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + for (int i=0; i<size; i++) { + array[i] -= anArray.array[i]; + } + + return *this; +} + + + +////////////////////////////// +// +// Array::operator- +// + +template<class type> +Array<type> Array<type>::operator-(const Array<type>& anArray) const { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + Array<type> bArray(*this); + bArray -= anArray; + return bArray; +} + + +template<class type> +Array<type> Array<type>::operator-(void) const { + Array<type> anArray(*this); + for (int i=0; i<size; i++) { + anArray[i] = -anArray[i]; + } + return anArray; +} + +template<class type> +Array<type> Array<type>::operator-(type aNumber) const { + Array<type> anArray(*this); + for (int i=0; i<size; i++) { + anArray[i] -= aNumber; + } + return anArray; +} + + + +////////////////////////////// +// +// Array::operator*= +// + +template<class type> +Array<type>& Array<type>::operator*=(const Array<type>& anArray) { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + for (int i=0; i<size; i++) { + array[i] *= anArray.array[i]; + } + + return *this; +} + + + +////////////////////////////// +// +// Array::operator* +// + +template<class type> +Array<type> Array<type>::operator*(const Array<type>& anArray) const { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + Array<type> bArray(*this); + bArray *= anArray; + return bArray; +} + + +template<class type> +Array<type> Array<type>::operator*(type aNumber) const { + Array<type> anArray(*this); + for (int i=0; i<size; i++) { + anArray[i] *= aNumber; + } + return anArray; +} + +////////////////////////////// +// +// Array::operator/= +// + +template<class type> +Array<type>& Array<type>::operator/=(const Array<type>& anArray) { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + for (int i=0; i<size; i++) { + array[i] /= anArray.array[i]; + } + + return *this; +} + +////////////////////////////// +// +// Array::operator/ +// + +template<class type> +Array<type> Array<type>::operator/(const Array<type>& anArray) const { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + Array<type> bArray(*this); + bArray /= anArray; + return bArray; +} + + +#endif /* _ARRAY_CPP_INCLUDED */ + + + +// md5sum: 8f52a167c93f51702ce316204fd6e722 - Array.cpp =css= 20030102 diff --git a/src/midiio/include/Array.h b/src/midiio/include/Array.h new file mode 100644 index 0000000..75e08eb --- /dev/null +++ b/src/midiio/include/Array.h @@ -0,0 +1,67 @@ +// +// Copyright 1997-1999 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed Feb 5 19:42:53 PST 1997 +// Last Modified: Sun May 11 20:33:13 GMT-0800 1997 +// Last Modified: Wed Jul 7 11:44:50 PDT 1999 (added setAll() function) +// Last Modified: Mon Jul 29 22:08:32 PDT 2002 (added operator==) +// Filename: ...sig/maint/code/base/Array/Array.h +// Web Address: http://sig.sapp.org/include/sigBase/Array.h +// Documentation: http://sig.sapp.org/doc/classes/Array +// Syntax: C++ +// +// Description: An array which can grow dynamically. Array is derived from +// the Collection class and adds various mathematical operators +// to the Collection class. The Array template class is used for +// storing numbers of any type which can be added, multiplied +// and divided into one another. +// + +#ifndef _ARRAY_H_INCLUDED +#define _ARRAY_H_INCLUDED + +#include "Collection.h" + + +template<class type> +class Array : public Collection<type> { + public: + Array (void); + Array (int arraySize); + Array (Array<type>& aArray); + Array (int arraySize, type *anArray); + ~Array (); + + void setAll (type aValue); + type sum (void); + type sum (int lowIndex, int hiIndex); + void zero (int minIndex = -1, int maxIndex = -1); + + int operator== (const Array<type>& aArray); + Array<type>& operator= (const Array<type>& aArray); + Array<type>& operator+= (const Array<type>& aArray); + Array<type>& operator-= (const Array<type>& aArray); + Array<type>& operator*= (const Array<type>& aArray); + Array<type>& operator/= (const Array<type>& aArray); + + Array<type> operator+ (const Array<type>& aArray) const; + Array<type> operator+ (type aNumber) const; + Array<type> operator- (const Array<type>& aArray) const; + Array<type> operator- (void) const; + + Array<type> operator- (type aNumber) const; + Array<type> operator* (const Array<type>& aArray) const; + Array<type> operator* (type aNumber) const; + Array<type> operator/ (const Array<type>& aArray) const; +}; + + +#include "Array.cpp" /* necessary for templates */ + + + +#endif /* _ARRAY_H_INCLUDED */ + + + +// md5sum: 09d1b1f8e70ecde53f484548e48f33c3 - Array.h =css= 20030102 diff --git a/src/midiio/include/CircularBuffer.cpp b/src/midiio/include/CircularBuffer.cpp new file mode 100644 index 0000000..9f4aca6 --- /dev/null +++ b/src/midiio/include/CircularBuffer.cpp @@ -0,0 +1,291 @@ +// +// Copyright 1997-1998 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 19 December 1997 +// Last Modified: Wed Jan 21 23:16:54 GMT-0800 1998 +// Filename: ...sig/maint/code/base/CircularBuffer/CircularBuffer.cpp +// Web Address: http://sig.sapp.org/src/sigBase/CircularBuffer.cpp +// Syntax: C++ +// +// Description: A Circular buffer designed to handle MIDI input, +// but able to store any type of object. Elements +// can be read out of the buffer in two ways. +// (1) from a read pointer which extracts the +// elements in order by following the write pointer, +// and (2) from an index operator related to the +// write pointer's location, for example, +// object[0] is the last value written into the +// buffer and object[-1] (or object[1]) is the +// item written just before that. +// +// + +#ifndef _CIRCULARBUFFER_CPP_INCLUDED +#define _CIRCULARBUFFER_CPP_INCLUDED + +#include "CircularBuffer.h" +#include <stdlib.h> +#include <iostream> + + +////////////////////////////// +// +// CircularBuffer::CircularBuffer -- Constructor. +// + +template<class type> +CircularBuffer<type>::CircularBuffer(void) { + size = 0; + buffer = NULL; + reset(); +} + + +template<class type> +CircularBuffer<type>::CircularBuffer(int maxElements) { + if (maxElements < 0) { + std::cerr << "Error: cannot have a negative number of elements: " + << maxElements << std::endl; + exit(1); + } + if (maxElements == 0) { + size = 0; + buffer = NULL; + reset(); + } else { + size = maxElements; + buffer = new type[maxElements]; + reset(); + } +} + + +template<class type> +CircularBuffer<type>::CircularBuffer(const CircularBuffer<type>& anotherBuffer) { + size = anotherBuffer.size; + if (getSize() == 0) { + buffer = NULL; + reset(); + } else { + buffer = new type[getSize()]; + writeIndex = anotherBuffer.writeIndex; + readIndex = anotherBuffer.readIndex; + itemCount = anotherBuffer.itemCount; + for (int i=0; i<getSize(); i++) { + buffer[i] = anotherBuffer.buffer[i]; + } + } +} + + + +////////////////////////////// +// +// CircularBuffer::~CircularBuffer -- Destructor. +// deallocates buffer memory. +// + +template<class type> +CircularBuffer<type>::~CircularBuffer() { + if (buffer != NULL) { + delete [] buffer; + } +} + + + +////////////////////////////// +// +// CircularBuffer::capacity -- returns the number of items which +// can be added to the buffer. Returns a positive number +// if the buffer has empty locations available. Returns 0 if the +// buffer is 100% full. Returns a negative number if the +// buffer has overflowed. + +template<class type> +int CircularBuffer<type>::capacity(void) const { + return getSize() - getCount(); +} + + + +////////////////////////////// +// +// CircularBuffer::extract -- reads the next value from the buffer. +// + +template<class type> +type CircularBuffer<type>::extract(void) { + itemCount--; + if (itemCount < 0) { + std::cerr << "Error: no elements in buffer to extract." << std::endl; + exit(1); + } + increment(readIndex); + return buffer[readIndex]; +} + + + +////////////////////////////// +// +// CircularBuffer::getCount -- returns the number of elements +// between the write index and the read index. +// + +template<class type> +int CircularBuffer<type>::getCount(void) const { + return itemCount; +} + + + +////////////////////////////// +// +// CircularBuffer::getSize -- returns the allocated size of the buffer. +// + +template<class type> +int CircularBuffer<type>::getSize(void) const { + return size; +} + + + +////////////////////////////// +// +// CircularBuffer::insert -- add an element to the circular buffer +// + +template<class type> +void CircularBuffer<type>::insert(const type& anItem) { + itemCount++; + increment(writeIndex); + buffer[writeIndex] = anItem; +} + + + +////////////////////////////// +// +// CircularBuffer::operator[] -- access an element relative to the +// currently written element +// + +template<class type> +type& CircularBuffer<type>::operator[](int index) { + if (buffer == NULL) { + std::cerr << "Error: buffer has no allocated space" << std::endl; + exit(1); + } + int realIndex = (index < 0) ? -index : index; + if (realIndex >= getSize()) { + std::cerr << "Error: Invalid access: " << realIndex << ", maximum is " + << getSize()-1 << std::endl; + exit(1); + } + realIndex = writeIndex - realIndex; + + // should need to go through this loop a max of one time: + while (realIndex < 0) { + realIndex += getSize(); + } + + return buffer[realIndex]; +} + + + +////////////////////////////// +// +// CircularBuffer::read -- an alias for the extract function. +// + +template<class type> +type CircularBuffer<type>::read(void) { + return extract(); +} + + + +////////////////////////////// +// +// CircularBuffer::reset -- throws out all previous data and +// sets the read/write/count to initial values. The size +// data variable must be valid before this function is +// called. +// + +template<class type> +void CircularBuffer<type>::reset(void) { + readIndex = writeIndex = getSize() - 1; + itemCount = 0; +} + + + +////////////////////////////// +// +// CircularBuffer::setSize -- warning: will throw out all previous data +// stored in buffer. +// + +template<class type> +void CircularBuffer<type>::setSize(int aSize) { + if (aSize < 0) { + std::cerr << "Error: cannot have a negative buffer size: " << aSize << std::endl; + exit(1); + } + if (buffer != NULL) { + delete [] buffer; + } + + if (aSize == 0) { + size = aSize; + buffer = NULL; + reset(); + } else { + size = aSize; + buffer = new type[aSize]; + reset(); + } +} + + + +////////////////////////////// +// +// CircularBuffer::write -- an alias for the insert function. +// + +template<class type> +void CircularBuffer<type>::write(const type& anElement) { + write(anElement); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + +////////////////////////////// +// +// CircularBuffer::increment -- adds one to specified index and +// will automatically wrap the index when it gets too large. +// + +template<class type> +void CircularBuffer<type>::increment(int& index) { + index++; + if (index >= getSize()) { + index = 0; + } +} + + +#endif /* _CIRCULARBUFFER_CPP_INCLUDED */ + + + +// md5sum: 31b2e8d6efe7398a12ddb0a1b5680ca2 - CircularBuffer.cpp =css= 20030102 diff --git a/src/midiio/include/CircularBuffer.h b/src/midiio/include/CircularBuffer.h new file mode 100644 index 0000000..6bb3071 --- /dev/null +++ b/src/midiio/include/CircularBuffer.h @@ -0,0 +1,66 @@ +// +// Copyright 1997-1998 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 19 December 1997 +// Last Modified: Wed Jan 21 23:08:13 GMT-0800 1998 +// Filename: ...sig/maint/code/base/CircularBuffer/CircularBuffer.h +// Web Address: http://sig.sapp.org/include/sigBase/CircularBuffer.cpp +// Documentation: http://sig.sapp.org/doc/classes/CircularBuffer +// Syntax: C++ +// +// Description: A Circular buffer designed to handle MIDI input, +// but able to store any type of object. Elements +// can be read out of the buffer in two ways. +// (1) from a read pointer which extracts the +// elements in order by following the write pointer, +// and (2) from an index operator related to the +// write pointer's location, for example, +// object[0] is the last value written into the +// buffer and object[-1] (or object[1]) is the +// item written just before that. +// + +#ifndef _CIRCULARBUFFER_H_INCLUDED +#define _CIRCULARBUFFER_H_INCLUDED + + +template<class type> +class CircularBuffer { + public: + CircularBuffer (void); + CircularBuffer (int maxElements); + CircularBuffer (const CircularBuffer<type>& + anotherBuffer); + ~CircularBuffer (); + + int capacity (void) const; + type extract (void); + int getCount (void) const; + int getSize (void) const; + void insert (const type& aMessage); + type& operator[] (int index); + type read (void); + void reset (void); + void setSize (int aSize); + void write (const type& aMessage); + + protected: + type* buffer; + int size; + int writeIndex; + int readIndex; + int itemCount; + + void increment (int& index); +}; + + +#include "CircularBuffer.cpp" + + + +#endif /* _CIRCULARBUFFER_H_INCLUDED */ + + + +// md5sum: 2857693ec37fdcb6df09db479faf110b - CircularBuffer.h =css= 20030102 diff --git a/src/midiio/include/Collection.cpp b/src/midiio/include/Collection.cpp new file mode 100644 index 0000000..74eef16 --- /dev/null +++ b/src/midiio/include/Collection.cpp @@ -0,0 +1,355 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed Feb 5 19:42:53 PST 1997 +// Last Modified: Wed Apr 23 22:08:34 GMT-0800 1997 +// Last Modified: Fri Sep 14 15:50:52 PDT 2001 (added last() function) +// Filename: ...sig/maint/code/base/Collection/Collection.cpp +// Web Address: http://sig.sapp.org/src/sigBase/Collection.cpp +// Syntax: C++ +// +// Description: A dynamic array which can grow as necessary. +// This class can hold any type of item, but the +// derived Array class is specifically for collections +// of numbers. +// + +#ifndef _COLLECTION_CPP_INCLUDED +#define _COLLECTION_CPP_INCLUDED + +#include "Collection.h" +#include <iostream> +#include <stdlib.h> + + +////////////////////////////// +// +// Collection::Collection +// + +template<class type> +Collection<type>::Collection(void) { + allocSize = 0; + size = 0; + array = NULL; + allowGrowthQ = 0; + growthAmount = 8; + maxSize = 0; +} + +template<class type> +Collection<type>::Collection(int arraySize) { + array = new type[arraySize]; + size = arraySize; + allocSize = arraySize; + allowGrowthQ = 0; + growthAmount = arraySize; + maxSize = 0; +} + + +template<class type> +Collection<type>::Collection(int arraySize, type *aCollection) { + size = arraySize; + allocSize = arraySize; + array = new type[size]; + for (int i=0; i<size; i++) { + array[i] = aCollection[i]; + } + growthAmount = arraySize; + allowGrowthQ = 0; + maxSize = 0; +} + + +template<class type> +Collection<type>::Collection(Collection<type>& aCollection) { + size = aCollection.size; + allocSize = size; + array = new type[size]; + for (int i=0; i<size; i++) { + array[i] = aCollection.array[i]; + } + allowGrowthQ = aCollection.allowGrowthQ; + growthAmount = aCollection.growthAmount; + maxSize = aCollection.maxSize; +} + + + +////////////////////////////// +// +// Collection::~Collection +// + +template<class type> +Collection<type>::~Collection() { + if (getAllocSize() != 0) { + delete [] array; + } +} + + + +////////////////////////////// +// +// Collection::allowGrowth +// default value: status = 1 +// + +template<class type> +void Collection<type>::allowGrowth(int status) { + if (status == 0) { + allowGrowthQ = 0; + } else { + allowGrowthQ = 1; + } +} + + + +////////////////////////////// +// +// Collection::append +// + +template<class type> +void Collection<type>::append(type& element) { + if (size == getAllocSize()) { + grow(); + } + array[size] = element; + size++; +} + +template<class type> +void Collection<type>::appendcopy(type element) { + if (size == getAllocSize()) { + grow(); + } + array[size] = element; + size++; +} + +template<class type> +void Collection<type>::append(type *element) { + if (size == getAllocSize()) { + grow(); + } + array[size] = *element; + size++; +} + + + +////////////////////////////// +// +// Collection::grow +// default parameter: growamt = -1 +// + +template<class type> +void Collection<type>::grow(long growamt) { + allocSize += growamt > 0 ? growamt : growthAmount; + if (maxSize != 0 && getAllocSize() > maxSize) { + std::cerr << "Error: Maximum size allowed for array exceeded." << std::endl; + exit(1); + } + + type *temp = new type[getAllocSize()]; + for (int i=0; i<size; i++) { + temp[i] = array[i]; + } + array = temp; +} + + + +////////////////////////////// +// +// Collection::pointer +// + +template<class type> +type* Collection<type>::pointer(void) { + return array; +} + + + +////////////////////////////// +// +// Collection::getBase +// + +template<class type> +type* Collection<type>::getBase(void) { + return array; +} + + + +////////////////////////////// +// +// Collection::getAllocSize +// + +template<class type> +long Collection<type>::getAllocSize(void) const { + return allocSize; +} + + + +////////////////////////////// +// +// Collection::getSize -- +// + +template<class type> +long Collection<type>::getSize(void) const { + return size; +} + + + +////////////////////////////// +// +// Collection::last -- +// + +template<class type> +type& Collection<type>::last(void) { + return array[getSize()-1]; +} + + + +////////////////////////////// +// +// Collection::setAllocSize +// + +template<class type> +void Collection<type>::setAllocSize(long aSize) { + if (aSize < getSize()) { + std::cerr << "Error: cannot set allocated size smaller than actual size." + << std::endl; + exit(1); + } + + if (aSize <= getAllocSize()) { + shrinkTo(aSize); + } else { + grow(aSize-getAllocSize()); + size = aSize; + } +} + + + +////////////////////////////// +// +// Collection::setGrowth +// default parameter: growth = -1 +// + +template<class type> +void Collection<type>::setGrowth(long growth) { + if (growth > 0) { + growthAmount = growth; + } +} + + + +////////////////////////////// +// +// Collection::setSize +// + +template<class type> +void Collection<type>::setSize(long newSize) { + if (newSize <= getAllocSize()) { + size = newSize; + } else { + grow(newSize-getAllocSize()); + size = newSize; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// Collection operators +// + +////////////////////////////// +// +// Collection::operator[] +// + +template<class type> +type& Collection<type>::operator[](int elementIndex) { + if (allowGrowthQ && elementIndex == size) { + if (size == getAllocSize()) { + grow(); + } + size++; + } else if (elementIndex >= size) { + std::cerr << "Error: accessing invalid array location " + << elementIndex + << " Maximum is " << size-1 << std::endl; + exit(1); + } + return array[elementIndex]; +} + + +////////////////////////////// +// +// Collection::operator[] const +// + +template<class type> +type Collection<type>::operator[](int elementIndex) const { + if (elementIndex >= size) { + std::cerr << "Error: accessing invalid array location " + << elementIndex + << " Maximum is " << size-1 << std::endl; + exit(1); + } + return array[elementIndex]; +} + +////////////////////////////// +// +// shrinkTo +// + +template<class type> +void Collection<type>::shrinkTo(long aSize) { + if (aSize < getSize()) { + exit(1); + } + + type *temp = new type[aSize]; + for (int i=0; i<size; i++) { + temp[i] = array[i]; + } + delete [] array; + array = temp; + + allocSize = aSize; + if (size > allocSize) { + size = allocSize; + } +} + + +#endif /* _COLLECTION_CPP_INCLUDED */ + + + +// md5sum: 9929fee30b1bede4305e1fb46303ddc1 - Collection.cpp =css= 20030102 diff --git a/src/midiio/include/Collection.h b/src/midiio/include/Collection.h new file mode 100644 index 0000000..6775366 --- /dev/null +++ b/src/midiio/include/Collection.h @@ -0,0 +1,70 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed Feb 5 19:42:53 PST 1997 +// Last Modified: Tue Apr 22 20:28:16 GMT-0800 1997 +// Last Modified: Fri Sep 14 15:50:52 PDT 2001 (added last() function) +// Filename: ...sig/maint/code/base/Collection/Collection.h +// Web Address: http://sig.sapp.org/include/sigBase/Collection.h +// Documentation: http://sig.sapp.org/doc/classes/Collection +// Syntax: C++ +// +// Description: A dynamic array which can grow as necessary. +// This class can hold any type of item, but the +// derived Array class is specifically for collections +// of numbers. +// + +#ifndef _COLLECTION_H_INCLUDED +#define _COLLECTION_H_INCLUDED + + +template<class type> +class Collection { + public: + Collection (void); + Collection (int arraySize); + Collection (int arraySize, type *aCollection); + Collection (Collection<type>& aCollection); + ~Collection (); + + void allowGrowth (int status = 1); + void append (type& element); + void appendcopy (type element); + void append (type* element); + type *getBase (void); + long getAllocSize (void) const; + long getSize (void) const; + type *pointer (void); + void setAllocSize (long aSize); + void setGrowth (long growth); + void setSize (long newSize); + type& operator[] (int arrayIndex); + type operator[] (int arrayIndex) const; + void grow (long growamt = -1); + type& last (void); + + + protected: + long size; // actual array size + long allocSize; // maximum allowable array size + type *array; // where the array data is stored + char allowGrowthQ; // allow/disallow growth + long growthAmount; // number of elements to grow by if index + // element one beyond max size is accessed + long maxSize; // the largest size the array is allowed + // to grow to, if 0, then ignore max + + void shrinkTo (long aSize); +}; + + +#include "Collection.cpp" + + + +#endif /* _COLLECTION_H_INCLUDED */ + + + +// md5sum: 01bec04835c0bd117f40c2bfe51c4abd - Collection.h =css= 20030102 diff --git a/src/midiio/include/FileIO.h b/src/midiio/include/FileIO.h new file mode 100644 index 0000000..fdec5de --- /dev/null +++ b/src/midiio/include/FileIO.h @@ -0,0 +1,148 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Fri May 9 22:30:32 PDT 1997 +// Last Modified: Sun Dec 14 05:26:16 GMT-0800 1997 +// Filename: ...sig/maint/code/base/FileIO/FileIO.h +// Web Address: http://sig.sapp.org/include/sigBase/FileIO.h +// Documentation: http://sig.sapp.org/doc/classes/FileIO +// Syntax: C++ +// +// Description: Derived from the fstream class, this class has +// functions which allow writing binary files in +// both little and big endian formats. Useful for +// writing files such as soundfiles and MIDI files +// which require numbers to be stored in a particular +// endian format. +// + +#ifndef _FILEIO_H_INCLUDED +#define _FILEIO_H_INCLUDED + + +#include <fstream> + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; +typedef unsigned int uint; + +// templates would be nice to use here, but they don't seem +// to work intuitively... + +class FileIO : public std::fstream { + public: + FileIO (void); + FileIO (const char* filename, std::ios::openmode state); + ~FileIO (); + + void readBigEndian (char& aNumber); + void readBigEndian (uchar& aNumber); + void readBigEndian (short& aNumber); + void readBigEndian (ushort& aNumber); + void readBigEndian (long& aNumber); + void readBigEndian (ulong& aNumber); + void readBigEndian (int& aNumber); + void readBigEndian (uint& aNumber); + void readBigEndian (float& aNumber); + void readBigEndian (double& aNumber); + + void readLittleEndian (char& aNumber); + void readLittleEndian (uchar& aNumber); + void readLittleEndian (short& aNumber); + void readLittleEndian (ushort& aNumber); + void readLittleEndian (long& aNumber); + void readLittleEndian (ulong& aNumber); + void readLittleEndian (int& aNumber); + void readLittleEndian (uint& aNumber); + void readLittleEndian (float& aNumber); + void readLittleEndian (double& aNumber); + + void readMachineEndian (char& aNumber); + void readMachineEndian (uchar& aNumber); + void readMachineEndian (short& aNumber); + void readMachineEndian (ushort& aNumber); + void readMachineEndian (long& aNumber); + void readMachineEndian (ulong& aNumber); + void readMachineEndian (int& aNumber); + void readMachineEndian (uint& aNumber); + void readMachineEndian (float& aNumber); + void readMachineEndian (double& aNumber); + + void readNotMachineEndian (char& aNumber); + void readNotMachineEndian (uchar& aNumber); + void readNotMachineEndian (short& aNumber); + void readNotMachineEndian (ushort& aNumber); + void readNotMachineEndian (long& aNumber); + void readNotMachineEndian (ulong& aNumber); + void readNotMachineEndian (int& aNumber); + void readNotMachineEndian (uint& aNumber); + void readNotMachineEndian (float& aNumber); + void readNotMachineEndian (double& aNumber); + + void writeBigEndian (char aNumber); + void writeBigEndian (uchar aNumber); + void writeBigEndian (short aNumber); + void writeBigEndian (ushort aNumber); + void writeBigEndian (long aNumber); + void writeBigEndian (ulong aNumber); + void writeBigEndian (int aNumber); + void writeBigEndian (uint aNumber); + void writeBigEndian (float aNumber); + void writeBigEndian (double aNumber); + + void writeLittleEndian (char aNumber); + void writeLittleEndian (uchar aNumber); + void writeLittleEndian (short aNumber); + void writeLittleEndian (ushort aNumber); + void writeLittleEndian (long aNumber); + void writeLittleEndian (ulong aNumber); + void writeLittleEndian (int aNumber); + void writeLittleEndian (uint aNumber); + void writeLittleEndian (float aNumber); + void writeLittleEndian (double aNumber); + + void writeMachineEndian (char aNumber); + void writeMachineEndian (uchar aNumber); + void writeMachineEndian (short aNumber); + void writeMachineEndian (ushort aNumber); + void writeMachineEndian (long aNumber); + void writeMachineEndian (ulong aNumber); + void writeMachineEndian (int aNumber); + void writeMachineEndian (uint aNumber); + void writeMachineEndian (float aNumber); + void writeMachineEndian (double aNumber); + + void writeNotMachineEndian (char aNumber); + void writeNotMachineEndian (uchar aNumber); + void writeNotMachineEndian (short aNumber); + void writeNotMachineEndian (ushort aNumber); + void writeNotMachineEndian (long aNumber); + void writeNotMachineEndian (ulong aNumber); + void writeNotMachineEndian (int aNumber); + void writeNotMachineEndian (uint aNumber); + void writeNotMachineEndian (float aNumber); + void writeNotMachineEndian (double aNumber); + + protected: + + char flipBytes (char aNumber); + uchar flipBytes (uchar aNumber); + short flipBytes (short aNumber); + ushort flipBytes (ushort aNumber); + long flipBytes (long aNumber); + ulong flipBytes (ulong aNumber); + int flipBytes (int aNumber); + uint flipBytes (uint aNumber); + float flipBytes (float aNumber); + double flipBytes (double aNumber); + +}; + + + +#endif /* _FILEIO_H_INCLUDED */ + + + +// md5sum: 0a146ebe5c6bd0850be973f612827d20 - FileIO.h =css= 20030102 diff --git a/src/midiio/include/MidiFile.h b/src/midiio/include/MidiFile.h new file mode 100644 index 0000000..10794d5 --- /dev/null +++ b/src/midiio/include/MidiFile.h @@ -0,0 +1,108 @@ +// +// Copyright 1999-2000 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Fri Nov 26 14:12:01 PST 1999 +// Last Modified: Fri Dec 2 13:26:44 PST 1999 +// Last Modified: Fri Nov 10 12:13:15 PST 2000 (added some more editing cap.) +// Last Modified: Thu Jan 10 10:03:39 PST 2002 (added allocateEvents()) +// Last Modified: Mon Jun 10 22:43:10 PDT 2002 (added clear()) +// Filename: ...sig/include/sigInfo/MidiFile.h +// Web Address: http://sig.sapp.org/include/sigInfo/MidiFile.h +// Syntax: C++ +// +// Description: A class which can read/write Standard MIDI files. +// MIDI data is stored by track in an array. This +// class is used for example in the MidiPerform class. +// + +#ifndef _MIDIfILE_H_INCLUDED +#define _MIDIfILE_H_INCLUDED + +#include "FileIO.h" +#include "Array.h" +#include "Collection.h" + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; + +#define TIME_STATE_DELTA 0 +#define TIME_STATE_ABSOLUTE 1 + +#define TRACK_STATE_SPLIT 0 +#define TRACK_STATE_JOINED 1 + + +class _MFEvent { + public: + _MFEvent (void); + _MFEvent (int command); + _MFEvent (int command, int param1); + _MFEvent (int command, int param1, int param2); + _MFEvent (int track, int command, int param1, int param2); + _MFEvent (int aTime, int aTrack, int command, int param1, int param2); + ~_MFEvent (); + int time; + int track; + Array<uchar> data; +}; + + + +class MidiFile { + public: + MidiFile (void); + MidiFile (char* aFile); + ~MidiFile (); + + void absoluteTime (void); + int addEvent (int aTrack, int aTime, + Array<uchar>& midiData); + int addTrack (void); + int addTrack (int count); + void allocateEvents (int track, int aSize); + void deltaTime (void); + void deleteTrack (int aTrack); + void erase (void); + void clear (void); + _MFEvent& getEvent (int aTrack, int anIndex); + int getTimeState (void); + int getTrackState (void); + int getTicksPerQuarterNote (void); + int getTrackCount (void); + int getNumTracks (void); + int getNumEvents (int aTrack); + void joinTracks (void); + void mergeTracks (int aTrack1, int aTrack2); + int read (char* aFile); + void setTicksPerQuarterNote (int ticks); + void sortTrack (Collection<_MFEvent>& trackData); + void sortTracks (void); + void splitTracks (void); + int write (const char* aFile); + + protected: + Collection<Collection<_MFEvent>*> events; // midi file events + int ticksPerQuarterNote; // time base of file + int trackCount; // # of tracks in file + int theTrackState; // joined or split + int theTimeState; // absolute or delta + char* readFileName; // read file name + + private: + void extractMidiData (FileIO& inputfile, Array<uchar>& array, + uchar& runningCommand); + ulong extractVlvTime (FileIO& inputfile); + ulong unpackVLV (uchar a, uchar b, uchar c, uchar d, uchar e); + void writeVLValue (long aValue, Array<uchar>& data); +}; + + +int eventcompare(const void* a, const void* b); +std::ostream& operator<<(std::ostream& out, MidiFile& aMidiFile); + +#endif /* _MIDIfILE_H_INCLUDED */ + + + +// md5sum: ff46e64698e2d9e88ebeef3efa9927d0 - MidiFile.h =css= 20030102 diff --git a/src/midiio/include/MidiFileWrite.h b/src/midiio/include/MidiFileWrite.h new file mode 100644 index 0000000..a213fdf --- /dev/null +++ b/src/midiio/include/MidiFileWrite.h @@ -0,0 +1,61 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Mar 15 10:55:56 GMT-0800 1998 +// Last Modified: Sun Mar 15 10:55:56 GMT-0800 1998 +// Filename: ...sig/code/control/MidiFileWrite/MidiFileWrite.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiFileWrite.h +// Syntax: C++ +// +// Description: The MidiFileWrite class will write out a Type 0 MidiFile. +// Used for recording MIDI data streams into Standard +// MIDI files. +// + +#ifndef _MIDIFILEWRITE_INCLUDED +#define _MIDIFILEWRITE_INCLUDED + + +#include "FileIO.h" + + +class MidiFileWrite { + public: + MidiFileWrite (void); + MidiFileWrite (const char* aFilename, int startTime = -1); + ~MidiFileWrite (); + + void close (void); + void setup (const char* aFilename, int startTime = -1); + void start (int startTime = -1); + void writeAbsolute (int aTime, int command, int p1, int p2); + void writeAbsolute (int aTime, int command, int p1); + void writeAbsolute (int aTime, int command); + void writeRaw (uchar aByte); + void writeRaw (uchar aByte, uchar Byte); + void writeRaw (uchar aByte, uchar Byte, uchar cByte); + void writeRaw (uchar aByte, uchar Byte, uchar cByte, + uchar dByte); + void writeRaw (uchar aByte, uchar Byte, uchar cByte, + uchar dByte, uchar eByte); + void writeRaw (uchar* anArray, int arraySize); + void writeRelative (int aTime, int command, int p1, int p2); + void writeRelative (int aTime, int command, int p1); + void writeRelative (int aTime, int command); + void writeVLValue (long aValue); + + + protected: + FileIO *midifile; // file stream for MIDI file + long trackSize; // size count for MIDI track + int lastPlayTime; // for calculating delta times + int openQ; // for checking file status + +}; + + + +#endif /* _MIDIFILEWRITE_INCLUDED */ + + + +// md5sum: 44ac572078bff648d096c7e7867d1b3c - MidiFileWrite.h =css= 20030102 diff --git a/src/midiio/include/MidiIO.h b/src/midiio/include/MidiIO.h new file mode 100644 index 0000000..80c9168 --- /dev/null +++ b/src/midiio/include/MidiIO.h @@ -0,0 +1,58 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 21 December 1997 +// Last Modified: Sun Jan 25 15:44:35 GMT-0800 1998 +// Filename: ...sig/code/control/MidiIO/MidiIO.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiIO.h +// Syntax: C++ +// +// Description: A unified class for MidiInput and MidiOutput that handles +// MIDI input and output connections. The Synthesizer +// and RadioBaton classes are derived from this class. +// + +#ifndef _MIDIIO_H_INCLUDED +#define _MIDIIO_H_INCLUDED + + +#include "MidiInput.h" +#include "MidiOutput.h" + + +class MidiIO : public MidiOutput, public MidiInput { + public: + MidiIO (void); + MidiIO (int outPort, int inPort); + ~MidiIO (); + + void close (void); + void closeInput (void); + void closeOutput (void); + int getChannelInOffset (void) const; + int getChannelOutOffset (void) const; + int getInputPort (void); + int getInputTrace (void); + int getNumInputPorts (void); + int getNumOutputPorts (void); + int getOutputPort (void); + int getOutputTrace (void); + int open (void); + int openInput (void); + int openOutput (void); + void setChannelOffset (int anOffset); + void setInputPort (int aPort); + void setInputTrace (int aState); + void setOutputPort (int aPort); + void setOutputTrace (int aState); + void toggleInputTrace (void); + void toggleOutputTrace (void); + +}; + + + +#endif /* _MIDIIO_H_INCLUDED */ + + + +// md5sum: 9f6122405c4d9e83994457210217ff22 - MidiIO.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort.h b/src/midiio/include/MidiInPort.h new file mode 100644 index 0000000..ac225c4 --- /dev/null +++ b/src/midiio/include/MidiInPort.h @@ -0,0 +1,98 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed Jan 21 22:35:31 GMT-0800 1998 +// Last Modified: Thu Jan 22 23:13:54 GMT-0800 1998 +// Last Modified: Sat Nov 7 16:09:18 PST 1998 +// Last Modified: Tue Jun 29 16:14:50 PDT 1999 (added Sysex input) +// Last Modified: Tue May 23 23:08:44 PDT 2000 (oss/alsa selection added) +// Filename: ...sig/maint/code/control/MidiInPort/MidiInPort.h +// Web Address: http://sig.sapp.org/include/sig/MidiInPort.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of an +// operating-system specific MIDI input method. +// Provides control of all low-level MIDI input +// functionality such that it will work on all +// computers in the same manner. +// + +#ifndef _MIDIINPORT_H_INCLUDED +#define _MIDIINPORT_H_INCLUDED + + +#include "MidiMessage.h" + +#ifdef VISUAL + #define MIDIINPORT MidiInPort_visual + #include "MidiInPort_visual.h" +#elif defined(LINUX) && defined(ALSA) && defined(OSS) + #define MIDIINPORT MidiInPort_linux + #include "MidiInPort_linux.h" +#elif defined(LINUX) && defined(ALSA) && !defined(OSS) + #define MIDIINPORT MidiInPort_alsa + #include "MidiInPort_alsa.h" +#elif defined (LINUX) && defined(OSS) && !defined(ALSA) + #define MIDIINPORT MidiInPort_oss + #include "MidiInPort_oss.h" +#elif defined(LINUX) + #define MIDIINPORT MidiInPort_oss + #include "MidiInPort_oss.h" +#else + #define MIDIINPORT MidiInPort_unsupported + #include "MidiInPort_unsupported.h" +#endif + + +class MidiInPort : protected MIDIINPORT { + public: + MidiInPort (void) : MIDIINPORT() {} + MidiInPort (int aPort, int autoOpen = 1) : + MIDIINPORT(aPort, autoOpen) {} + ~MidiInPort() { } + + void clearSysex(void) { MIDIINPORT::clearSysex(); } + void clearSysex(int buffer) { MIDIINPORT::clearSysex(buffer); } + void close(void) { MIDIINPORT::close(); } + void closeAll(void) { MIDIINPORT::closeAll(); } + MidiMessage extract(void) { return MIDIINPORT::extract(); } + int getBufferSize(void) { return MIDIINPORT::getBufferSize(); } + int getChannelOffset(void) const { + return MIDIINPORT::getChannelOffset(); } + int getCount(void) { return MIDIINPORT::getCount(); } + const char* getName(void) { return MIDIINPORT::getName(); } + static const char* getName(int i) { return MIDIINPORT::getName(i); } + static int getNumPorts(void) { + return MIDIINPORT::getNumPorts(); } + int getPort(void) { return MIDIINPORT::getPort(); } + int getPortStatus(void){ + return MIDIINPORT::getPortStatus(); } + uchar* getSysex(int buffer) { return MIDIINPORT::getSysex(buffer); } + int getSysexSize(int buffer) { return MIDIINPORT::getSysexSize(buffer); } + int getTrace(void) { return MIDIINPORT::getTrace(); } + void insert(const MidiMessage& aMessage) { + MIDIINPORT::insert(aMessage); } + int installSysex(uchar* anArray, int aSize) { + return MIDIINPORT::installSysex(anArray, aSize); } + int open(void) { return MIDIINPORT::open(); } + MidiMessage& operator[](int index) { + return MIDIINPORT::message(index); } + void pause(void) { MIDIINPORT::pause(); } + void setBufferSize(int aSize) { + MIDIINPORT::setBufferSize(aSize); } + void setChannelOffset(int anOffset) { + MIDIINPORT::setChannelOffset(anOffset); } + void setAndOpenPort(int aPort) { setPort(aPort); open(); } + void setPort(int aPort) { MIDIINPORT::setPort(aPort); } + int setTrace(int aState) { + return MIDIINPORT::setTrace(aState); } + void toggleTrace(void) { MIDIINPORT::toggleTrace(); } + void unpause(void) { MIDIINPORT::unpause(); } +}; + + + +#endif /* _MIDIINPORT_H_INCLUDED */ + + + +// md5sum: 96f8a2b4411a356d1b73cd96421b8931 - MidiInPort.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_alsa.h b/src/midiio/include/MidiInPort_alsa.h new file mode 100644 index 0000000..b321600 --- /dev/null +++ b/src/midiio/include/MidiInPort_alsa.h @@ -0,0 +1,107 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun May 14 22:05:27 PDT 2000 +// Last Modified: Sat Oct 13 16:11:24 PDT 2001 (updated for ALSA 0.9) +// Last Modified: Sat Nov 2 20:35:50 PST 2002 (added #ifdef ALSA) +// Filename: ...sig/maint/code/control/MidiInPort/linux/MidiInPort_alsa.h +// Web Address: http://sig.sapp.org/include/sig/MidiInPort_alsa.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux ALSA sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#ifndef _MIDIINPORT_ALSA_H_INCLUDED +#define _MIDIINPORT_ALSA_H_INCLUDED + +#ifdef LINUX +#ifdef ALSA + +#include "MidiMessage.h" +#include "CircularBuffer.h" +#include "Array.h" +#include "Sequencer_alsa.h" +#include "SigTimer.h" +#include <pthread.h> + +typedef unsigned char uchar; +typedef void (*MIDI_Callback_function)(int arrivalPort); + + +class MidiInPort_alsa : public Sequencer_alsa { + public: + MidiInPort_alsa (void); + MidiInPort_alsa (int aPort, int autoOpen = 1); + ~MidiInPort_alsa (); + + void clearSysex (int buffer); + void clearSysex (void); + void close (void); + void closeAll (void); + MidiMessage extract (void); + int getBufferSize (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + uchar* getSysex (int buffer); + int getSysexSize (int buffer); + int getTrace (void); + void insert (const MidiMessage& aMessage); + int installSysex (uchar* anArray, int aSize); + MidiMessage& message (int index); + int open (void); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + static Array<int> threadinitport; + + protected: + int port; // the port to which this object belongs + + static MIDI_Callback_function callbackFunction; + + static int installSysexPrivate (int port, + uchar* anArray, int aSize); + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* trace; // for verifying input + static std::ostream* tracedisplay; // stream for displaying trace + static int numDevices; // number of input ports + static CircularBuffer<MidiMessage>** midiBuffer; // MIDI storage frm ports + static int channelOffset; // channel offset, either 0 or 1 + // not being used right now. + static int* pauseQ; // for adding items to Buffer or not + static SigTimer midiTimer; // for timing MIDI input + static Array<pthread_t> midiInThread; // for MIDI input thread function + static int* sysexWriteBuffer; // for MIDI sysex write location + static Array<uchar>** sysexBuffers; // for MIDI sysex storage + + private: + void deinitialize (void); + void initialize (void); + + + friend void *interpretMidiInputStreamPrivateALSA(void * x); + +}; + + +#endif /* ALSA */ +#endif /* LINUX */ + +#endif /* _MIDIINPORT_ALSA_H_INCLUDED */ + + + +// md5sum: 260a0accd6b08b638a00904c382293bc - MidiInPort_alsa.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_alsa05.h b/src/midiio/include/MidiInPort_alsa05.h new file mode 100644 index 0000000..27af569 --- /dev/null +++ b/src/midiio/include/MidiInPort_alsa05.h @@ -0,0 +1,107 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun May 14 22:05:27 PDT 2000 +// Last Modified: Wed Oct 3 22:28:20 PDT 2001 (frozen for ALSA 0.5) +// Last Modified: Thu Jan 2 18:55:12 PST 2003 (added #ifdef ALSA05) +// Filename: ...sig/maint/code/control/MidiInPort/linux/MidiInPort_alsa05.h +// Web Address: http://sig.sapp.org/include/sig/MidiInPort_alsa05.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux ALSA sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#ifndef _MIDIINPORT_ALSA05_H_INCLUDED +#define _MIDIINPORT_ALSA05_H_INCLUDED + +#ifdef LINUX +#ifdef ALSA05 + +#include "MidiMessage.h" +#include "CircularBuffer.h" +#include "Array.h" +#include "Sequencer_alsa05.h" +#include "SigTimer.h" +#include <pthread.h> + +typedef unsigned char uchar; +typedef void (*MIDI_Callback_function)(int arrivalPort); + + +class MidiInPort_alsa05 : public Sequencer_alsa05 { + public: + MidiInPort_alsa05 (void); + MidiInPort_alsa05 (int aPort, int autoOpen = 1); + ~MidiInPort_alsa05 (); + + void clearSysex (int buffer); + void clearSysex (void); + void close (void); + void closeAll (void); + MidiMessage extract (void); + int getBufferSize (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + uchar* getSysex (int buffer); + int getSysexSize (int buffer); + int getTrace (void); + void insert (const MidiMessage& aMessage); + int installSysex (uchar* anArray, int aSize); + MidiMessage& message (int index); + int open (void); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + static Array<int> threadinitport; + + protected: + int port; // the port to which this object belongs + + static MIDI_Callback_function callbackFunction; + + static int installSysexPrivate (int port, + uchar* anArray, int aSize); + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* trace; // for verifying input + static ostream* tracedisplay; // stream for displaying trace + static int numDevices; // number of input ports + static CircularBuffer<MidiMessage>** midiBuffer; // MIDI storage frm ports + static int channelOffset; // channel offset, either 0 or 1 + // not being used right now. + static int* pauseQ; // for adding items to Buffer or not + static SigTimer midiTimer; // for timing MIDI input + static Array<pthread_t> midiInThread; // for MIDI input thread function + static int* sysexWriteBuffer; // for MIDI sysex write location + static Array<uchar>** sysexBuffers; // for MIDI sysex storage + + private: + void deinitialize (void); + void initialize (void); + + + friend void *interpretMidiInputStreamPrivateALSA05(void * x); + +}; + + +#endif /* ALSA05 */ +#endif /* LINUX */ + +#endif /* _MIDIINPORT_ALSA05_H_INCLUDED */ + + + +// md5sum: 7b85b4a658c6f1d45dc1da7752f25cae - MidiInPort_alsa05.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_linux.h b/src/midiio/include/MidiInPort_linux.h new file mode 100644 index 0000000..589d27a --- /dev/null +++ b/src/midiio/include/MidiInPort_linux.h @@ -0,0 +1,94 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun May 14 22:30:04 PDT 2000 +// Last Modified: Thu May 18 23:36:07 PDT 2000 (added ifdef LINUX lines) +// Last Modified: Sat Nov 2 20:37:49 PST 2002 (added ifdef ALSA OSS) +// Filename: ...sig/maint/code/control/MidiInPort/MidiInPort_linux.h +// Web Address: http://sig.sapp.org/include/sig/MidiInPort_linux.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of an +// operating-system specific MIDI input method. +// Provides control of all low-level MIDI input +// functionality such that it will work on all +// computers in the same manner. +// + +#ifndef _MIDIINPORT_LINUX_H_INCLUDED +#define _MIDIINPORT_LINUX_H_INCLUDED + +#ifdef LINUX +#if defined(ALSA) && defined(OSS) + +#define MIDI_IN_UNKNOWN_SELECT 0 +#define MIDI_IN_OSS_SELECT 1 +#define MIDI_IN_ALSA_SELECT 2 + +#include "MidiInPort_oss.h" +#include "MidiInPort_alsa.h" +#include "MidiInPort_unsupported.h" +#include "MidiMessage.h" + + +class MidiInPort_linux { + public: + MidiInPort_linux(void); + MidiInPort_linux(int aPort, int autoOpen = 1); + ~MidiInPort_linux(); + + void clearSysex (void); + void clearSysex (int buffer); + void close (void); + void closeAll (void); + MidiMessage extract (void); + int getBufferSize (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + uchar* getSysex (int buffer); + int getSysexSize (int buffer); + int getTrace (void); + void insert (const MidiMessage& aMessage); + int installSysex (uchar* anArray, int aSize); + MidiMessage& message (int index); + int open (void); + MidiMessage& operator[] (int index); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setAndOpenPort (int aPort); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + static int getSelect (void); + static int selectOSS (void); + static int selectALSA (void); + static int selectUnknown (void); + + private: + + static int current; // the type of MIDI out selected + static int alsaQ; // boolean for if ALSA is present + static int ossQ; // boolean for if OSS is present + static int objectCount; // keeps track of static variables + + static MidiInPort_oss *oss_input; + static MidiInPort_alsa *alsa_input; + static MidiInPort_unsupported *unknown_input; + + void determineDrivers (void); +}; + +#endif /* ALSA and OSS def */ +#endif /* LINUX def */ + +#endif /* _MIDIINPORT_LINUX_H_INCLUDED */ + + +// md5sum: cc3608fb63ccf222f018efc89a4275f0 - MidiInPort_linux.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_oss.h b/src/midiio/include/MidiInPort_oss.h new file mode 100644 index 0000000..ffa5666 --- /dev/null +++ b/src/midiio/include/MidiInPort_oss.h @@ -0,0 +1,105 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Fri Jan 8 08:33:57 PST 1999 +// Last Modified: Fri Jan 8 08:34:01 PST 1999 +// Last Modified: Tue Jun 29 16:18:02 PDT 1999 (added sysex capability) +// Last Modified: Wed May 10 17:10:05 PDT 2000 (name change from _linux to _oss) +// Filename: ...sig/maint/code/control/MidiInPort/linux/MidiInPort_oss.h +// Web Address: http://sig.sapp.org/include/sig/MidiInPort_oss.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux OSS sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#ifndef _MIDIINPORT_OSS_H_INCLUDED +#define _MIDIINPORT_OSS_H_INCLUDED + +#ifdef LINUX + +#include "MidiMessage.h" +#include "CircularBuffer.h" +#include "Array.h" +#include "Sequencer_oss.h" +#include "SigTimer.h" +#include <pthread.h> + +typedef unsigned char uchar; +typedef void (*MIDI_Callback_function)(int arrivalPort); + + +class MidiInPort_oss : public Sequencer_oss { + public: + MidiInPort_oss (void); + MidiInPort_oss (int aPort, int autoOpen = 1); + ~MidiInPort_oss (); + + void clearSysex (int buffer); + void clearSysex (void); + void close (void); + void close (int i) { close(); } + void closeAll (void); + MidiMessage extract (void); + int getBufferSize (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + uchar* getSysex (int buffer); + int getSysexSize (int buffer); + int getTrace (void); + void insert (const MidiMessage& aMessage); + int installSysex (uchar* anArray, int aSize); + MidiMessage& message (int index); + int open (void); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + protected: + int port; // the port to which this object belongs + + static MIDI_Callback_function callbackFunction; + + static int installSysexPrivate (int port, + uchar* anArray, int aSize); + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* trace; // for verifying input + static std::ostream* tracedisplay; // stream for displaying trace + static int numDevices; // number of input ports + static CircularBuffer<MidiMessage>** midiBuffer; // MIDI storage frm ports + static int channelOffset; // channel offset, either 0 or 1 + // not being used right now. + static int* pauseQ; // for adding items to Buffer or not + static SigTimer midiTimer; // for timing MIDI input + static pthread_t midiInThread; // for MIDI input thread function + static int* sysexWriteBuffer; // for MIDI sysex write location + static Array<uchar>** sysexBuffers; // for MIDI sysex storage + + private: + void deinitialize (void); + void initialize (void); + + + friend void *interpretMidiInputStreamPrivate(void * x); + +}; + + +#endif /* LINUX */ + +#endif /* _MIDIINPORT_OSS_H_INCLUDED */ + + + +// md5sum: 05331ff5c3806fc753ebebaeffa3c377 - MidiInPort_oss.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_unsupported.h b/src/midiio/include/MidiInPort_unsupported.h new file mode 100644 index 0000000..1f3bcf0 --- /dev/null +++ b/src/midiio/include/MidiInPort_unsupported.h @@ -0,0 +1,89 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Fri Jan 23 00:04:51 GMT-0800 1998 +// Last Modified: Fri Jan 23 00:04:58 GMT-0800 1998 +// Last Modified: Wed Jun 30 11:42:59 PDT 1999 (added sysex capability) +// Filename: ...sig/code/control/MidiInPort/unsupported/MidiInPort_unsupported.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiInPort_unsupported.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// an unknown sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// This class is used when there is no MIDI input, so +// that MIDI programs can otherwise be compiled and run. +// This file can also serve as a template for creating +// an OS specific class for MIDI input. +// + +#ifndef _MIDIINPUT_UNSUPPORTED_H_INCLUDED +#define _MIDIINPUT_UNSUPPORTED_H_INCLUDED + +#include "MidiMessage.h" +#include "CircularBuffer.h" +#include "Array.h" + +class MidiInPort_unsupported { + public: + MidiInPort_unsupported (void); + MidiInPort_unsupported (int aPort, int autoOpen = 1); + ~MidiInPort_unsupported (); + + void clearSysex (int index) { } + void clearSysex (void) { } + int getSysexSize (int index) { return 0; } + uchar* getSysex (int buffer) { return NULL; } + int installSysex (unsigned char *&, int &) { return 0; } + int getBufferSize (void) { return 0; } + void close (void); + void close (int i) { close(); } + void closeAll (void); + MidiMessage extract (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + int getTrace (void); + void insert (const MidiMessage& aMessage); + MidiMessage& message (int index); + int open (void); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + protected: + int port; // the port to which this object belongs + int trace; + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* openQ; // for open/close status of port + static int numDevices; // number of input ports + static CircularBuffer<MidiMessage>* midiBuffer; // MIDI storage from ports + static int channelOffset; // channel offset, either 0 or 1 + // not being used right now. + static int* sysexWriteBuffer; // for MIDI sysex write location + static Array<uchar>** sysexBuffers; // for MIDI sysex storage + + private: + void deinitialize (void); + void initialize (void); + void setPortStatus (int aStatus); + + +}; + + + +#endif /* _MIDIINPUT_UNSUPPORTED_H_INCLUDED */ + + + +// md5sum: ff5492fbd59a47e48e2c0ce06705add1 - MidiInPort_unsupported.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_visual.h b/src/midiio/include/MidiInPort_visual.h new file mode 100644 index 0000000..398a187 --- /dev/null +++ b/src/midiio/include/MidiInPort_visual.h @@ -0,0 +1,114 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Dec 28 15:18:46 GMT-0800 1997 +// Last Modified: Mon Jan 12 20:05:27 GMT-0800 1998 +// Last Modified: Wed Jun 30 11:29:51 PDT 1999 (added sysex capability) +// Filename: ...sig/code/control/MidiInPort/visual/MidiInPort_visual.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiInPort_visual.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// Windows 95/NT/98 specific MIDI input methods. +// as defined in winmm.lib. This class is inherited +// privately by the MidiInPort class. +// + +#ifndef _MIDIINPUT_VISUAL_H_INCLUDED +#define _MIDIINPUT_VISUAL_H_INCLUDED + + +#ifdef VISUAL + +#define DEFAULT_INPUT_BUFFER_SIZE (1024) + +#include <windows.h> +#include <mmsystem.h> + +#include "MidiMessage.h" +#include "CircularBuffer.h" +#include "Array.h" + +class MidiInPort_visual { + public: + MidiInPort_visual (void); + MidiInPort_visual (int aPort, int autoOpen = 1); + ~MidiInPort_visual (); + + void clearSysex (void); + void clearSysex (int buffer); + void close (void); + void closeAll (void); + MidiMessage extract (void); + int getBufferSize (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + uchar* getSysex (int buffer); + int getSysexSize (int buffer); + int getTrace (void); + void insert (const MidiMessage& aMessage); + int installSysex (uchar* anArray, int aSize); + MidiMessage& message (int index); + int open (void); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + protected: + int port; // the port to which this object belongs + int trace; + + int installSysexPrivate (int port, uchar* anArray, int aSize); + void installSysexStuff (HMIDIIN dev, int port); + void uninstallSysexStuff (HMIDIIN dev, int port); + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* openQ; // for open/close status of port + static int* inrunningQ; // for running open input port + static int numDevices; // number of input ports + static HMIDIIN* device; // Windoze MIDI-in device structure + static MIDIHDR** sysexDriverBuffer1; // for Windoze driver sysex buffers + static MIDIHDR** sysexDriverBuffer2; // for Windoze driver sysex buffers + static int* sysexDBnumber; // for Windoze driver sysex buffers + static HANDLE* hMutex; // mutual exclusive + static CircularBuffer<MidiMessage>* midiBuffer; // MIDI storage from ports + static int channelOffset; // channel offset from either 0 or 1. + // not being used right now. + static int* sysexWriteBuffer; // for MIDI sysex write location + static Array<uchar>** sysexBuffers;// for MIDI sysex storage + static int* sysexStatus; // tracing multiple MIM_LONGDATA messgs + + private: + void deinitialize (void); + void initialize (void); + void releaseMutex (void); + void setPortStatus (int aStatus); + void waitForMutex (void); + + + friend void CALLBACK midiInputCallback(HMIDIIN hMidiIn, UINT inputStatus, + DWORD instancePtr, DWORD midiMessage, DWORD timestamp); +}; + + +// This is the command which is called by the driver when there is +// MIDI data being received from the MIDI input port: + void CALLBACK midiInputCallback(HMIDIIN hMidiIn, UINT inputStatus, + DWORD instancePtr, DWORD midiMessage, DWORD timestamp); + + +#endif /* VISUAL */ +#endif /* _MIDIINPUT_VISUAL_H_INCLUDED */ + + + +// md5sum: d5aee7a88c4a054b3e2d4d40622fdc42 - MidiInPort_visual.h =css= 20030102 diff --git a/src/midiio/include/MidiInput.h b/src/midiio/include/MidiInput.h new file mode 100644 index 0000000..4425f75 --- /dev/null +++ b/src/midiio/include/MidiInput.h @@ -0,0 +1,53 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 18 December 1997 +// Last Modified: Sun Jan 25 15:27:02 GMT-0800 1998 +// Last Modified: Thu Apr 20 16:23:24 PDT 2000 (added scale function) +// Filename: ...sig/code/control/MidiInput/MidiInput.h +// Web Address: http://sig.sapp.org/include/sig/MidiInput.h +// Syntax: C++ +// +// Description: A higher-level MIDI input interface than the +// MidiInPort class. Can be used to allow multiple +// objects to share a single MIDI input stream, or +// to fake a MIDI input connection. +// + +#ifndef _MIDIINPUT_H_INCLUDED +#define _MIDIINPUT_H_INCLUDED + + +#include "MidiInPort.h" + + +class MidiInput : public MidiInPort { + public: + MidiInput (void); + MidiInput (int aPort, int autoOpen = 1); + ~MidiInput (); + + int getBufferSize (void); + int getCount (void); + MidiMessage extract (void); + void insert (const MidiMessage& aMessage); + int isOrphan (void) const; + void makeOrphanBuffer (int aSize = 1024); + void removeOrphanBuffer(void); + void setBufferSize (int aSize); + + int scale (int value, int min, int max); + double fscale (int value, double min, double max); + int scale14 (int value, int min, int max); + double fscale14 (int value, double min, double max); + + protected: + CircularBuffer<MidiMessage>* orphanBuffer; + +}; + + +#endif /* _MIDIINPUT_H_INCLUDED */ + + + +// md5sum: 73972cc29d7bcf0fba136b098c0419a0 - MidiInput.h =css= 20030102 diff --git a/src/midiio/include/MidiMessage.h b/src/midiio/include/MidiMessage.h new file mode 100644 index 0000000..e4b59ba --- /dev/null +++ b/src/midiio/include/MidiMessage.h @@ -0,0 +1,78 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 19 December 1997 +// Last Modified: Fri Jan 23 00:21:24 GMT-0800 1998 +// Last Modified: Sun Sep 20 20:30:53 PDT 1998 +// Last Modified: Mon Oct 15 14:29:12 PDT 2001 (added is_note functions) +// Filename: ...sig/include/sigInfo/MidiMessage.h +// Web Address: http://sig.sapp.org/include/sigInfo/MidiMessage.h +// Syntax: C++ +// +// Description: A structure for handling MIDI input messages. +// This class stores a time stamp plus up to +// four MIDI message bytes. System Exclusive messages +// are stored in a separate array in the MidiInPort +// class, and their storage index is passed to the +// user through a MIDI message for later extraction +// of the full sysex message. +// + +#ifndef _MIDIMESSAGE_H_INCLUDED +#define _MIDIMESSAGE_H_INCLUDED + +#include <iostream> + +typedef unsigned char uchar; +typedef unsigned long ulong; + +class MidiMessage { + public: + ulong time; // timestamp + ulong data; // MIDI command and parameters + + MidiMessage (void); + MidiMessage (int aCommand, int aP1, int aP2, + int aTime = 0); + MidiMessage (const MidiMessage& aMessage); + ~MidiMessage (); + + uchar& command (void); + MidiMessage& operator= (const MidiMessage& aMessage); + uchar& operator[] (int index); + uchar& p0 (void); + uchar& p1 (void); + uchar& p2 (void); + uchar& p3 (void); + int getArgCount (void) const; + int getParameterCount (void) const; + + uchar getCommand (void) const; + uchar getP0 (void) const; + uchar getP1 (void) const; + uchar getP2 (void) const; + uchar getP3 (void) const; + + void setCommand (uchar aCommand); + void setData (uchar aCommand, uchar aP1 = 0, + uchar aP2 = 0, uchar aP3 = 0); + void setP0 (uchar aP0); + void setP1 (uchar aP1); + void setP2 (uchar aP2); + void setP3 (uchar aP3); + + int is_note (void); + int is_note_on (void); + int is_note_off (void); + +}; + + +std::ostream& operator<<(std::ostream& out, MidiMessage& aMessage); + + +#endif /* _MIDIMESSAGE_H_INCLUDED */ + + + +// md5sum: 4738e957fb8a233f6dbaeebda490e6a4 - MidiMessage.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort.h b/src/midiio/include/MidiOutPort.h new file mode 100644 index 0000000..0287dfd --- /dev/null +++ b/src/midiio/include/MidiOutPort.h @@ -0,0 +1,92 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Dec 28 15:04:24 GMT-0800 1997 +// Last Modified: Fri Jan 23 10:56:18 GMT-0800 1998 +// Last Modified: Sat Nov 7 16:15:54 PST 1998 +// Last Modified: Tue May 23 23:08:44 PDT 2000 (oss/alsa selection added) +// Last Modified: Mon Jun 19 10:32:11 PDT 2000 (oss/alsa define fix) +// Filename: ...sig/code/control/MidiOutPort/MidiOutPort.h +// Web Address: http://sig.sapp.org/include/sig/MidiOutPort.h +// Syntax: C++ +// +// Description: Operating-System independent interface for +// basic MIDI output capabilities. Privately +// inherits the operating-system specific class +// for MIDI output. +// + +#ifndef _MIDIOUTPORT_H_INCLUDED +#define _MIDIOUTPORT_H_INCLUDED + + +#ifdef VISUAL + #define MIDIOUTPORT MidiOutPort_visual + #include "MidiOutPort_visual.h" +#elif defined(LINUX) && defined(ALSA) && defined(OSS) + #define MIDIOUTPORT MidiOutPort_linux + #include "MidiOutPort_linux.h" +#elif defined(LINUX) && defined(ALSA) && !defined(OSS) + #define MIDIOUTPORT MidiOutPort_alsa + #include "MidiOutPort_alsa.h" +#elif defined (LINUX) && defined(OSS) && !defined(ALSA) + #define MIDIOUTPORT MidiOutPort_oss + #include "MidiOutPort_oss.h" +#elif defined(LINUX) + #define MIDIOUTPORT MidiOutPort_oss + #include "MidiOutPort_oss.h" +#else + #define MIDIOUTPORT MidiOutPort_unsupported + #include "MidiOutPort_unsupported.h" +#endif + + +class MidiOutPort : protected MIDIOUTPORT { + public: + MidiOutPort (void) : MIDIOUTPORT() {} + MidiOutPort (int aPort, int autoOpen = 1) : + MIDIOUTPORT(aPort, autoOpen) {} + ~MidiOutPort() { } + + void close(void) { MIDIOUTPORT::close(); } + void closeAll(void) { MIDIOUTPORT::closeAll(); } + int getChannelOffset(void) const { + return MIDIOUTPORT::getChannelOffset(); } + const char* getName(void) { return MIDIOUTPORT::getName(); } + static const char* getName(int i) { return MIDIOUTPORT::getName(i); } + static int getNumPorts(void) { return MIDIOUTPORT::getNumPorts(); } + int getPort(void) { return MIDIOUTPORT::getPort(); } + int getPortStatus(void) { + return MIDIOUTPORT::getPortStatus(); } + int getTrace(void) { + return MIDIOUTPORT::getTrace(); } + int open(void) { return MIDIOUTPORT::open(); } + int rawsend(int command, int p1, int p2) { + return MIDIOUTPORT::rawsend(command, p1, p2); } + int rawsend(int command, int p1) { + return MIDIOUTPORT::rawsend(command, p1); } + int rawsend(int command) { + return MIDIOUTPORT::rawsend(command); } + int rawsend(uchar* array, int size) { + return MIDIOUTPORT::rawsend(array, size); } + void setAndOpenPort(int aPort) { setPort(aPort); open(); } +// void setChannelOffset(int aChannel) { +// MIDIOUTPORT::setChannelOffset(aChannel); } + void setPort(int aPort) { MIDIOUTPORT::setPort(aPort); } + int setTrace(int aState) { + return MIDIOUTPORT::setTrace(aState); } + int sysex(uchar* array, int size) { + return MIDIOUTPORT::sysex(array, size); } + void toggleTrace(void) { MIDIOUTPORT::toggleTrace(); } + MidiOutPort& operator=(MidiOutPort& other) { + setPort(other.getPort()); + if (other.getPortStatus()) { open(); } + return *this; } +}; + + + + +#endif /* _MIDIOUTPORT_H_INCLUDED */ + + +// md5sum: 2f7b8aa8ef705eab57179b626ce1d62d - MidiOutPort.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort_alsa.h b/src/midiio/include/MidiOutPort_alsa.h new file mode 100644 index 0000000..34139a3 --- /dev/null +++ b/src/midiio/include/MidiOutPort_alsa.h @@ -0,0 +1,79 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed May 10 16:22:00 PDT 2000 +// Last Modified: Sun May 14 20:43:44 PDT 2000 +// Last Modified: Sat Nov 2 20:39:01 PST 2002 (added ALSA def) +// Filename: ...sig/maint/code/control/MidiOutPort/linux/MidiOutPort_alsa.h +// Web Address: http://sig.sapp.org/include/sig/MidiOutPort_alsa.h +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Linux using +// OSS sound drivers. Privately inherited by the +// MidiOutPort class. +// + +#ifndef _MIDIOUTPORT_ALSA_H_INCLUDED +#define _MIDIOUTPORT_ALSA_H_INCLUDED + +#ifdef LINUX +#ifdef ALSA + +#include "Sequencer_alsa.h" +#include <iostream> + +typedef unsigned char uchar; + + +class MidiOutPort_alsa : public Sequencer_alsa { + public: + MidiOutPort_alsa (void); + MidiOutPort_alsa (int aPort, int autoOpen = 1); + ~MidiOutPort_alsa (); + + void close (void); + void closeAll (void); + int getChannelOffset (void) const; + const char* getName (void); + static const char* getName (int i); + int getPort (void); + static int getNumPorts (void); + int getPortStatus (void); + int getTrace (void); + int rawsend (int command, int p1, int p2); + int rawsend (int command, int p1); + int rawsend (int command); + int rawsend (uchar* array, int size); + int open (void); + void setChannelOffset (int aChannel); + void setPort (int aPort); + int setTrace (int aState); + int sysex (uchar* array, int size); + void toggleTrace (void); + + protected: + int port; // the port to which this object belongs + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int numDevices; // number of output ports + static int* trace; // for printing messages to output + static std::ostream* tracedisplay; // for printing trace messages + + private: + void deinitialize (void); + void initialize (void); + void setPortStatus (int aStatus); + + static int channelOffset; // channel offset, either 0 or 1. + // not being used right now. +}; + + + +#endif /* ALSA */ +#endif /* LINUX */ +#endif /* _MIDIOUTPUT_ALSA_H_INCLUDED */ + + +// md5sum: 5b7648c7b493df7cb0d1fae3bbb8be24 - MidiOutPort_alsa.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort_linux.h b/src/midiio/include/MidiOutPort_linux.h new file mode 100644 index 0000000..a02dc22 --- /dev/null +++ b/src/midiio/include/MidiOutPort_linux.h @@ -0,0 +1,80 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed May 10 16:03:52 PDT 2000 +// Last Modified: Thu May 18 23:37:17 PDT 2000 +// Last Modified: Sat Nov 2 20:40:01 PST 2002 (added ALSA OSS def) +// Filename: ...sig/code/control/MidiOutPort_linux/MidiOutPort_linux.h +// Web Address: http://sig.sapp.org/include/sig/MidiOutPort_linux.h +// Syntax: C++ +// +// Description: Linux MIDI output class which detects which +// type of MIDI drivers are available: either +// ALSA or OSS. +// + +#ifndef _MIDIOUTPORT_LINUX_H_INCLUDED +#define _MIDIOUTPORT_LINUX_H_INCLUDED + +#ifdef LINUX +#if defined(ALSA) && defined(OSS) + +#include "MidiOutPort_oss.h" +#include "MidiOutPort_alsa.h" +#include "MidiOutPort_unsupported.h" + +#define UNKNOWN_MIDI_SELECT 0 /* use dummy MIDI output */ +#define OSS_MIDI_SELECT 1 /* use OSS MIDI output */ +#define ALSA_MIDI_SELECT 2 /* use ALSA MIDI output */ + +class MidiOutPort_linux { + public: + MidiOutPort_linux (void); + MidiOutPort_linux (int aPort, int autoOpen = 1); + ~MidiOutPort_linux (); + + void close (void); + void closeAll (void); + int getChannelOffset (void) const; + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + int getTrace (void); + int open (void); + int rawsend (int command, int p1, int p2); + int rawsend (int command, int p1); + int rawsend (int command); + int rawsend (uchar* array, int size); + void setAndOpenPort (int aPort); + void setChannelOffset (int aChannel); + void setPort (int aPort); + int setTrace (int aState); + int sysex (uchar* array, int size); + void toggleTrace (void); + + static int getSelect (void); + static int selectOSS (void); + static int selectALSA (void); + static int selectUnknown (void); + + private: + static int current; // the type of MIDI out selected + static int alsaQ; // boolean for if ALSA is present + static int ossQ; // boolean for if OSS is present + + static int objectCount; + static MidiOutPort_oss *oss_output; + static MidiOutPort_alsa *alsa_output; + static MidiOutPort_unsupported *unknown_output; + + void determineDrivers (void); +}; + +#endif /* ALSA and OSS */ +#endif /* LINUX */ + +#endif /* _MIDIOUTPORT_LINUX_H_INCLUDED */ + + +// md5sum: c80f9f47c45a6d4a20b6549743cae9fb - MidiOutPort_linux.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort_oss.h b/src/midiio/include/MidiOutPort_oss.h new file mode 100644 index 0000000..22cf32d --- /dev/null +++ b/src/midiio/include/MidiOutPort_oss.h @@ -0,0 +1,75 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Fri Dec 18 19:15:00 PST 1998 +// Last Modified: Wed May 10 17:00:11 PDT 2000 (name change from _linux to _oss) +// Filename: ...sig/maint/code/control/MidiOutPort/linux/MidiOutPort_oss.h +// Web Address: http://sig.sapp.org/include/sig/MidiOutPort_oss.h +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Linux using +// OSS sound drivers. Privately inherited by the +// MidiOutPort class. +// + +#ifndef _MIDIOUTPORT_OSS_H_INCLUDED +#define _MIDIOUTPORT_OSS_H_INCLUDED + +#ifdef LINUX + +#include "Sequencer_oss.h" + +typedef unsigned char uchar; + + +class MidiOutPort_oss : public Sequencer_oss { + public: + MidiOutPort_oss (void); + MidiOutPort_oss (int aPort, int autoOpen = 1); + ~MidiOutPort_oss (); + + void close (void); + void closeAll (void); + int getChannelOffset (void) const; + const char* getName (void); + static const char* getName (int i); + int getPort (void); + static int getNumPorts (void); + int getPortStatus (void); + int getTrace (void); + int rawsend (int command, int p1, int p2); + int rawsend (int command, int p1); + int rawsend (int command); + int rawsend (uchar* array, int size); + int open (void); + void setChannelOffset (int aChannel); + void setPort (int aPort); + int setTrace (int aState); + int sysex (uchar* array, int size); + void toggleTrace (void); + + protected: + int port; // the port to which this object belongs + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int numDevices; // number of output ports + static int* trace; // for printing messages to output + static std::ostream* tracedisplay; // for printing trace messages + + private: + void deinitialize (void); + void initialize (void); + void setPortStatus (int aStatus); + + static int channelOffset; // channel offset, either 0 or 1. + // not being used right now. +}; + + + +#endif /* LINUX */ +#endif /* _MIDIOUTPUT_OSS_H_INCLUDED */ + + +// md5sum: f60183e23c49741e93d9b965bbe9a6d8 - MidiOutPort_oss.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort_unsupported.h b/src/midiio/include/MidiOutPort_unsupported.h new file mode 100644 index 0000000..a5e8c35 --- /dev/null +++ b/src/midiio/include/MidiOutPort_unsupported.h @@ -0,0 +1,71 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Mon Jan 12 21:36:26 GMT-0800 1998 +// Last Modified: Mon Jan 12 21:36:31 GMT-0800 1998 +// Filename: ...sig/code/control/MidiOutPort/unsupported/MidiOutPort_unsupported.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiOutPort_unsupported.h +// Syntax: C++ +// +// Description: Operating-System specific interface for basic MIDI output +// capabilities in an unknown operating system. Privately +// inherited by the MidiOutPort class. Used for compiling +// and running MIDI programs on a computer with no +// MIDI output. +// + +#ifndef _MIDIOUTPUT_UNSUPPORTED_H_INCLUDED +#define _MIDIOUTPUT_UNSUPPORTED_H_INCLUDED + +typedef unsigned char uchar; + +class MidiOutPort_unsupported { + public: + MidiOutPort_unsupported (void); + MidiOutPort_unsupported (int aPort, int autoOpen = 1); + ~MidiOutPort_unsupported (); + + void close (void); + void closeAll (void); + int getChannelOffset (void) const; + const char* getName (void) const; + const char* getName (int i) const; + int getPort (void) const; + int getNumPorts (void) const; + int getPortStatus (void) const; + int getTrace (void) const; + int rawsend (int command, int p1, int p2); + int rawsend (int command, int p1); + int rawsend (int command); + int rawsend (uchar* array, int size); + int open (void); + void setChannelOffset (int aChannel); + void setPort (int aPort); + int setTrace (int aState); + int sysex (uchar* array, int size); + void toggleTrace (void); + + protected: + int port; // the port to which this object belongs + int trace; // for printing out midi messages to standard output + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* openQ; // for open/close status of port + static int numDevices; // number of output ports + + private: + void deinitialize (void); + void initialize (void); + void setPortStatus (int aStatus); + + static int channelOffset; // channel offset, either 0 or 1 + // not being used right now. +}; + + + +#endif /* _MIDIOUTPUT_UNSUPPORTED_H_INCLUDED */ + + + +// md5sum: e244688a99d220addc7b1c6f6f6a8022 - MidiOutPort_unsupported.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort_visual.h b/src/midiio/include/MidiOutPort_visual.h new file mode 100644 index 0000000..d6a3984 --- /dev/null +++ b/src/midiio/include/MidiOutPort_visual.h @@ -0,0 +1,75 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Dec 28 15:18:46 GMT-0800 1997 +// Last Modified: Mon Jan 12 20:05:27 GMT-0800 1998 +// Filename: ...sig/code/control/MidiOutPort/visual/MidiOutPort_visual.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiOutPort_visual.h +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Windows 95/NT/98 +// using winmm.lib. Privately inherited by the +// MidiOutPort class. +// + +#ifndef _MIDIOUTPUT_VISUAL_H_INCLUDED +#define _MIDIOUTPUT_VISUAL_H_INCLUDED + +#ifdef VISUAL + +typedef unsigned char uchar; + +#include <windows.h> +#include <mmsystem.h> + +class MidiOutPort_visual { + public: + MidiOutPort_visual (void); + MidiOutPort_visual (int aPort, int autoOpen = 1); + ~MidiOutPort_visual (); + + void close (void); + void closeAll (void); + int getChannelOffset (void) const; + const char* getName (void); + static const char* getName (int i); + int getPort (void); + static int getNumPorts (void); + int getPortStatus (void); + int getTrace (void); + int rawsend (int command, int p1, int p2); + int rawsend (int command, int p1); + int rawsend (int command); + int rawsend (uchar* array, int size); + int open (void); + void setChannelOffset (int aChannel); + void setPort (int aPort); + int setTrace (int aState); + int sysex (uchar* array, int size); + void toggleTrace (void); + + protected: + int port; // the port to which this object belongs + int trace; // for printing out Midi messages to standard output + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* openQ; // for open/close status of port + static int numDevices; // number of output ports + static HMIDIOUT* device; // Windoze midi out device structure + + private: + void deinitialize (void); + void initialize (void); + void setPortStatus (int aStatus); + + static int channelOffset; // channel offset, either 0 or 1. + // not being used right now. +}; + + +#endif /* VISUAL */ +#endif /* _MIDIOUTPUT_VISUAL_H_INCLUDED */ + + +// md5sum: 47799e340effa57676be8a3943cabb70 - MidiOutPort_visual.h =css= 20030102 diff --git a/src/midiio/include/MidiOutput.h b/src/midiio/include/MidiOutput.h new file mode 100644 index 0000000..d424816 --- /dev/null +++ b/src/midiio/include/MidiOutput.h @@ -0,0 +1,140 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 18 December 1997 +// Last Modified: Mon Jan 26 23:53:05 GMT-0800 1998 +// Last Modified: Sat Jan 30 14:00:29 PST 1999 +// Last Modified: Sun Jul 18 18:52:42 PDT 1999 (added RPN functions) +// Filename: ...sig/maint/code/control/MidiOutput/MidiOutput.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiOutput.h +// Syntax: C++ +// +// Description: The MIDI output interface for MIDI synthesizers/equipment +// which has many convienience functions defined for +// various types of MIDI output. +// + +#ifndef _MIDIOUTPUT_H_INCLUDED +#define _MIDIOUTPUT_H_INCLUDED + +#include "MidiOutPort.h" +#include "FileIO.h" +#include "SigTimer.h" +#include "Array.h" + + +class MidiOutput : public MidiOutPort { + public: + MidiOutput (void); + MidiOutput (int aPort, int autoOpen = 1); + ~MidiOutput (); + + // Basic user MIDI output commands: + int cont (int channel, int controller, int data); + int off (int channel, int keynum, int releaseVelocity); + int pc (int channel, int timbre); + int play (int channel, int keynum, int velocity); + int pw (int channel, int mostByte, int leastByte); + int pw (int channel, int tuningData); + int pw (int channel, double tuningData); + void recordStart (char *filename, int format); + void recordStop (void); + void reset (void); + int send (int command, int p1, int p2); + int send (int command, int p1); + int send (int command); + void silence (int aChannel = -1); + void sustain (int channel, int status); + int sysex (char* data, int length); + int sysex (uchar* data, int length); + + protected: + int outputRecordQ; // boolean for recording + int outputRecordType; // what form to record MIDI data in + int lastFlushTime; // for recording midi data + FileIO outputRecordFile; // file for recording midi data + static SigTimer timer; // for recording midi data + static Array<int>* rpn_lsb_status; // for RPN messages + static Array<int>* rpn_msb_status; // for RPN messages + static int objectCount; // for RPN messages + + void deinitializeRPN (void); + void initializeRPN (void); + void writeOutputAscii (int channel, int p1, int p2); + void writeOutputBinary (int channel, int p1, int p2); + void writeOutputMidifile(int channel, int p1, int p2); + + public: // RPN controller functions + int NRPN (int channel, int nrpn_msb, int nrpn_lsb, + int data_msb, int data_lsb); + int NRPN (int channel, int nrpn_msb, int nrpn_lsb, + int data_msb); + int NRPN (int channel, int nrpn_msb, int nrpn_lsb, + double data); + int NRPN_null (int channel); + int NRPN_attack (int channel, double value); + int NRPN_attack (int channel, int value); + int NRPN_decay (int channel, double value); + int NRPN_decay (int channel, int value); + int NRPN_drumAttack (int drum, double value); + int NRPN_drumAttack (int drum, int value); + int NRPN_drumChorus (int drum, double value); + int NRPN_drumChorus (int drum, int value); + int NRPN_drumDecay (int drum, double value); + int NRPN_drumDecay (int drum, int value); + int NRPN_drumLevel (int drum, double value); + int NRPN_drumLevel (int drum, int value); + int NRPN_drumPan (int drum, double value); + int NRPN_drumPan (int drum, int value); + int NRPN_drumPitch (int drum, double value); + int NRPN_drumPitch (int drum, int value); + int NRPN_drumFilterCutoff (int drum, double value); + int NRPN_drumFilterCutoff (int drum, int value); + int NRPN_drumFilterResonance(int drum, double value); + int NRPN_drumFilterResonance(int drum, int value); + int NRPN_drumReverb (int drum, double value); + int NRPN_drumReverb (int drum, int value); + int NRPN_drumVariation (int drum, double value); + int NRPN_drumVariation (int drum, int value); + int NRPN_filterCutoff (int channel, double value); + int NRPN_filterCutoff (int channel, int value); + int NRPN_release (int channel, double value); + int NRPN_release (int channel, int value); + int NRPN_vibratoDelay (int channel, double value); + int NRPN_vibratoDelay (int channel, int value); + int NRPN_vibratoDepth (int channel, double value); + int NRPN_vibratoDepth (int channel, int value); + int NRPN_vibratoRate (int channel, double value); + int NRPN_vibratoRate (int channel, int value); + + int RPN (int channel, int rpn_msb, int rpn_lsb, + int data_msb, int data_lsb); + int RPN (int channel, int rpn_msb, int rpn_lsb, + int data_msb); + int RPN (int channel, int rpn_msb, int rpn_lsb, + double data); + int RPN_null (void); + int RPN_null (int channel); + int pbRange (int channel, int steps); + int tuneFine (int channel, int cents); + int fineTune (int channel, int cents); + int tuneCoarse (int channel, int steps); + int coarseTune (int channel, int steps); + int tuningProgram (int channel, int program); + int tuningBank (int channel, int bank); + +}; + + +#endif /* _MIDIOUTPUT_H_INCLUDED */ + +// Brief description of MidiOutput public member functions: +// +// send: sends a MIDI command to the MIDI output with up to two parameters +// play: sends a playnote command to the MIDI output +// pc: Patch Change. changes the timbre (instrument) on the given channel +// cont: sends a CONTinuous CONTroller MIDI command +// sysex: sends a system exclusive command to the MIDI output +// + + +// md5sum: 12ee02c32563ae219aaa8c7599de55db - MidiOutput.h =css= 20030102 diff --git a/src/midiio/include/MidiPort.h b/src/midiio/include/MidiPort.h new file mode 100644 index 0000000..834877e --- /dev/null +++ b/src/midiio/include/MidiPort.h @@ -0,0 +1,49 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 21 December 1997 +// Last Modified: Fri Jan 23 10:21:25 GMT-0800 1998 +// Filename: .../sig/code/control/MidiPort/MidiPort.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiPort.h +// Syntax: C++ +// +// Description: A unified object that handles basic MIDI input and output. +// Derived from the MidiInPort and MidiOutPort classes. +// + +#ifndef _MIDIPORT_H_INCLUDED +#define _MIDIPORT_H_INCLUDED + + +#include "MidiInPort.h" +#include "MidiOutPort.h" + + +class MidiPort : public MidiOutPort, public MidiInPort { + public: + MidiPort (void); + MidiPort (int outputPort, int inputPort); + ~MidiPort (); + + int getChannelInOffset (void) const; + int getChannelOutOffset (void) const; + int getInputPort (void); + int getInputTrace (void); + int getOutputPort (void); + int getOutputTrace (void); + void setChannelOffset (int anOffset); + void setInputPort (int aPort); + int setInputTrace (int aState); + void setOutputPort (int aPort); + int setOutputTrace (int aState); + void toggleInputTrace (void); + void toggleOutputTrace (void); + +}; + + + +#endif /* _MIDIPORT_H_INCLUDED */ + + + +// md5sum: 84d8155528b06c9aa902e8f06649385f - MidiPort.h =css= 20030102 diff --git a/src/midiio/include/Options.h b/src/midiio/include/Options.h new file mode 100644 index 0000000..71754fb --- /dev/null +++ b/src/midiio/include/Options.h @@ -0,0 +1,106 @@ +// +// Copyright 1998-2000 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Apr 5 13:07:18 PDT 1998 +// Last Modified: Fri Jan 15 07:24:00 PST 1999 +// Last Modified: Sat Mar 27 18:17:59 PST 1999 +// Last Modified: Thu Apr 13 14:02:52 PDT 2000 (added 2nd define function) +// Last Modified: Fri May 5 17:57:50 PDT 2000 (added --options suppression) +// Filename: ...sig/maint/code/base/Options/Options.h +// Web Address: http://sig.sapp.org/include/sigBase/Options.h +// Documentation: http://sig.sapp.org/doc/classes/Options +// Syntax: C++ +// +// Description: Handles command-line options in a graceful manner. +// + +#ifndef _OPTIONS_H_INCLUDED +#define _OPTIONS_H_INCLUDED + +#include "Array.h" + +class option_list; +class option_register; + + +class Options { + public: + Options (void); + Options (int argc, char** argv); + ~Options (); + + int argc (void) const; + char** argv (void) const; + void define (const char* aDefinition); + void define (const char* aDefinition, + const char* description); + char* getArg (int index); + char* getArgument (int index); + int getArgCount (void); + int getArgumentCount (void); + int getBoolean (const char* optionName); + const char* getCommand (void); + const char* getCommandLine (void); + const char* getString (void); + const char* getDefinition (const char* optionName); + double getDouble (const char* optionName); + char getFlag (void); + float getFloat (const char* optionName); + int getInt (const char* optionName); + int getInteger (const char* optionName); + const char* getString (const char* optionName); + char getType (const char* optionName); + int optionsArg (void); + void print (void); + void process (int error_check = 1, int suppress = 0); + void process (int argc, char** argv, + int error_check = 1, + int suppress = 0); + void reset (void); + void verify (int argc, char** argv, + int error_check = 1, + int suppress = 0); + void verify (int error_check = 1, + int suppress = 0); + void setFlag (char aFlag); + void setModified (const char* optionName, + const char* optionValue); + void setOptions (int argc, char** argv); + + protected: + int options_error_check; // for verify command + int gargc; + char** gargv; + char* commandString; + char optionFlag; + Array<char*> argument; + Array<option_register*> optionRegister; + Array<option_list*> optionList; + int processedQ; + int sortedQ; + int suppressQ; // prevent the --options option + int optionsArgument; // indicates --options present + + int getRegIndex (const char* optionName); + int optionQ (const char* aString, int& argp); + void sortOptionNames (void); + int storeOption (int gargp, int& position, + int& running); + +}; + +#define OPTION_BOOLEAN_TYPE 'b' +#define OPTION_CHAR_TYPE 'c' +#define OPTION_DOUBLE_TYPE 'd' +#define OPTION_FLOAT_TYPE 'f' +#define OPTION_INT_TYPE 'i' +#define OPTION_STRING_TYPE 's' +#define OPTION_UNKNOWN_TYPE 'x' + + + +#endif /* _OPTIONS_H_INCLUDED */ + + + +// md5sum: c59d297a8081cb48f61b534484819f48 - Options.h =css= 20030102 diff --git a/src/midiio/include/Options_private.h b/src/midiio/include/Options_private.h new file mode 100644 index 0000000..8349d55 --- /dev/null +++ b/src/midiio/include/Options_private.h @@ -0,0 +1,73 @@ +// +// Copyright 1998-1999 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Apr 5 13:07:18 PDT 1998 +// Last Modified: Sun Jan 10 05:44:48 PST 1999 +// Filename: ...sig/maint/code/base/Options/Options_private.h +// Web Address: http://sig.sapp.org/include/sigBase/Options_private.h +// Syntax: C++ +// +// Description: A private function for use in the Options class. +// + +#ifndef _OPTIONS_PRIVATE_H_INCLUDED +#define _OPTIONS_PRIVATE_H_INCLUDED + + +class option_register { + public: + option_register (void); + option_register (const char* aDefinition, char aType, + const char* aDefaultOption, + const char* aModifiedOption); + ~option_register (); + void clearModified (void); + const char* getDefinition (void); + const char* getDefault (void); + const char* getOption (void); + const char* getModified (void); + int getModifiedQ (void); + char getType (void); + void reset (void); + void setDefault (const char* aString); + void setDefinition (const char* aString); + void setModified (const char* aString); + void setType (char aType); + + protected: + char* definition; + char* defaultOption; + char* modifiedOption; + char type; + +}; + + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + + +class option_list { + public: + option_list (void); + option_list (const char* optionName, int anIndex); + ~option_list (); + + int getIndex (void); + const char* getName (void); + void setName (const char* aString); + void setIndex (int anIndex); + + protected: + char* name; + int index; + +}; + + + +#endif /* _OPTIONS_PRIVATE_H_INCLUDED */ + + + +// md5sum: b440ad2158e9921d0e31463a8c3e1ae0 - Options_private.h =css= 20030102 diff --git a/src/midiio/include/Sequencer_alsa.h b/src/midiio/include/Sequencer_alsa.h new file mode 100644 index 0000000..3227f5e --- /dev/null +++ b/src/midiio/include/Sequencer_alsa.h @@ -0,0 +1,139 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Thu May 11 21:06:21 PDT 2000 +// Last Modified: Sat Oct 13 14:50:04 PDT 2001 (updated for ALSA 0.9 interface) +// Filename: ...sig/maint/code/control/MidiOutPort/Sequencer_alsa.h +// Web Address: http://sig.sapp.org/include/sig/Sequencer_alsa.h +// Syntax: C++ +// +// Description: Basic MIDI input/output functionality for the +// Linux ALSA midi device /dev/snd/midiXX. This class +// is inherited by the classes MidiInPort_alsa and +// MidiOutPort_alsa. +// +// to get information of status a alsa hardware & software +// cat /proc/asound/version +// cat /proc/asound/devices +// cat /proc/asound/card0/midi0 +// + +#ifndef _SEQUENCER_ALSA_H_INCLUDED +#define _SEQUENCER_ALSA_H_INCLUDED + +#include <iostream> + +#ifdef ALSA + +#include <alsa/asoundlib.h> +#include "Collection.h" + +#define MIDI_EXTERNAL (1) +#define MIDI_INTERNAL (2) + +typedef unsigned char uchar; + + +class Sequencer_alsa { + public: + Sequencer_alsa (int autoOpen = 1); + ~Sequencer_alsa (); + + void close (void); + void closeInput (int index); + void closeOutput (int index); + void displayInputs (std::ostream& out = std::cout, + char* initial = "\t"); + void displayOutputs (std::ostream& out = std::cout, + char* initial = "\t"); + static const char* getInputName (int aDevice); + static const char* getOutputName (int aDevice); + static int getNumInputs (void); + static int getNumOutputs (void); + int is_open (int mode, int index); + int is_open_in (int index); + int is_open_out (int index); + int open (int direction, int index); + int openInput (int index); + int openOutput (int index); + void read (int dev, uchar* buf, int count); + void rebuildInfoDatabase (void); + int write (int aDevice, int aByte); + int write (int aDevice, uchar* bytes, int count); + int write (int aDevice, char* bytes, int count); + int write (int aDevice, int* bytes, int count); + + int getInCardValue (int aDevice) const; + int getOutCardValue (int aDevice) const; + protected: + static int class_count; // number of existing classes using + static int indevcount; // number of MIDI input devices + static int outdevcount; // number of MIDI output devices + static int initialized; // for starting buileinfodatabase + + static Collection<snd_rawmidi_t*> Sequencer_alsa::rawmidi_in; + static Collection<snd_rawmidi_t*> Sequencer_alsa::rawmidi_out; + static Collection<int> Sequencer_alsa::midiincard; + static Collection<int> Sequencer_alsa::midioutcard; + static Collection<int> Sequencer_alsa::midiindevice; + static Collection<int> Sequencer_alsa::midioutdevice; + static Collection<char*> Sequencer_alsa::midiinname; + static Collection<char*> Sequencer_alsa::midioutname; + + private: + static void buildInfoDatabase (void); + static void getPossibleMidiStreams(Collection<int>& cards, + Collection<int>& devices); + int getInDeviceValue (int aDevice) const; + int getInputType (int aDevice) const; + int getOutDeviceValue (int aDevice) const; + int getOutputType (int aDevice) const; + void removeInfoDatabase (void); + + + friend void *interpretMidiInputStreamPrivateALSA(void * x); + +}; + +#else /* ALSA is not defined */ + +typedef unsigned char uchar; + +class Sequencer_alsa { + public: + Sequencer_alsa (int autoOpen = 1) { } + ~Sequencer_alsa () { } + + void close (void) { }; + void displayInputs (std::ostream& out = std::cout, + char* initial = "\t") + { out << initial << "NONE\n"; } + void displayOutputs (std::ostream& out = std::cout, + char* initial = "\t") + { out << initial << "NONE\n"; } + static const char* getInputName (int aDevice) { return ""; } + static const char* getOutputName (int aDevice) { return ""; } + static int getNumInputs (void) { return 0; } + static int getNumOutputs (void) { return 0; } + int is_open (int mode, int index) { return 0; } + int is_open_in (int index) { return 0; } + int is_open_out (int index) { return 0; } + int open (void) { return 0; } + void read (int dev, uchar* buf, int count) { } + void rebuildInfoDatabase (void) { } + int write (int aDevice, int aByte) { return 0; } + int write (int aDevice, uchar* bytes, int count) { return 0; } + int write (int aDevice, char* bytes, int count) { return 0; } + int write (int aDevice, int* bytes, int count) { return 0; } + int getInCardValue (int aDevice) const { return 0; } + int getOutCardValue (int aDevice) const { return 0; } + +}; + + +#endif /* ALSA */ + + +#endif /* _SEQUENCER_ALSA_H_INCLUDED */ + + +// md5sum: 6147020b0646fca8245f653505308949 - Sequencer_alsa.h =css= 20030102 diff --git a/src/midiio/include/Sequencer_oss.h b/src/midiio/include/Sequencer_oss.h new file mode 100644 index 0000000..5f269a7 --- /dev/null +++ b/src/midiio/include/Sequencer_oss.h @@ -0,0 +1,92 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Jan 3 21:02:02 PST 1999 +// Last Modified: Sat Jan 30 14:11:18 PST 1999 +// Last Modified: Wed May 10 17:00:11 PDT 2000 (name change from _oss to _oss) +// Filename: ...sig/maint/code/control/MidiOutPort/Sequencer_oss.h +// Web Address: http://sig.sapp.org/include/sig/Sequencer_oss.h +// Syntax: C++ +// +// Description: Basic MIDI input/output functionality for the +// Linux OSS midi device /dev/sequencer. This class +// is inherited by the classes MidiInPort_oss and +// MidiOutPort_oss. +// + +#ifndef _SEQUENCER_OSS_H_INCLUDED +#define _SEQUENCER_OSS_H_INCLUDED + +#include <iostream> + +#define MIDI_EXTERNAL (1) +#define MIDI_INTERNAL (2) + +typedef unsigned char uchar; + + +class Sequencer_oss { + public: + Sequencer_oss (int autoOpen = 1); + ~Sequencer_oss (); + + void close (void); + void displayInputs (std::ostream& out = std::cout, + char* initial = "\t"); + void displayOutputs (std::ostream& out = std::cout, + char* initial = "\t"); + static int getNumInputs (void); + static int getNumOutputs (void); + static const char* getInputName (int aDevice); + static const char* getOutputName (int aDevice); + int is_open (void); + int open (void); + void read (uchar* buf, uchar* dev, int count); + void rawread (uchar* buf, int packetCount); + void rebuildInfoDatabase (void); + int write (int aDevice, int aByte); + int write (int aDevice, uchar* bytes, int count); + int write (int aDevice, char* bytes, int count); + int write (int aDevice, int* bytes, int count); + + protected: + static const char* sequencer; // name of sequencer device + static int sequencer_fd; // sequencer file descriptor + static int class_count; // number of existing classes using + static uchar midi_write_packet[4]; // for writing MIDI bytes out + static uchar midi_read_packet[4]; // for reading MIDI bytes out + static uchar synth_write_message[8]; // for writing to internal seq + static int indevcount; // number of MIDI input devices + static int outdevcount; // number of MIDI output devices + static char** indevnames; // MIDI input device names + static char** outdevnames; // MIDI output device names + static int* indevnum; // total number of MIDI inputs + static int* outdevnum; // total number of MIDI outputs + static int* indevtype; // 1 = External, 2 = Internal + static int* outdevtype; // 1 = External, 2 = Internal + static uchar synth_message_buffer[1024]; // hold bytes for synth dev + static int synth_message_buffer_count; // count of synth buffer + static int synth_message_bytes_expected; // expected count of synth + static int synth_message_curr_device; // for keeping track of dev + static int initialized; // for starting buileinfodatabase + + private: + static void buildInfoDatabase (void); + static int getFd (void); + int getInDeviceValue (int aDevice) const; + int getInputType (int aDevice) const; + int getOutDeviceValue (int aDevice) const; + int getOutputType (int aDevice) const; + void removeInfoDatabase (void); + void setFd (int anFd); + + int writeInternal(int aDevice, int aByte); + int transmitMessageToInternalSynth(void); + int transmitVoiceMessage(void); + int transmitCommonMessage(void); +}; + + +#endif /* _SEQUENCER_OSS_H_INCLUDED */ + + +// md5sum: 1df08cd946c609b9b42aadbc96b7a296 - Sequencer_oss.h =css= 20030102 diff --git a/src/midiio/include/SigTimer.h b/src/midiio/include/SigTimer.h new file mode 100644 index 0000000..e93345c --- /dev/null +++ b/src/midiio/include/SigTimer.h @@ -0,0 +1,104 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Thanks to: Erik Neuenschwander <erikn@leland.stanford.edu> +// for Windows 95 assembly code for Pentium clock cycles. +// Ozgur Izmirli <ozgur@ccrma.stanford.edu> +// for concept of periodic timer. +// Creation Date: Mon Oct 13 11:34:57 GMT-0800 1997 +// Last Modified: Tue Feb 10 21:05:19 GMT-0800 1998 +// Last Modified: Sat Sep 19 15:56:48 PDT 1998 +// Last Modified: Mon Feb 22 04:44:25 PST 1999 +// Last Modified: Sun Nov 28 12:39:39 PST 1999 (added adjustPeriod()) +// Filename: .../sig/code/control/SigTimer/SigTimer.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/SigTimer.h +// Syntax: C++ +// +// Description: This class can only be used on Motorola Pentinum 75 Mhz +// chips or better because the timing information is +// extracted from the clock cycle count from a register +// on the CPU itself. This class will estimate the +// speed of the computer, but it would be better if there +// was a way of finding out the speed from some function. +// This class is used primarily for timing of MIDI input +// and output at a millisecond resolution. +// +// Interesting: http://www.datasilicon.nl/I786/timer_1.htm +// + +#ifndef _SIGTIMER_H_INCLUDED +#define _SIGTIMER_H_INCLUDED + + +#ifdef VISUAL + #include <wtypes.h> + typedef LONGLONG int64bits; +#else + typedef long long int int64bits; + #include <unistd.h> /* for millisleep function */ +#endif + + +class SigTimer { + public: + SigTimer (void); + SigTimer (int aSpeed); + SigTimer (SigTimer& aTimer); + ~SigTimer (); + + void adjustPeriod (double periodDelta); + int expired (void) const; + double getPeriod (void) const; + double getPeriodCount (void) const; + double getTempo (void) const; + int getTicksPerSecond (void) const; + int getTime (void) const; + double getTimeInSeconds (void) const; + int getTimeInTicks (void) const; + void reset (void); + void setPeriod (double aPeriod); + void setTempo (double beatsPerMinute); + void setPeriodCount (double aCount); + void setTicksPerSecond (int aTickRate); + void start (void); + void sync (SigTimer& aTimer); + void update (void); + void update (int periodCount); + + // The following functions are semi-private. They do not have + // anything to do with timing themselves, but are a by-product + // of the timer implementation. They are useful, so they have + // been left public; however, they should be used judiciously. + static int getCpuSpeed (void); + static int measureCpuSpeed (int quantize = 0); + static void setCpuSpeed (int aSpeed); + + // the following function is hardware specific to Intel Pentium + // computers with a processor speed of at least 75 MHz. + // This function is the only non-portable function in this + // class, but everything else is based on it. + static int64bits clockCycles (void); + + protected: + static int64bits globalOffset; + static int cpuSpeed; + + int64bits offset; + int ticksPerSecond; + double period; + + // protected functions + double getFactor (void) const; + +}; + + +// The following function is mostly for Linux: +void millisleep(int milliseconds); +void millisleep(float milliseconds); + + +#endif /* _SIGTIMER_H_INCLUDED */ + + + +// md5sum: 601fa3caae4e3bacc4e6fb87f545c86b - SigTimer.h =css= 20030102 diff --git a/src/midiio/include/Voice.h b/src/midiio/include/Voice.h new file mode 100644 index 0000000..3cddf9f --- /dev/null +++ b/src/midiio/include/Voice.h @@ -0,0 +1,70 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Oct 11 18:21:46 PDT 1998 +// Last Modified: Sun Oct 11 18:33:04 PDT 1998 +// Filename: ...sig/maint/code/control/Voice/Voice.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/Voice.h +// Syntax: C++ +// +// Description: The Voice class is a MIDI output class which keeps +// track of the last note played in to it. If the last +// note was not turned off when a new note is played, +// then the old note will be turned off before the +// new note is played. +// + +#ifndef _VOICE_H_INCLUDED +#define _VOICE_H_INCLUDED + +#include "MidiOutput.h" + +class Voice : public MidiOutput { + public: + Voice (int aChannel); + Voice (const Voice& aVoice); + Voice (void); + ~Voice (); + + void cont (int controler, int data); + int getChan (void) const; + int getChannel (void) const; + int getKey (void) const; + int getKeynum (void) const; + int getOffTime (void) const; + int getOnTime (void) const; + int getVel (void) const; + int getVelocity (void) const; + void off (void); + void pc (int aTimbre); + void play (int aChannel, int aKeyno, int aVelocity); + void play (int aKeyno, int aVelocity); + void play (void); + void setChan (int aChannel); + void setChannel (int aChannel); + void setKey (int aKeyno); + void setKeynum (int aKeyno); + void setVel (int aVelocity); + void setVelocity (int aVelocity); + int status (void) const; + void sustain (int aStatus); + + protected: + int chan; // the current channel number + int key; // the current key number + int vel; // the current velocity value + + int onTime; // last note on message sent + int offTime; // last note off message sent + + int oldChan; // last channel played on + int oldKey; // last key to be played + int oldVel; // last velocity of last key + + static SigTimer timer; // for recording on/off times +}; + + +#endif /* _VOICE_H_INCLUDED */ + + +// md5sum: 8a5495ecc10d42be6b1832492e107723 - Voice.h =css= 20030102 diff --git a/src/midiio/include/gminstruments.h b/src/midiio/include/gminstruments.h new file mode 100644 index 0000000..0e567da --- /dev/null +++ b/src/midiio/include/gminstruments.h @@ -0,0 +1,251 @@ +// +// Copyright 1997-2000 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> (from 18Dec1997) +// Creation Date: 26 December 1997 +// Last Modified: Tue Apr 18 11:38:28 PDT 2000 (put CH_X defines here) +// Filename: ...sig/include/sigInfo/gminstruments.h +// Web Address: http://sig.sapp.org/include/sigInfo/gminstruments.h +// Syntax: C +// +// Description: Defines names for instruments as arranged in General MIDI. +// + +#ifndef _GMINSTRUMENTS_H_INCLUDED +#define _GMINSTRUMENTS_H_INCLUDED + +#define CH_1 0 +#define CH_2 1 +#define CH_3 2 +#define CH_4 3 +#define CH_5 4 +#define CH_6 5 +#define CH_7 6 +#define CH_8 7 +#define CH_9 8 +#define CH_10 9 +#define CH_11 10 +#define CH_12 11 +#define CH_13 12 +#define CH_14 13 +#define CH_15 14 +#define CH_16 15 + +#define GM_PIANO(X) (0+(X)) +#define GM_ACOUSTIC_GRAND_PIANO (0) +#define GM_BRIGHT_ACOUSTIC_PIANO (1) +#define GM_ELECTRIC_GRAND_PIANO (1) +#define GM_HONKYTONK_PIANO (2) +#define GM_HONKY_TONK_PIANO (3) +#define GM_ELECTRIC_PIANO_1 (4) +#define GM_ELECTRIC_PIANO_2 (5) +#define GM_HARPSICHORD (6) +#define GM_CLAVI (7) + +#define GM_CHROMATIC(X) (8+(X)) +#define GM_CELESTA (8) +#define GM_GLOCKENSPIEL (9) +#define GM_MUSIC_BOX (10) +#define GM_VIBRAPHONE (11) +#define GM_MARIMBA (12) +#define GM_XYLOPHONE (13) +#define GM_TUBULAR_BELLS (14) +#define GM_DULCIMER (15) + +#define GM_ORGAN(X) (16+(X)) +#define GM_DRAWBAR_ORGAN (16) +#define GM_PERCUSSIVE_ORGAN (17) +#define GM_ROCK_ORGAN (18) +#define GM_CHURCH_ORGAN (19) +#define GM_REED_ORGAN (20) +#define GM_ACCORDION (21) +#define GM_HARMONICA (22) +#define GM_TANGO_ACCORDION (23) + +#define GM_GUITAR(X) (24+(X)) +#define GM_ACOUSTIC_GUITAR_NYLON (24) +#define GM_ACOUSTIC_GUITAR_STEEL (25) +#define GM_ELECTRIC_GUITAR_JAZZ (26) +#define GM_ELECTRIC_GUITAR_CLEAN (27) +#define GM_ELECTRIC_GUITAR_MUTED (28) +#define GM_OVERDRIVEN_GUITAR (29) +#define GM_DISTORTION_GUITAR (30) +#define GM_GUITAR_HARMONICS (31) + +#define GM_BASS(X) (32+(X)) +#define GM_ACOUSTIC_BASS (32) +#define GM_ELECTRIC_BASS_FINGER (33) +#define GM_ELECTRIC_BASS_PICK (34) +#define GM_FRETLESS_BASS (35) +#define GM_SLAP_BASS_1 (36) +#define GM_SLAP_BASS_2 (37) +#define GM_SYNTH_BASS_1 (38) +#define GM_SYNTH_BASS_2 (39) + +#define GM_STRINGS(X) (40+(X)) +#define GM_VIOLIN (40) +#define GM_VIOLA (41) +#define GM_CELLO (42) +#define GM_CONTRABASS (43) +#define GM_TREMOLO_STRINGS (44) +#define GM_PIZZACATO_STRINGS (45) +#define GM_ORCHESTRAL_HARP (46) +#define GM_TIMPANI (47) + +#define GM_ENSEMBLE(X) (48+(X)) +#define GM_STRING_ENSEMBLE_1 (48) +#define GM_STRING_ENSEMBLE_2 (49) +#define GM_SYNTHSTRINGS_1 (50) +#define GM_SYNTHSTRINGS_2 (51) +#define GM_CHOIR_AAHS (52) +#define GM_VOICE_OOHS (53) +#define GM_SYNTH_VOICE (54) +#define GM_ORCHESTRA_HIT (55) + +#define GM_BRASS(X) (56+(X)) +#define GM_TRUMPET (56) +#define GM_TROMBONE (57) +#define GM_TUBA (58) +#define GM_MUTED_TRUMPED (59) +#define GM_FRENCH_HORN (60) +#define GM_BRASS_SECTION (61) +#define GM_SYNTHBRASS_1 (62) +#define GM_SYNTHBRASS_2 (63) + +#define GM_REED(X) (64+(X)) +#define GM_SOPRANO_SAX (64) +#define GM_ALTO_SAX (65) +#define GM_TENOR_SAX (66) +#define GM_BARITONE_SAX (67) +#define GM_OBOE (68) +#define GM_ENGLISH_HORN (69) +#define GM_BASSOON (70) +#define GM_CLARINET (71) + +#define GM_PIPE(X) (72+(X)) +#define GM_PICCOLO (72) +#define GM_FLUTE (73) +#define GM_RECORDER (74) +#define GM_PAN_FLUTE (75) +#define GM_BLOWN_BOTTLE (76) +#define GM_SHAKUHACHI (77) +#define GM_WHISTLE (78) +#define GM_OCARINA (79) + +#define GM_LEAD(X) (80+(X)) +#define GM_LEAD_SQUARE (80) +#define GM_LEAD_SAWTOOTH (81) +#define GM_LEAD_CALLIOPE (82) +#define GM_LEAD_CHIFF (83) +#define GM_LEAD_CHARANG (84) +#define GM_LEAD_VOICE (85) +#define GM_LEAD_FIFTHS (86) +#define GM_LEAD_BASS (87) + +#define GM_PAD(X) (88+(X)) +#define GM_PAD_NEW_AGE (88) +#define GM_PAD_WARM (89) +#define GM_PAD_POLYSYNTH (90) +#define GM_PAD_CHOIR (91) +#define GM_PAD_BOWED (92) +#define GM_PAD_METALLIC (93) +#define GM_PAD_HALO (94) +#define GM_PAD_SWEEP (95) + +#define GM_FX(X) (96+(X)) +#define GM_FX_TRAIN (96) +#define GM_FX_SOUNDTRACK (97) +#define GM_FX_CRYSTAL (98) +#define GM_FX_ATMOSPHERE (99) +#define GM_FX_BRIGHTNESS (100) +#define GM_FX_GOBLINS (101) +#define GM_FX_ECHOES (102) +#define GM_FX_SCI_FI (103) + +#define GM_ETHNIC(X) (104+(X)) +#define GM_SITAR (104) +#define GM_BANJO (105) +#define GM_SHAMISEN (106) +#define GM_KOTO (107) +#define GM_KALIMBA (108) +#define GM_BAGPIPE (109) +#define GM_FIDDLE (110) +#define GM_SHANAI (111) + +#define GM_PERCUSSION(X) (112+(X)) +#define GM_TINKLE_BELL (112) +#define GM_AGOGO (113) +#define GM_STEEL_DRUMS (114) +#define GM_WOODBLOCKS (115) +#define GM_TAIKO_DRUM (116) +#define GM_MELODIC_DRUM (117) +#define GM_SYNTH_DRUM (118) +#define GM_REVERSE_CYMBAL (119) + +#define GM_SOUNDEFFECT(X) (120+(X)) +#define GM_GUITAR_FRET_NOISE (120) +#define GM_BREATH_NOISE (121) +#define GM_SEASHORE (122) +#define GM_BIRD_TWEET (123) +#define GM_TELEPHONE_RING (124) +#define GM_HELICOPTER (125) +#define GM_APPLAUSE (126) +#define GM_GUNSHOT (127) + +// +// Percussion instruments on channel 10 +// + +#define GM_ACOUSTIC_BASS_DRUM (35) +#define GM_BASS_DRUM_1 (36) +#define GM_SIDE_STICK (37) +#define GM_ACOUSTIC_SNARE (38) +#define GM_HAND_CLAP (39) +#define GM_ELECTRIC_SNARE (40) +#define GM_LOW_FLOOR_TOM (41) +#define GM_CLOSED_HI_HAT (42) +#define GM_HIGH_FLOOR_TOM (43) +#define GM_PEDAL_HI_HAT (44) +#define GM_LOW_TOM (45) +#define GM_OPEN_HI_HAT (46) +#define GM_LOW_MID_TOM (47) +#define GM_HIGH_MID_TOM (48) +#define GM_CRASH_CYMBAL_1 (49) +#define GM_HIGH_TOM (50) +#define GM_RIDE_CYMBAL_1 (51) +#define GM_CHINESE_CYMBAL (52) +#define GM_RIDE_BELL (53) +#define GM_TAMBOURINE (54) +#define GM_SPLASH_CYMBAL (55) +#define GM_COWBELL (56) +#define GM_CRASH_CYMBAL_2 (57) +#define GM_VIBRASLAP (58) +#define GM_RIDE_CYMBAL_2 (59) +#define GM_HI_BONGO (60) +#define GM_LOW_BONGO (61) +#define GM_MUTE_HI_CONGA (62) +#define GM_OPEN_HI_CONGA (63) +#define GM_LOW_CONGA (64) +#define GM_HIGH_TIMBALE (65) +#define GM_LOW_TIMBALE (66) +#define GM_HIGH_AGOGO (67) +#define GM_LOW_AGOGO (68) +#define GM_CABASA (69) +#define GM_MARACAS (70) +#define GM_SHORT_WHISTLE (71) +#define GM_LONG_WHISTLE (72) +#define GM_SHORT_GUIRO (73) +#define GM_LONG_GUIRO (74) +#define GM_CLAVES (75) +#define GM_HI_WOOD_BLOCK (76) +#define GM_LOW_WOOD_BLOCK (77) +#define GM_MUTE_CUICA (78) +#define GM_OPEN_CUICA (79) +#define GM_MUTE_TRIANGLE (80) +#define GM_OPEN_TRIANGLE (81) + + +#endif /* _GMINSTRUMENTS_H_INCLUDED */ + + + +// md5sum: 6299d04892a6899533b9164aa9e1a874 - gminstruments.h =css= 20030102 diff --git a/src/midiio/include/midichannels.h b/src/midiio/include/midichannels.h new file mode 100644 index 0000000..4526813 --- /dev/null +++ b/src/midiio/include/midichannels.h @@ -0,0 +1,42 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 21 December 1997 +// Last Modified: Wed Feb 11 22:49:59 GMT-0800 1998 +// Filename: ...sig/code/control/misc/midichannels.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/midichannels.h +// Syntax: C++ +// +// Description: Offset by 1 MIDI channel names. +// + +#ifndef _MIDICHANNELS_H_INCLUDED +#define _MIDICHANNELS_H_INCLUDED + +/* temporarily changed : + +// channel defines: offset from 0 +#define CH_1 (0x00) +#define CH_2 (0x01) +#define CH_3 (0x02) +#define CH_4 (0x03) +#define CH_5 (0x04) +#define CH_6 (0x05) +#define CH_7 (0x06) +#define CH_8 (0x07) +#define CH_9 (0x08) +#define CH_10 (0x09) +#define CH_11 (0x0a) +#define CH_12 (0x0b) +#define CH_13 (0x0c) +#define CH_14 (0x0d) +#define CH_15 (0x0e) +#define CH_16 (0x0f) + +*/ + +#endif /* _MIDICHANNELS_H_INCLUDED */ + + + + +// md5sum: 5267399f7ff90a6ea3ad2dc132afae3e - midichannels.h =css= 20030102 diff --git a/src/midiio/include/mididefines.h b/src/midiio/include/mididefines.h new file mode 100644 index 0000000..4161c2f --- /dev/null +++ b/src/midiio/include/mididefines.h @@ -0,0 +1,34 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 21 December 1997 +// Last Modified: Wed Feb 11 22:49:59 GMT-0800 1998 +// Filename: ...sig/code/control/misc/mididefines.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/mididefines.h +// Syntax: C++ +// +// Description: Collection of all of the MIDI convienience defines. +// + +#ifndef _MIDIDEFINES_H_INCLUDED +#define _MIDIDEFINES_H_INCLUDED + + +// include channel defines +#include "midichannels.h" + + +// include note name defines +#include "notenames.h" + + +// include General MIDI instrument names +#include "gminstruments.h" + + + +#endif /* _MIDIDEFINES_H_INCLUDED */ + + + + +// md5sum: 0f081c8e0b386a11e448b6088bfcd489 - mididefines.h =css= 20030102 diff --git a/src/midiio/include/midiiolib.h b/src/midiio/include/midiiolib.h new file mode 100644 index 0000000..17d0430 --- /dev/null +++ b/src/midiio/include/midiiolib.h @@ -0,0 +1,57 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sat Nov 2 20:20:24 PST 2002 +// Last Modified: Thu Jan 2 18:51:20 PST 2003 (changed name from midio.h) +// Filename: ...sig/code/misc/midiiolib.h +// Web Address: http://sig.sapp.org/include/sig/midiiolib.h +// Syntax: C++ +// +// Description: Includes all of the header files for using the midiio +// Library. +// + +#ifndef _MIDIIOLIB_H_INCLUDED +#define _MIDIIOLIB_H_INCLUDED + +#include "Array.h" +#include "CircularBuffer.h" +#include "Collection.h" +#include "FileIO.h" +#include "gminstruments.h" +#include "midichannels.h" +#include "mididefines.h" +#include "MidiFile.h" +#include "MidiFileWrite.h" +#include "MidiInPort_alsa05.h" +#include "MidiInPort_alsa.h" +#include "MidiInPort.h" +#include "MidiInPort_linux.h" +#include "MidiInPort_oss.h" +#include "MidiInPort_unsupported.h" +#include "MidiInPort_visual.h" +#include "MidiInput.h" +#include "MidiIO.h" +#include "MidiMessage.h" +#include "MidiOutPort_alsa.h" +#include "MidiOutPort.h" +#include "MidiOutPort_linux.h" +#include "MidiOutPort_oss.h" +#include "MidiOutPort_unsupported.h" +#include "MidiOutPort_visual.h" +#include "MidiOutput.h" +#include "MidiPort.h" +#include "notenames.h" +#include "Options.h" +#include "Options_private.h" +#include "Sequencer_alsa.h" +#include "Sequencer_oss.h" +#include "sigConfiguration.h" +#include "SigTimer.h" +#include "Voice.h" + + +#endif /* _MIDIIO_H_INCLUDED */ + + + +// md5sum: b389c20c620865344d827a88a0fb048d - midiiolib.h =css= 20030102 diff --git a/src/midiio/include/notenames.h b/src/midiio/include/notenames.h new file mode 100644 index 0000000..ce9d505 --- /dev/null +++ b/src/midiio/include/notenames.h @@ -0,0 +1,219 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> (from 18Dec1997) +// Creation Date: 26 December 1997 +// Last Modified: 26 December 1997 +// Filename: ...sig/code/control/misc/notenames.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/notenames.h +// Syntax: C +// +// Description: Defines for pitch names of midi key numbers +// + +#ifndef _NOTENAMES_H_INCLUDED +#define _NOTENAMES_H_INCLUDED + +#define C00 (0) +#define Cs00 (1) +#define Db00 (1) +#define D00 (2) +#define Ds00 (3) +#define Eb00 (3) +#define E00 (4) +#define F00 (5) +#define Fs00 (6) +#define Gb00 (6) +#define G00 (7) +#define Gs00 (8) +#define Ab00 (8) +#define A00 (9) +#define As00 (10) +#define Bb00 (10) +#define B00 (11) + +#define C0 (12) +#define Cs0 (13) +#define Db0 (13) +#define D0 (14) +#define Ds0 (15) +#define Eb0 (15) +#define E0 (16) +#define F0 (17) +#define Fs0 (18) +#define Gb0 (18) +#define G0 (19) +#define Gs0 (20) +#define Ab0 (20) +#define A0 (21) +#define As0 (22) +#define Bb0 (22) + +/* + * Note that the following symbol B0 is used in + * unix in the file /usr/include/termios.h also as + * a symbol, so It is disabled for now in this file. + * termios.h is need in Unix for the KeyboardInput.h file + */ + +// #define B0 (23) + +#define C1 (24) +#define Cs1 (25) +#define Db1 (25) +#define D1 (26) +#define Ds1 (27) +#define Eb1 (27) +#define E1 (28) +#define F1 (29) +#define Fs1 (30) +#define Gb1 (30) +#define G1 (31) +#define Gs1 (32) +#define Ab1 (32) +#define A1 (33) +#define As1 (34) +#define Bb1 (34) +#define B1 (35) + +#define C2 (36) +#define Cs2 (37) +#define Db2 (37) +#define D2 (38) +#define Ds2 (39) +#define Eb2 (39) +#define E2 (40) +#define F2 (41) +#define Fs2 (42) +#define Gb2 (42) +#define G2 (43) +#define Gs2 (44) +#define Ab2 (44) +#define A2 (45) +#define As2 (46) +#define Bb2 (46) +#define B2 (47) + +#define C3 (48) +#define Cs3 (49) +#define Db3 (49) +#define D3 (50) +#define Ds3 (51) +#define Eb3 (51) +#define E3 (52) +#define F3 (53) +#define Fs3 (54) +#define Gb3 (54) +#define G3 (55) +#define Gs3 (56) +#define Ab3 (56) +#define A3 (57) +#define As3 (58) +#define Bb3 (58) +#define B3 (59) + +#define C4 (60) +#define Cs4 (61) +#define Db4 (61) +#define D4 (62) +#define Ds4 (63) +#define Eb4 (63) +#define E4 (64) +#define F4 (65) +#define Fs4 (66) +#define Gb4 (66) +#define G4 (67) +#define Gs4 (68) +#define Ab4 (68) +#define A4 (69) +#define As4 (70) +#define Bb4 (70) +#define B4 (71) + +#define C5 (72) +#define Cs5 (73) +#define Db5 (73) +#define D5 (74) +#define Ds5 (75) +#define Eb5 (75) +#define E5 (76) +#define F5 (77) +#define Fs5 (78) +#define Gb5 (78) +#define G5 (79) +#define Gs5 (80) +#define Ab5 (81) +#define A5 (81) +#define As5 (82) +#define Bb5 (82) +#define B5 (83) + +#define C6 (84) +#define Cs6 (85) +#define Db6 (85) +#define D6 (86) +#define Ds6 (87) +#define Eb6 (87) +#define E6 (88) +#define F6 (89) +#define Fs6 (90) +#define Gb6 (90) +#define G6 (91) +#define Gs6 (92) +#define Ab6 (92) +#define A6 (93) +#define As6 (94) +#define Bb6 (94) +#define B6 (95) + +#define C7 (96) +#define Cs7 (97) +#define Db7 (97) +#define D7 (98) +#define Ds7 (99) +#define Eb7 (99) +#define E7 (100) +#define F7 (101) +#define Fs7 (102) +#define Gb7 (102) +#define G7 (103) +#define Gs7 (104) +#define Ab7 (104) +#define A7 (105) +#define As7 (106) +#define Bb7 (106) +#define B7 (107) + +#define C8 (108) +#define Cs8 (109) +#define Db8 (109) +#define D8 (110) +#define Ds8 (111) +#define Eb8 (111) +#define E8 (112) +#define F8 (113) +#define Fs8 (114) +#define Gb8 (114) +#define G8 (115) +#define Gs8 (116) +#define Ab8 (116) +#define A8 (117) +#define As8 (118) +#define Bb8 (118) +#define B8 (119) + +#define C9 (120) +#define Cs9 (121) +#define Db9 (121) +#define D9 (122) +#define Ds9 (123) +#define Eb9 (123) +#define E9 (124) +#define F9 (125) +#define Fs9 (126) +#define Gb9 (126) +#define G9 (127) + + +#endif /* _NOTENAMES_H_INCLUDED */ + + +// md5sum: c0f727163d32e04212a0ce5c8b6c4a6f - notenames.h =css= 20030102 diff --git a/src/midiio/include/sigConfiguration.h b/src/midiio/include/sigConfiguration.h new file mode 100644 index 0000000..b1e5f17 --- /dev/null +++ b/src/midiio/include/sigConfiguration.h @@ -0,0 +1,100 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Mon Dec 1 18:16:57 GMT-0800 1997 +// Last Modified: Mon Dec 1 18:16:57 GMT-0800 1997 +// Filename: ...sig/maint/code/misc/sigConfiguration.h +// Web Address: http://sig.sapp.org/include/sig/sigConfiguration.h +// Syntax: C +// +// Description: This file defines flags for different code setups: +// You specify the OS in a compiler flag and this file takes care +// of the rest of the defines for that OS. This file should +// automatically be included in any file which uses any of the +// define flags below. +// +// OS setup defines to use in compiling files: +// +// -DLINUX: Linux running on intel computers +// -DNEXTI: NeXT OS on Intel Hardware +// -DNEXTM: NeXT OS on Motorola Hardware +// -DSUN: Sun SPARCstations +// -DVISUAL: Windows 95/NT using Microsoft Visual C++ 5.0 +// -DHPUX: Hewlett-Packard Unix Workstations. +// -DIRIX: SGI computers with IRIX OS. +// +// +// Various options that can be defined for each OS. These +// defines may be mixed and matched in different OSes: +// +// -DOTHEREND: If the computer is little-endian, then this +// define switches the byte ordering behavior for writing/reading +// soundfiles. Intel computers need this define, most others +// will not.need this define. +// +// -DSHORTRAND: Indicates that the rand() function generates +// numbers between 0 and 0x7fff. The default without this +// option is a range between 0 and 0x7fffffff. +// +// -DINTEL: Indicates that the computer hardware uses an +// intel x86 CPU. Not used for anything right now except to +// define the endian flag (OTHEREND). +// +// -DMOTOROLA: Indicates that the computer hardware uses a +// Motorola 68k CPU. Not used for anything right now. +// +// + +#ifndef _SIGCONFIGURATION_H_INCLUDED +#define _SIGCONFIGURATION_H_INCLUDED + + +#ifdef LINUX + #define INTEL +#endif + + +#ifdef NEXTI + #define INTEL +#endif + + +#ifdef NEXT + #define MOTOROLA +#endif + + +#ifdef VISUAL + #define INTEL +#endif + + +#ifdef SUN + #define SHORTRAND +#endif + + +#ifdef HPUX + #define SHORTRAND +#endif + + +#ifdef IRIX + #define SHORTRAND +#endif + + +// These defines must come after the previous defines: + + +#ifdef INTEL + #define OTHEREND +#endif + + + +#endif /* _SIGCONFIGURATION_H_INCLUDED */ + + + +// md5sum: 32f74a7c264b158b83ff38db1ea885f8 - sigConfiguration.h =css= 20030102 diff --git a/src/midiio/src/FileIO.cpp b/src/midiio/src/FileIO.cpp new file mode 100644 index 0000000..93ef153 --- /dev/null +++ b/src/midiio/src/FileIO.cpp @@ -0,0 +1,761 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Fri May 9 22:30:32 PDT 1997 +// Last Modified: Sun Dec 14 03:29:39 GMT-0800 1997 +// Filename: ...sig/maint/code/sigBase/FileIO.cpp +// Web Address: http://sig.sapp.org/src/sigBase/FileIO.cpp +// Documentation: http://sig.sapp.org/doc/classes/FileIO +// Syntax: C++ +// +// Description: Derived from the fstream class, this class has +// functions which allow writing binary files in +// both little and big endian formats. Useful for +// writing files such as soundfiles and MIDI files +// which require numbers to be stored in a particular +// endian format. +// + +#include "FileIO.h" +#include "sigConfiguration.h" + +////////////////////////////// +// +// FileIO::FileIO -- +// + +FileIO::FileIO(void) { + // do nothing +}; + +FileIO::FileIO(const char* filename, std::ios::openmode state) : +#ifdef VISUAL /* for stupid LF-CR prevention in DOS */ + std::fstream(filename, state | ios::binary) { +#else + std::fstream(filename, state) { +#endif + // do nothing +}; + + + +////////////////////////////// +// +// FileIO::~FileIO -- +// + +FileIO::~FileIO() { + // do nothing +} + + + +////////////////////////////// +// +// FileIO::readBigEndian -- +// Read numbers from a file as big endian +// + +void FileIO::readBigEndian(char& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(uchar& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(short& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(ushort& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(long& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(ulong& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(int& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(uint& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(float& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(double& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + + + +////////////////////////////// +// +// FileIO::readLittleEndian -- +// Read numbers from a file as little endian +// + +void FileIO::readLittleEndian(char& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(uchar& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(short& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(ushort& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(long& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(ulong& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(int& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(uint& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(float& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(double& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + + + +////////////////////////////// +// +// FileIO::readMachineEndian -- +// Read numbers from a file in the same endian as the computer. +// + +void FileIO::readMachineEndian(char& aNumber) { + this->read(&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(uchar& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(short& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(ushort& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(long& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(ulong& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(int& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(uint& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(float& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(double& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + + + +////////////////////////////// +// +// FileIO::readNotMachineEndian -- +// Read numbers from a file with different endian from the computer. +// + +void FileIO::readNotMachineEndian(char& aNumber) { + this->read(&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(uchar& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(short& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(ushort& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(long& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(ulong& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(int& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(uint& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(float& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(double& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + + + +////////////////////////////// +// +// FileIO::writeBigEndian -- +// + +void FileIO::writeBigEndian(char aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(uchar aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(short aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(ushort aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(long aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(ulong aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(int aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(uint aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(float aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(double aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + + + +////////////////////////////// +// +// FileIO::writeLittleEndian -- +// + +void FileIO::writeLittleEndian(char aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(uchar aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(short aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(ushort aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(long aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(ulong aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(int aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(uint aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(float aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(double aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + + + +////////////////////////////// +// +// FileIO::writeMachineEndian -- +// + +void FileIO::writeMachineEndian(char aNumber) { + this->write(&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(uchar aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(short aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(ushort aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(long aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(ulong aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(int aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(uint aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(float aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(double aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + + + +////////////////////////////// +// +// FileIO::writeNotMachineEndian -- +// + +void FileIO::writeNotMachineEndian(char aNumber) { + // aNumber = flipBytes(aNumber); + this->write(&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(uchar aNumber) { + // aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(short aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(ushort aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(long aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(ulong aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(int aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(uint aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(float aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(double aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + + +////////////////////////////// +// +// flipBytes -- flip the bytes in a number +// + +char FileIO::flipBytes(char aNumber) { + return aNumber; +} + + +uchar FileIO::flipBytes(uchar aNumber) { + return aNumber; +} + + +short FileIO::flipBytes(short aNumber) { + static uchar output[2]; + static uchar* input; + input = (uchar*)(&aNumber); + + output[0] = input[1]; + output[1] = input[0]; + + return *((short*)(&output)); +} + + +ushort FileIO::flipBytes(ushort aNumber) { + static uchar output[2]; + static uchar* input; + input = (uchar*)(&aNumber); + + output[0] = input[1]; + output[1] = input[0]; + + return *((ushort*)(&output)); +} + + +long FileIO::flipBytes(long aNumber) { + static uchar output[4]; + static uchar* input; + input = (uchar*)(&aNumber); + + output[0] = input[3]; + output[1] = input[2]; + output[2] = input[1]; + output[3] = input[0]; + + return *((long*)(&output)); +} + + +ulong FileIO::flipBytes(ulong aNumber) { + static uchar output[4]; + static uchar* input; + input = (uchar*)(&aNumber); + + output[0] = input[3]; + output[1] = input[2]; + output[2] = input[1]; + output[3] = input[0]; + + return *((ulong*)(&output)); +} + + +int FileIO::flipBytes(int aNumber) { + static uchar output[sizeof(uint)]; + static uchar* input; + input = (uchar*)(&aNumber); + + for(uint i=0; i<sizeof(int); i++) { + output[i] = input[sizeof(int)-1-i]; + } + + return *((int*)(&output)); +} + + +uint FileIO::flipBytes(uint aNumber) { + static uchar output[sizeof(uint)]; + static uchar* input; + input = (uchar*)(&aNumber); + + for(uint i=0; i<sizeof(uint); i++) { + output[i] = input[sizeof(uint)-1-i]; + } + + return *((uint*)(&output)); +} + + + +float FileIO::flipBytes(float aNumber) { + static uchar output[4]; + static uchar* input; + input = (uchar*)(&aNumber); + + output[0] = input[3]; + output[1] = input[2]; + output[2] = input[1]; + output[3] = input[0]; + + return *((float*)(&output)); +} + + +double FileIO::flipBytes(double aNumber) { + static uchar output[8]; + static uchar* input; + input = (uchar*)(&aNumber); + + output[0] = input[7]; + output[1] = input[6]; + output[2] = input[5]; + output[3] = input[4]; + output[4] = input[3]; + output[5] = input[2]; + output[6] = input[1]; + output[7] = input[0]; + + return *((double*)(&output)); +} + + + +/* This is what I want to use +template<class type> +type FileIO::flipBytes(type aThing) { + uchar* input = (uchar*)(&aNumber); + uchar output[sizeof(aThing)]; + + for(int i=0; i<sizeof(aThing); i++) { + output[i] = input[sizeof(aThing) - 1 - i]; + } + + return *((type*)(&output)); +} +*/ + + + +// md5sum: a82bcb961043a48d2cae34d5eaac0101 - FileIO.cpp =css= 20030102 diff --git a/src/midiio/src/MidiFile.cpp b/src/midiio/src/MidiFile.cpp new file mode 100644 index 0000000..e3307ca --- /dev/null +++ b/src/midiio/src/MidiFile.cpp @@ -0,0 +1,1200 @@ +// +// Copyright 1999 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Fri Nov 26 14:12:01 PST 1999 +// Last Modified: Fri Dec 2 13:26:29 PST 1999 +// Last Modified: Wed Dec 13 10:33:30 PST 2000 (modified sorting routine) +// Last Modified: Tue Jan 22 23:23:37 PST 2002 (allowed reading of meta events) +// Filename: ...sig/src/sigInfo/MidiFile.cpp +// Web Address: http://sig.sapp.org/src/sigInfo/MidiFile.cpp +// Syntax: C++ +// +// Description: A class which can read/write Standard MIDI files. +// MIDI data is stored by track in an array. This +// class is used for example in the MidiPerform class. +// + +#include "MidiFile.h" +#include <iomanip> + +////////////////////////////// +// +// _MFEvent::_MFEvent -- +// + +_MFEvent::_MFEvent(void) { + time = 0; + track = 0; + data.allowGrowth(); + data.setSize(0); +} + +_MFEvent::_MFEvent(int command) { + time = 0; + track = 0; + data.allowGrowth(); + data.setSize(1); + data[0] = (uchar)command; +} + +_MFEvent::_MFEvent(int command, int param1) { + time = 0; + track = 0; + data.allowGrowth(); + data.setSize(2); + data[0] = (uchar)command; + data[1] = (uchar)param1; +} + +_MFEvent::_MFEvent(int command, int param1, int param2) { + time = 0; + track = 0; + data.allowGrowth(); + data.setSize(3); + data[0] = (uchar)command; + data[1] = (uchar)param1; + data[2] = (uchar)param2; +} + +_MFEvent::_MFEvent(int aTrack, int command, int param1, int param2) { + time = 0; + track = aTrack; + data.allowGrowth(); + data.setSize(3); + data[0] = (uchar)command; + data[1] = (uchar)param1; + data[2] = (uchar)param2; +} + +_MFEvent::_MFEvent(int aTime, int aTrack, int command, int param1, int param2) { + time = aTime; + track = aTrack; + data.allowGrowth(); + data.setSize(3); + data[0] = (uchar)command; + data[1] = (uchar)param1; + data[2] = (uchar)param2; +} + + + +////////////////////////////// +// +// _MFEvent::~MFEvent +// + +_MFEvent::~_MFEvent() { + time = -1; + track = -1; + data.setSize(0); +} + + + +////////////////////////////// +// +// MidiFile::MidiFile -- +// + +MidiFile::MidiFile(void) { + ticksPerQuarterNote = 48; // time base of file + trackCount = 1; // # of tracks in file + theTrackState = TRACK_STATE_SPLIT; // joined or split + theTimeState = TIME_STATE_DELTA; // absolute or delta + events.setSize(1); + events[0] = new Collection<_MFEvent>; + events[0]->setSize(0); + events[0]->allowGrowth(1); + readFileName = new char[1]; + readFileName[0] = '\0'; +} + + +MidiFile::MidiFile(char* aFile) { + ticksPerQuarterNote = 48; // time base of file + trackCount = 1; // # of tracks in file + theTrackState = TRACK_STATE_SPLIT; // joined or split + theTimeState = TIME_STATE_DELTA; // absolute or delta + events.setSize(1); + events[0] = new Collection<_MFEvent>; + events[0]->setSize(0); + events[0]->allowGrowth(1); + readFileName = new char[1]; + readFileName[0] = '\0'; + read(aFile); +} + + + +////////////////////////////// +// +// MidiFile::~MidiFile -- +// + +MidiFile::~MidiFile() { + if (readFileName != NULL) { + delete [] readFileName; + readFileName = NULL; + } + + erase(); + + if (events[0] != NULL) { + delete events[0]; + events[0] = NULL; + } + +} + + + +////////////////////////////// +// +// MidiFile::absoluteTime -- convert the time data to +// absolute time, which means that the time field +// in the _MFEvent struct represents the exact tick +// time to play the event rather than the time since +// the last event to wait untill playing the current +// event. +// + +void MidiFile::absoluteTime(void) { + if (getTimeState() == TIME_STATE_ABSOLUTE) { + return; + } + int i, j; + int length = getNumTracks(); + int* timedata = new int[length]; + for (i=0; i<length; i++) { + timedata[i] = 0; + if (events[i]->getSize() > 0) { + timedata[i] = (*events[i])[0].time; + } else { + continue; + } + for (j=1; j<events[i]->getSize(); j++) { + timedata[i] += (*events[i])[j].time; + (*events[i])[j].time = timedata[i]; + } + } + theTimeState = TIME_STATE_ABSOLUTE; + delete [] timedata; +} + +////////////////////////////// +// +// MidiFile::addEvent -- +// + +int MidiFile::addEvent(int aTrack, int aTime, Array<uchar>& midiData) { + _MFEvent anEvent; + anEvent.time = aTime; + anEvent.track = aTrack; + anEvent.data = midiData; + + events[aTrack]->append(anEvent); + return events[aTrack]->getSize() - 1; +} + + + +////////////////////////////// +// +// MidiFile::addTrack -- adds a blank track at end of the +// track list. Returns the track number of the added +// track. +// + +int MidiFile::addTrack(void) { + int length = getNumTracks(); + events.setSize(length+1); + events[length] = new Collection<_MFEvent>; + events[length]->setSize(10000); + events[length]->setSize(0); + events[length]->allowGrowth(1); + return length; +} + +int MidiFile::addTrack(int count) { + int length = getNumTracks(); + events.setSize(length+count); + int i; + for (i=0; i<count; i++) { + events[length + i] = new Collection<_MFEvent>; + events[length + i]->setSize(10000); + events[length + i]->setSize(0); + events[length + i]->allowGrowth(1); + } + return length + count - 1; +} + + +////////////////////////////// +// +// MidiFile::allocateEvents -- +// + +void MidiFile::allocateEvents(int track, int aSize) { + int oldsize = events[track]->getSize(); + if (oldsize < aSize) { + events[track]->setSize(aSize); + events[track]->setSize(oldsize); + } +} + + + +////////////////////////////// +// +// MidiFile::deleteTrack -- remove a track from the MidiFile. +// Tracks are numbered starting at track 0. +// + +void MidiFile::deleteTrack(int aTrack) { + int length = getNumTracks(); + if (aTrack < 0 || aTrack >= length) { + return; + } + if (length == 1) { + return; + } + delete events[aTrack]; + for (int i=aTrack; i<length-1; i++) { + events[i] = events[i+1]; + } + + events[length] = NULL; + events.setSize(length-1); +} + + + +////////////////////////////// +// +// MidiFile::deltaTime -- convert the time data to +// delta time, which means that the time field +// in the _MFEvent struct represents the time +// since the last event was played. When a MIDI file +// is read from a file, this is the default setting. +// + +void MidiFile::deltaTime(void) { + if (getTimeState() == TIME_STATE_DELTA) { + return; + } + int i, j; + int temp; + int length = getNumTracks(); + int *timedata = new int[length]; + for (i=0; i<length; i++) { + timedata[i] = 0; + if (events[i]->getSize() > 0) { + timedata[i] = (*events[i])[0].time; + } else { + continue; + } + for (j=1; j<events[i]->getSize(); j++) { + temp = (*events[i])[j].time; + (*events[i])[j].time = temp - timedata[i]; + timedata[i] = temp; + } + } + theTimeState = TIME_STATE_DELTA; + delete [] timedata; +} + + + +////////////////////////////// +// +// MidiFile::erase -- make the MIDI file empty with one +// track with no data in it. +// + +void MidiFile::erase(void) { + int length = getNumTracks(); + for (int i=0; i<length; i++) { + delete events[i]; + events[i] = NULL; + } + events.setSize(1); + events[0] = new Collection<_MFEvent>; + events[0]->setSize(0); + events[0]->allowGrowth(1); +} + + +void MidiFile::clear(void) { + MidiFile::erase(); +} + + + +////////////////////////////// +// +// MidiFile::getEvent -- return the event at the given index in the +// specified track. +// + +_MFEvent& MidiFile::getEvent(int aTrack, int anIndex) { + return (*events[aTrack])[anIndex]; +} + + + +////////////////////////////// +// +// MidiFile::getTicksPerQuarterNote -- returns the number of +// time units that are supposed to occur during a quarternote. +// + +int MidiFile::getTicksPerQuarterNote(void) { + return ticksPerQuarterNote; +} + + + +////////////////////////////// +// +// MidiFile::getTrackCount -- return the number of tracks in +// the Midi File. +// + +int MidiFile::getTrackCount(void) { + return events.getSize(); +} + +int MidiFile::getNumTracks(void) { + return events.getSize(); +} + + + +////////////////////////////// +// +// MidiFile::getNumEvents -- returns the number of events +// in a given track. +// + +int MidiFile::getNumEvents(int aTrack) { + return events[aTrack]->getSize(); +} + + + +////////////////////////////// +// +// MidiFile::joinTracks -- merge the data from all tracks, +// but keeping the identity of the tracks unique so that +// the function splitTracks can be called to split the +// tracks into separate units again. The style of the +// MidiFile when read from a file is with tracks split. +// + +void MidiFile::joinTracks(void) { + if (getTrackState() == TRACK_STATE_JOINED) { + return; + } + if (getNumTracks() == 1) { + return; + } + + Collection <_MFEvent>* joinedTrack; + joinedTrack = new Collection<_MFEvent>; + joinedTrack->setSize(200000); + joinedTrack->setSize(0); + int oldTimeState = getTimeState(); + if (oldTimeState == TIME_STATE_DELTA) { + absoluteTime(); + } + int i, j; + int length = getNumTracks(); + for (i=0; i<length; i++) { + for (j=0; j<events[i]->getSize(); j++) { + joinedTrack->append((*events[i])[j]); + } + } + + erase(); + + delete events[0]; + events[0] = joinedTrack; + sortTracks(); + if (oldTimeState == TIME_STATE_DELTA) { + deltaTime(); + } +} + + + +////////////////////////////// +// +// MidiFile::mergeTracks -- combine the data from two +// tracks into one. Placing the data in the first +// track location listed, and Moving the other tracks +// in the file around to fill in the spot where Track2 +// used to be. The results of this function call cannot +// be reversed. +// + +void MidiFile::mergeTracks(int aTrack1, int aTrack2) { + Collection <_MFEvent>* mergedTrack; + mergedTrack = new Collection<_MFEvent>; + mergedTrack->setSize(0); + int oldTimeState = getTimeState(); + if (oldTimeState == TIME_STATE_DELTA) { + absoluteTime(); + } + int i, j; + int length = getNumTracks(); + for (i=0; i<events[aTrack1]->getSize(); i++) { + mergedTrack->append((*events[aTrack1])[i]); + } + for (j=0; j<events[aTrack2]->getSize(); i++) { + (*events[aTrack2])[i].track = aTrack1; + mergedTrack->append((*events[aTrack2])[i]); + } + + sortTrack(*mergedTrack); + + delete events[aTrack1]; + + events[aTrack1] = mergedTrack; + + for (i=aTrack2; i<length-1; i++) { + events[i] = events[i+1]; + } + + events[length] = NULL; + events.setSize(length-1); + + if (oldTimeState == TIME_STATE_DELTA) { + deltaTime(); + } +} + + + +////////////////////////////// +// +// MidiFile::read -- read a MIDI file and store its contents. +// + +int MidiFile::read(char* aFile) { + + #ifdef VISUAL + FileIO inputfile(aFile, std::ios::in | std::ios::nocreate | std::ios::binary); + #else + // ios::nocreate does not exists anymore in GCC 3.x + FileIO inputfile(aFile, std::ios::in /*| std::ios::nocreate */); + #endif + + if (!inputfile.is_open()) { + return 0; + } + + // Read the MIDI header (4 bytes of ID, 4 byte data size, 6 bytes + // of data. + + ulong longdata; + uchar chardata; + ushort shortdata; + + inputfile.readBigEndian(chardata); + if (chardata != 'M') { + std::cout << "File: " << aFile << " is not a MIDI file" << std::endl; + std::cout << "Chara data is" << chardata << std::endl; + return 0; + } + + inputfile.readBigEndian(chardata); + if (chardata != 'T') { + std::cout << "File: " << aFile << " is not a MIDI file" << std::endl; + return 0; + } + + inputfile.readBigEndian(chardata); + if (chardata != 'h') { + std::cout << "File: " << aFile << " is not a MIDI file" << std::endl; + return 0; + } + + inputfile.readBigEndian(chardata); + if (chardata != 'd') { + std::cout << "File: " << aFile << " is not a MIDI file" << std::endl; + return 0; + } + + // read header size + inputfile.readBigEndian(longdata); + if (longdata != 6) { + std::cout << "File: " << aFile + << " is not a MIDI 1.0 Standard MIDI file." << std::endl; + std::cout << "The header size is: " << longdata << std::endl; + return 0; + } + + // read file type + int type; + inputfile.readBigEndian(shortdata); + switch (shortdata) { + case 0: + type = 0; + break; + case 1: + type = 1; + break; + default: + std::cout << "Error: cannot handle type " << shortdata + << " MIDI file" << std::endl; + return 0; + } + + // read number of tracks + int tracks; + inputfile.readBigEndian(shortdata); + if (type == 0 && shortdata != 1) { + std::cout << "Error: Type 0 MIDI file can only contain one track" << std::endl; + return 0; + } else { + tracks = shortdata; + } + // std::cout << "Track count is: " << tracks << std::endl; + erase(); + if (events[0] != NULL) { + delete events[0]; + } + events.setSize(tracks); + for (int z=0; z<tracks; z++) { + events[z] = new Collection<_MFEvent>; + events[z]->setAllocSize(10000); + events[z]->setSize(0); + events[z]->allowGrowth(1); + } + + // read ticks per quarter note + short signeddata; + inputfile.readBigEndian(signeddata); + if (signeddata <= 0) { + std::cout << "Error: cannot handle SMTP tick values for quarter notes" + " yet" << std::endl; + return 0; + } + ticksPerQuarterNote = signeddata; + + ////////////////////////////////////////////////// + // + // now read individual tracks: + // + + uchar runningCommand = 0; + _MFEvent event; + int absticks; + int barline; + + for (int i=0; i<tracks; i++) { + // std::cout << "\nReading Track: " << i + 1 << flush; + // read track header... + + inputfile.readBigEndian(chardata); + if (chardata != 'M') { + std::cout << "File: " << aFile << " has bad track info" << std::endl; + std::cout << "character 1 is: " << (int)chardata << std::endl; + inputfile.readBigEndian(chardata); + if (inputfile.eof()) { + std::cout << "End of file reached" << std::endl; + } + return 0; + } + + inputfile.readBigEndian(chardata); + if (chardata != 'T') { + std::cout << "File: " << aFile << " has bad track info" << std::endl; + std::cout << "character 2 is: " << (int)chardata << std::endl; + return 0; + } + + inputfile.readBigEndian(chardata); + if (chardata != 'r') { + std::cout << "File: " << aFile << " has bad track info" << std::endl; + std::cout << "character 3 is: " << (int)chardata << std::endl; + return 0; + } + + inputfile.readBigEndian(chardata); + if (chardata != 'k') { + std::cout << "File: " << aFile << " has bad track info" << std::endl; + std::cout << "character 4 is: " << (int)chardata << std::endl; + return 0; + } + + // Now read track chunk size and throw it away because it is + // not really necessary since the track MUST end with an + // end of track meta event, and 50% of Midi files or so + // do not correctly give the track size. + inputfile.readBigEndian(longdata); + + // set the size of the track allocation so that it might + // approximately fit the data. + events[i]->setSize(longdata/2); + events[i]->setSize(0); + + // process the track + absticks = 0; + barline = 1; + while (!inputfile.eof()) { + longdata = extractVlvTime(inputfile); +//std::cout << "ticks = " << longdata << std::endl; + absticks += longdata; + extractMidiData(inputfile, event.data, runningCommand); +//std::cout << "command = " << std::hex << (int)event.data[0] << std::dec << std::endl; + if (event.data[0] == 0xff && (event.data[1] == 1 || + event.data[1] == 2 || event.data[1] == 3 || event.data[1] == 4)) { + // mididata.append('\0'); + // std::cout << '\t'; + // for (int m=0; m<event.data[2]; m++) { + // std::cout << event.data[m+3]; + // } + // std::cout.flush(); + } else if (event.data[0] == 0xff && event.data[1] == 0x2f) { + break; + } + + if (event.data[0] != 0xff && event.data[0] != 0xf0) { + event.time = absticks; + if ((event.data[0] & 0xf0) == 0x90) { + if (event.data[1] < 12) { + event.data[0] = event.data[1]; + switch (event.data[0]) { + case 2: event.data[2] = barline++; // barline + break; + case 0: break; // beat + } + } + } + event.track = i; + events[i]->append(event); + } else { + event.time = absticks; + event.track = i; + events[i]->append(event); + } + + } + + } + // std::cout << std::endl; + + theTimeState = TIME_STATE_ABSOLUTE; + return 1; +} + + + +////////////////////////////// +// +// MidiFile::setTicksPerQuarterNote -- +// + +void MidiFile::setTicksPerQuarterNote(int ticks) { + ticksPerQuarterNote = ticks; +} + + + +////////////////////////////// +// +// MidiFile::sortTrack -- +// + +void MidiFile::sortTrack(Collection<_MFEvent>& trackData) { + qsort(trackData.getBase(), trackData.getSize(), + sizeof(_MFEvent), eventcompare); +} + + + +////////////////////////////// +// +// MidiFile::sortTracks -- sort all tracks in the MidiFile. +// + +void MidiFile::sortTracks(void) { + for (int i=0; i<getTrackCount(); i++) { + sortTrack(*events[i]); + } +} + + + +////////////////////////////// +// +// MidiFile::splitTracks -- take the joined tracks and split them +// back into their separate track identities. +// + +void MidiFile::splitTracks(void) { + if (getTrackState() == TRACK_STATE_SPLIT) { + return; + } + + int oldTimeState = getTimeState(); + if (oldTimeState == TIME_STATE_DELTA) { + absoluteTime(); + } + + int maxTrack = 0; + int i; + int length = events[0]->getSize(); + for (i=0; i<length; i++) { + if ((*events[0])[i].track > maxTrack) { + maxTrack = (*events[0])[i].track; + } + } + + Collection<_MFEvent>* olddata = events[0]; + events[0] = NULL; + events.setSize(maxTrack); + for (i=0; i<maxTrack; i++) { + events[i] = new Collection<_MFEvent>; + events[i]->setSize(0); + events[i]->allowGrowth(); + } + + int trackValue = 0; + for (i=0; length; i++) { + trackValue = (*olddata)[i].track; + events[trackValue]->append((*olddata)[i]); + } + + delete olddata; + + if (oldTimeState == TIME_STATE_DELTA) { + deltaTime(); + } +} + + + +////////////////////////////// +// +// MidiFile::timeState -- returns what type of time method is +// being used: either TIME_STATE_ABSOLUTE or TIME_STATE_DELTA. +// + +int MidiFile::getTimeState(void) { + return theTimeState; +} + + + +////////////////////////////// +// +// MidiFile::getTrackState -- returns what type of track method +// is being used: either TRACK_STATE_JOINED or TRACK_STATE_SPLIT. +// + +int MidiFile::getTrackState(void) { + return theTrackState; +} + + + +////////////////////////////// +// +// MidiFile::write -- write a standard MIDI file from data. +// + +int MidiFile::write(const char* aFile) { + int oldTimeState = getTimeState(); + if (oldTimeState == TIME_STATE_ABSOLUTE) { + deltaTime(); + } + + #ifdef VISUAL + FileIO outputfile(aFile, ios::out | ios::noreplace | ios::binary); + #else + // ios::noreplace does not exists anymore in GCC 3.x + FileIO outputfile(aFile, std::ios::out /* | std::ios::noreplace */); + #endif + + if (!outputfile.is_open()) { + std::cout << "Error: could not write: " << aFile << std::endl; + exit(1); + } + + // write the header of the Standard MIDI File + + char ch; + // 1. The characters "MThd" + ch = 'M'; + outputfile.writeBigEndian(ch); + ch = 'T'; + outputfile.writeBigEndian(ch); + ch = 'h'; + outputfile.writeBigEndian(ch); + ch = 'd'; + outputfile.writeBigEndian(ch); + + // 2. write the size of the header (alwas a "6" stored in unsigned long + ulong longdata = 6; + outputfile.writeBigEndian(longdata); + + // 3. MIDI file format, type 0, 1, or 2 + ushort shortdata; + if (getNumTracks() == 1) { + shortdata = 0; + } else { + shortdata = 1; + } + outputfile.writeBigEndian(shortdata); + + // 4. write out the number of tracks. + shortdata = getNumTracks(); + outputfile.writeBigEndian(shortdata); + + // 5. write out the number of ticks per quarternote. (avoiding SMTPE for now) + shortdata = getTicksPerQuarterNote(); + outputfile.writeBigEndian(shortdata); + + // now write each track. + Array<uchar> trackdata; + uchar endoftrack[4] = {0, 0xff, 0x2f, 0x00}; + int i, j, k; + int size; + for (i=0; i<getNumTracks(); i++) { + trackdata.setSize(1000000); // make the track data larger than + // expected data input + trackdata.setGrowth(1000000); + trackdata.setSize(0); + trackdata.allowGrowth(); + for (j=0; j<events[i]->getSize(); j++) { + writeVLValue((*events[i])[j].time, trackdata); + for (k=0; k<(*events[i])[j].data.getSize(); k++) { + trackdata.append((*events[i])[j].data[k]); + } + } + size = trackdata.getSize(); + if ((trackdata[size-3] != 0xff) && (trackdata[size-2] != 0x2f)) { + trackdata.append(endoftrack[0]); + trackdata.append(endoftrack[1]); + trackdata.append(endoftrack[2]); + trackdata.append(endoftrack[3]); + } + + // now ready to write to MIDI file. + + // first write the track ID marker "MTrk": + ch = 'M'; + outputfile.writeBigEndian(ch); + ch = 'T'; + outputfile.writeBigEndian(ch); + ch = 'r'; + outputfile.writeBigEndian(ch); + ch = 'k'; + outputfile.writeBigEndian(ch); + + // A. write the size of the MIDI data to follow: + longdata = trackdata.getSize(); + outputfile.writeBigEndian(longdata); + + // B. write the actual data + outputfile.write((char*)trackdata.getBase(), trackdata.getSize()); + } + + if (oldTimeState == TIME_STATE_ABSOLUTE) { + absoluteTime(); + } + + outputfile.close(); + + return 1; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + + +////////////////////////////// +// +// MidiF::extractMidiData -- +// + +void MidiFile::extractMidiData(FileIO& inputfile, Array<uchar>& array, + uchar& runningCommand) { + + uchar byte; + array.setSize(0); + array.allowGrowth(); + int runningQ; + + inputfile.readBigEndian(byte); + + if (byte < 0x80) { + runningQ = 1; + if (runningCommand == 0) { + std::cout << "Error: running command with no previous command" << std::endl; + exit(1); + } + } else { + runningCommand = byte; + runningQ = 0; + } + + array.append(runningCommand); + if (runningQ) { + array.append(byte); + } + + uchar metai; + switch (runningCommand & 0xf0) { + case 0x80: // note off (2 more bytes) + case 0x90: // note on (2 more bytes) + case 0xA0: // aftertouch (2 more bytes) + case 0xB0: // cont. controller (2 more bytes) + case 0xE0: // pitch wheel (2 more bytes) + inputfile.readBigEndian(byte); + array.append(byte); + if (!runningQ) { + inputfile.readBigEndian(byte); + array.append(byte); + } + break; + case 0xC0: // patch change (1 more byte) + case 0xD0: // channel pressure (1 more byte) + if (!runningQ) { + inputfile.readBigEndian(byte); + array.append(byte); + } + break; + case 0xF0: + switch (runningCommand) { + case 0xff: // meta event + { + if (!runningQ) { + inputfile.readBigEndian(byte); // meta type + array.append(byte); + } + inputfile.readBigEndian(metai); // meta size + array.append(metai); + for (uchar j=0; j<metai; j++) { + inputfile.readBigEndian(byte); // meta data + array.append(byte); + } + } + break; + case 0xf0: // sysex + // read until you find a 0xf7 character + byte = 0; + while (byte != 0xf7 && !inputfile.eof()) { + inputfile.readBigEndian(byte); // meta data + } + break; + } + break; + default: + std::cout << "Error reading midifile" << std::endl; + std::cout << "Command byte was " << (int)runningCommand << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiF::extractVlvTime -- +// + +ulong MidiFile::extractVlvTime(FileIO& inputfile) { + uchar b[5] = {0}; + + for (int i=0; i<5; i++) { + inputfile.readBigEndian(b[i]); + if (b[i] < 0x80) { + break; + } + } + + return unpackVLV(b[0], b[1], b[2], b[3], b[4]); +} + + + +////////////////////////////// +// +// MidiF::unpackVLV -- converts a VLV value to pure unsigned long value. +// default values: a = b = c = d = e = 0; +// + +ulong MidiFile::unpackVLV(uchar a, uchar b, uchar c, uchar d, uchar e) { + if (e > 0x7f) { + std::cout << "Error: VLV value was too long" << std::endl; + exit(1); + } + + uchar bytes[5] = {a, b, c, d, e}; + int count = 0; + while (bytes[count] > 0x7f && count < 5) { + count++; + } + count++; + + ulong output = 0; + for (int i=0; i<count; i++) { + output = output << 7; + output = output | (bytes[i] & 0x7f); + } + + return output; +} + + +////////////////////////////// +// +// MidiFileWrite::writeVLValue -- write a number to the midifile +// as a variable length value which segments a file into 7-bit +// values. Maximum size of aValue is 0x7fffffff +// + +void MidiFile::writeVLValue(long aValue, Array<uchar>& outdata) { + uchar bytes[5] = {0}; + bytes[0] = (uchar)(((ulong)aValue >> 28) & 0x7f); // most significant 5 bits + bytes[1] = (uchar)(((ulong)aValue >> 21) & 0x7f); // next largest 7 bits + bytes[2] = (uchar)(((ulong)aValue >> 14) & 0x7f); + bytes[3] = (uchar)(((ulong)aValue >> 7) & 0x7f); + bytes[4] = (uchar)(((ulong)aValue) & 0x7f); // least significant 7 bits + + int start = 0; + while (start<5 && bytes[start] == 0) start++; + + for (int i=start; i<4; i++) { + bytes[i] = bytes[i] | 0x80; + outdata.append(bytes[i]); + } + outdata.append(bytes[4]); +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// external functions +// + + +////////////////////////////// +// +// eventcompare -- for sorting the tracks +// + +int eventcompare(const void* a, const void* b) { + _MFEvent& aevent = *((_MFEvent*)a); + _MFEvent& bevent = *((_MFEvent*)b); + + if (aevent.time > bevent.time) { + return 1; + } else if (aevent.time < bevent.time) { + return -1; + } else if (aevent.data[0] == 0xff && bevent.data[0] != 0xff) { + return 1; + } else if (bevent.data[0] == 0xff && aevent.data[0] != 0xff) { + return -1; + } else if (bevent.data[0] == 0xff && bevent.data[1] == 0x2f) { + return -1; + } else if (aevent.data[0] == 0xff && aevent.data[1] == 0x2f) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// operator<< -- for printing an ASCII version of the MIDI file +// + +std::ostream& operator<<(std::ostream& out, MidiFile& aMidiFile) { + int i, j, k; + out << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"; + out << "Number of Tracks: " << aMidiFile.getTrackCount() << "\n"; + out << "Time method: " << aMidiFile.getTimeState(); + if (aMidiFile.getTimeState() == TIME_STATE_DELTA) { + out << " (Delta timing)"; + } else if (aMidiFile.getTimeState() == TIME_STATE_ABSOLUTE) { + out << " (Absolute timing)"; + } else { + out << " (unknown method)"; + } + out << "\n"; + + out << "Divisions per Quarter Note: " << std::dec << aMidiFile.getTicksPerQuarterNote() << "\n"; + for (i=0; i<aMidiFile.getNumTracks(); i++) { + out << "\nTrack " << i + << " +++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"; + for (j=0; j<aMidiFile.getNumEvents(i); j++) { + out << std::dec << aMidiFile.getEvent(i, j).time << "\t" + << "0x" << std::hex << (int)aMidiFile.getEvent(i, j).data[0] << " "; + if (aMidiFile.getEvent(i, j).data[0] == 0xff) { + + if (aMidiFile.getEvent(i, j).data[1] == 0x01) { + out << "TEXT ["; + for (k=3; k<aMidiFile.getEvent(i, j).data.getSize(); k++) { + out << (char)aMidiFile.getEvent(i, j).data[k]; + } + out << "]"; + + } else if (aMidiFile.getEvent(i, j).data[1] == 0x02) { + out << "COPY ["; + for (k=3; k<aMidiFile.getEvent(i, j).data.getSize(); k++) { + out << (char)aMidiFile.getEvent(i, j).data[k]; + } + out << "]"; + + } else if (aMidiFile.getEvent(i, j).data[1] == 0x03) { + out << "TRACK ["; + for (k=3; k<aMidiFile.getEvent(i, j).data.getSize(); k++) { + out << (char)aMidiFile.getEvent(i, j).data[k]; + } + out << "]"; + + } else if (aMidiFile.getEvent(i, j).data[1] == 0x04) { + out << "INSTR ["; + for (k=3; k<aMidiFile.getEvent(i, j).data.getSize(); k++) { + out << (char)aMidiFile.getEvent(i, j).data[k]; + } + out << "]"; + + } else if (aMidiFile.getEvent(i, j).data[1] == 0x05) { + out << "LYRIC ["; + for (k=3; k<aMidiFile.getEvent(i, j).data.getSize(); k++) { + out << (char)aMidiFile.getEvent(i, j).data[k]; + } + out << "]"; + + } else { + for (k=1; k<aMidiFile.getEvent(i, j).data.getSize(); k++) { + out << std::dec << (int)aMidiFile.getEvent(i, j).data[k] << " "; + } + } + + } else { + for (k=1; k<aMidiFile.getEvent(i, j).data.getSize(); k++) { + out << std::dec << (int)aMidiFile.getEvent(i, j).data[k] << " "; + } + } + out << "\n"; + } + } + out << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"; + return out; +} + + + +// md5sum: cd4fb330dd874cc263921ec55222a199 - MidiFile.cpp =css= 20030102 diff --git a/src/midiio/src/MidiFileWrite.cpp b/src/midiio/src/MidiFileWrite.cpp new file mode 100644 index 0000000..a22e70c --- /dev/null +++ b/src/midiio/src/MidiFileWrite.cpp @@ -0,0 +1,259 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Mar 15 10:55:56 GMT-0800 1998 +// Last Modified: Sun Mar 15 10:55:56 GMT-0800 1998 +// Filename: ...sig/code/control/MidiFileWrite/MidiFileWrite.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiFileWrite.cpp +// Syntax: C++ +// +// Description: The MidiFileWrite class will write out a Type 0 MidiFile. +// Used for recording MIDI data streams into Standard +// MIDI files. +// + +#include "MidiFileWrite.h" +#include "SigTimer.h" +#include <assert.h> + + +////////////////////////////// +// +// MidiFileWrite::MidiFileWrite +// default value: startTime = -1 +// + +MidiFileWrite::MidiFileWrite(void) { + trackSize = 0; + lastPlayTime = 0; + midifile = NULL; + openQ = 0; +} + + +MidiFileWrite::MidiFileWrite(const char* aFilename, int startTime) { + trackSize = 0; + lastPlayTime = 0; + midifile = NULL; + openQ = 0; + setup(aFilename, startTime); +} + + + +////////////////////////////// +// +// MidiFileWrite::~MidiFileWrite +// + +MidiFileWrite::~MidiFileWrite() { + close(); +} + + + +////////////////////////////// +// +// MidiFileWrite::close +// + +void MidiFileWrite::close(void) { + writeRaw(0, 0xff, 0x2f, 0); // end of track meta event + + midifile->seekg(18); + midifile->writeBigEndian(trackSize); + + midifile->close(); + + midifile = NULL; + openQ = 0; +} + + + +////////////////////////////// +// +// MidiFileWrite::setup -- writes the Midi file header and +// prepares the midifile for writing of data +// default value: startTime = -1 +// + +void MidiFileWrite::setup(const char* aFilename, int startTime) { + if (openQ) { + close(); + } + + if (midifile != NULL) delete midifile; + midifile = new FileIO; + midifile->open(aFilename, std::ios::out); + + // write the header chunk + *midifile << "MThd"; // file identification: MIDI file + midifile->writeBigEndian(6L); // size of header (always 6) + midifile->writeBigEndian((short)0); // format: type 0; + midifile->writeBigEndian((short)0); // num of tracks (always 0 for type 0) + midifile->writeBigEndian((short)1000); // divisions per quarter note + + + // write the track header + *midifile << "MTrk"; + midifile->writeBigEndian(0xffffL); // the track size which will + // be corrected with close() + + + // the midifile stream is now setup for writing + // track events + + openQ = 1; + + start(); // start can be called later and will behave well + // as long as no track events have been written +} + + + +////////////////////////////// +// +// MidiFileWrite::start +// default value: startTime = -1; +// + +void MidiFileWrite::start(int startTime) { + if (startTime < 0) { + SigTimer localTime; + lastPlayTime = localTime.getTime(); + } else { + lastPlayTime = startTime; + } +} + + + +////////////////////////////// +// +// MidiFileWrite::writeAbsolute -- considers the time data +// to be the current time. It will generate a difference +// time with the previously stored last playing time. +// + +void MidiFileWrite::writeAbsolute(int aTime, int command, int p1, int p2) { + writeVLValue(aTime - lastPlayTime); + writeRaw((uchar)command, (uchar)p1, (uchar)p2); + lastPlayTime = aTime; +} + +void MidiFileWrite::writeAbsolute(int aTime, int command, int p1) { + writeVLValue(aTime - lastPlayTime); + writeRaw((uchar)command, (uchar)p1); + lastPlayTime = aTime; +} + +void MidiFileWrite::writeAbsolute(int aTime, int command) { + writeVLValue(aTime - lastPlayTime); + writeRaw((uchar)command); + lastPlayTime = aTime; +} + + + +////////////////////////////// +// +// MidiFileWrite::writeRaw -- write an event byte to the midifile +// + +void MidiFileWrite::writeRaw(uchar aByte) { + assert(midifile != NULL); + *midifile << aByte; + trackSize++; +} + + +void MidiFileWrite::writeRaw(uchar aByte, uchar bByte) { + writeRaw(aByte); + writeRaw(bByte); +} + + +void MidiFileWrite::writeRaw(uchar aByte, uchar bByte, uchar cByte) { + writeRaw(aByte); + writeRaw(bByte); + writeRaw(cByte); +} + + +void MidiFileWrite::writeRaw(uchar aByte, uchar bByte, uchar cByte, + uchar dByte) { + writeRaw(aByte); + writeRaw(bByte); + writeRaw(cByte); + writeRaw(dByte); +} + + +void MidiFileWrite::writeRaw(uchar aByte, uchar bByte, uchar cByte, + uchar dByte, uchar eByte) { + writeRaw(aByte); + writeRaw(bByte); + writeRaw(cByte); + writeRaw(dByte); + writeRaw(eByte); +} + + +void MidiFileWrite::writeRaw(uchar* anArray, int arraySize) { + for (int i=0; i<arraySize; i++) { + writeRaw(anArray[i]); + } +} + + + +////////////////////////////// +// +// MidiFileWrite::writeRelative -- cosiders the time data +// to be a delta time from the last input message. +// + +void MidiFileWrite::writeRelative(int aTime, int command, int p1, int p2) { + writeVLValue(aTime); + writeRaw((uchar)command, (uchar)p1, (uchar)p2); + lastPlayTime += aTime; +} + +void MidiFileWrite::writeRelative(int aTime, int command, int p1) { + writeVLValue(aTime); + writeRaw((uchar)command, (uchar)p1); + lastPlayTime += aTime; +} + +void MidiFileWrite::writeRelative(int aTime, int command) { + writeVLValue(aTime); + writeRaw((uchar)command); + lastPlayTime += aTime; +} + + +////////////////////////////// +// +// MidiFileWrite::writeVLValue -- write a number to the midifile +// as a variable length value which segments a file into 7-bit +// values. Maximum size of aValue is 0x7fffffff +// + +void MidiFileWrite::writeVLValue(long aValue) { + uchar bytes[5]; + bytes[0] = (uchar)((aValue >> 28) & 0x7f); // most significant 5 bits + bytes[1] = (uchar)((aValue >> 21) & 0x7f); // next largest 7 bits + bytes[2] = (uchar)((aValue >> 14) & 0x7f); + bytes[3] = (uchar)((aValue >> 7) & 0x7f); + bytes[4] = (uchar)((aValue) & 0x7f); // least significant 7 bits + + int start = 0; + while (start<5 && bytes[start] == 0) start++; + + for (int i=start; i<4; i++) { + writeRaw((uchar)(bytes[i] | 0x80)); + } + writeRaw(bytes[4]); +} + +// md5sum: 251468fa23862745f0cf36f359bccc17 - MidiFileWrite.cpp =css= 20030102 diff --git a/src/midiio/src/MidiIO.cpp b/src/midiio/src/MidiIO.cpp new file mode 100644 index 0000000..26363f2 --- /dev/null +++ b/src/midiio/src/MidiIO.cpp @@ -0,0 +1,283 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 21 December 1997 +// Last Modified: Sun Jan 25 15:45:18 GMT-0800 1998 +// Filename: ...sig/code/control/MidiIO/MidiIO.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiIO.cpp +// Syntax: C++ +// +// Description: A unified class for MidiInput and MidiOutput that handles +// MIDI input and output connections. The Synthesizer +// and RadioBaton classes are derived from this class. +// + +#include "MidiIO.h" + + +////////////////////////////// +// +// MidiIO::MidiIO +// + +MidiIO::MidiIO(void) : MidiOutput(), MidiInput() { + // does nothing +} + + +MidiIO::MidiIO(int outPort, int inPort) : + MidiOutput(outPort), MidiInput(inPort) { + // does nothing +} + + + +////////////////////////////// +// +// MidiIO::~MidiIO +// + +MidiIO::~MidiIO() { + // does nothing +} + + + +////////////////////////////// +// +// MidiIO::close +// + +void MidiIO::close(void) { + MidiInput::close(); + MidiOutput::close(); +} + + + +////////////////////////////// +// +// MidiIO::closeInput +// + +void MidiIO::closeInput(void) { + MidiInput::close(); +} + + + +////////////////////////////// +// +// MidiIO::closeOutput +// + +void MidiIO::closeOutput(void) { + MidiOutput::close(); +} + + + +////////////////////////////// +// +// MidiIO::getChannelInOffset -- return the MIDI channel offset of +// the MIDI input. +// + +int MidiIO::getChannelInOffset(void) const { + return MidiInPort::getChannelOffset(); +} + + + +////////////////////////////// +// +// MidiIO::getChannelOutOffset -- return the MIDI channel offset of +// the MIDI output. +// + +int MidiIO::getChannelOutOffset (void) const { + return MidiOutPort::getChannelOffset(); +} + + + +////////////////////////////// +// +// MidiIO::getInputPort +// + +int MidiIO::getInputPort(void) { + return MidiInput::getPort(); +} + + + +////////////////////////////// +// +// MidiIO::getInputTrace +// + +int MidiIO::getInputTrace(void) { + return MidiInput::getTrace(); +} + + + +////////////////////////////// +// +// MidiIO::getNumInputPorts +// + +int MidiIO::getNumInputPorts(void) { + return MidiInput::getNumPorts(); +} + + + +////////////////////////////// +// +// MidiIO::getNumOutputPorts +// + +int MidiIO::getNumOutputPorts(void) { + return MidiOutput::getNumPorts(); +} + + + +////////////////////////////// +// +// MidiIO::getOutputPort +// + +int MidiIO::getOutputPort(void) { + return MidiOutput::getPort(); +} + + + +////////////////////////////// +// +// MidiIO::getOutputTrace +// + +int MidiIO::getOutputTrace(void) { + return MidiOutput::getTrace(); +} + + + +////////////////////////////// +// +// MidiIO::open +// + +int MidiIO::open(void) { + if (MidiInput::open()) { + return MidiOutput::open(); + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiIO::openInput +// + +int MidiIO::openInput(void) { + return MidiInput::open(); +} + + + +////////////////////////////// +// +// MidiIO::openOutput +// + +int MidiIO::openOutput(void) { + return MidiOutput::open(); +} + + + +////////////////////////////// +// +// MidiIO::setChannelOffset -- sets the MIDI channel offset +// + +void MidiIO::setChannelOffset(int anOffset) { + MidiInPort::setChannelOffset(anOffset); + MidiOutPort::setChannelOffset(anOffset); +} + + + +////////////////////////////// +// +// MidiIO::setInputPort +// + +void MidiIO::setInputPort(int aPort) { + MidiInput::setPort(aPort); +} + + + +////////////////////////////// +// +// MidiIO::setInputTrace +// + +void MidiIO::setInputTrace(int aState) { + MidiInput::setTrace(aState); +} + + + +////////////////////////////// +// +// MidiIO::setOutputPort +// + +void MidiIO::setOutputPort(int aPort) { + MidiOutput::setPort(aPort); +} + + + +////////////////////////////// +// +// MidiIO::setOutputTrace +// + +void MidiIO::setOutputTrace(int aState) { + MidiOutput::setTrace(aState); +} + + + +////////////////////////////// +// +// MidiIO::toggleInputTrace +// + +void MidiIO::toggleInputTrace(void) { + MidiInput::toggleTrace(); +} + + +////////////////////////////// +// +// MidiIO::toggleOutputTrace +// + +void MidiIO::toggleOutputTrace(void) { + MidiOutput::toggleTrace(); +} + + + +// md5sum: 860227c67236eb6f8897ae67f1338cb0 - MidiIO.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_alsa.cpp b/src/midiio/src/MidiInPort_alsa.cpp new file mode 100644 index 0000000..55d22b0 --- /dev/null +++ b/src/midiio/src/MidiInPort_alsa.cpp @@ -0,0 +1,1038 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun May 14 22:03:16 PDT 2000 +// Last Modified: Sat Oct 13 16:11:10 PDT 2001 (updated for ALSA 0.9) +// Last Modified: Fri Oct 26 14:41:36 PDT 2001 (running status for 0xa0 and 0xd0 +// fixed by Daniel Gardner) +// Last Modified: Mon Nov 19 17:52:15 PST 2001 (thread on exit improved) +// Filename: ...sig/code/control/MidiInPort/linux/MidiInPort_alsa.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiInPort_alsa.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux ALSA sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#if defined(LINUX) && defined(ALSA) + +#include "MidiInPort_alsa.h" +#include <iostream> +#include <stdlib.h> +#include <pthread.h> +#include <alsa/asoundlib.h> +#include <unistd.h> + +#define DEFAULT_INPUT_BUFFER_SIZE (1024) + +// initialized static variables + +int MidiInPort_alsa::numDevices = 0; +int MidiInPort_alsa::objectCount = 0; +int* MidiInPort_alsa::portObjectCount = NULL; +CircularBuffer<MidiMessage>** MidiInPort_alsa::midiBuffer = NULL; +int MidiInPort_alsa::channelOffset = 0; +SigTimer MidiInPort_alsa::midiTimer; +int* MidiInPort_alsa::pauseQ = NULL; +int* MidiInPort_alsa::trace = NULL; +std::ostream* MidiInPort_alsa::tracedisplay = &std::cout; +Array<pthread_t> MidiInPort_alsa::midiInThread; +int* MidiInPort_alsa::sysexWriteBuffer = NULL; +Array<uchar>** MidiInPort_alsa::sysexBuffers = NULL; + +Array<int> MidiInPort_alsa::threadinitport; + + + +////////////////////////////// +// +// MidiInPort_alsa::MidiInPort_alsa +// default values: autoOpen = 1 +// + +MidiInPort_alsa::MidiInPort_alsa(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiInPort_alsa::MidiInPort_alsa(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::~MidiInPort_alsa +// + +MidiInPort_alsa::~MidiInPort_alsa() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cerr << "Error: bad MidiInPort_alsa object count!: " + << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::clearSysex -- clears the data from a sysex +// message and sets the allocation size to the default size (of 32 +// bytes). +// + +void MidiInPort_alsa::clearSysex(int buffer) { + buffer = 0x7f | buffer; // limit buffer range from 0 to 127 + + if (getPort() == -1) { + return; + } + + sysexBuffers[getPort()][buffer].setSize(0); + if (sysexBuffers[getPort()][buffer].getAllocSize() != 32) { + // shrink the storage buffer's size if necessary + sysexBuffers[getPort()][buffer].setAllocSize(32); + } +} + + +void MidiInPort_alsa::clearSysex(void) { + // clear all sysex buffers + for (int i=0; i<128; i++) { + clearSysex(i); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::close +// + +void MidiInPort_alsa::close(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; + Sequencer_alsa::closeInput(getPort()); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::closeAll -- +// + +void MidiInPort_alsa::closeAll(void) { + for (int i=0; i<getNumPorts(); i++) { + pauseQ[i] = 1; + Sequencer_alsa::closeInput(i); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::extract -- returns the next MIDI message +// received since that last extracted message. +// + +MidiMessage MidiInPort_alsa::extract(void) { + if (getPort() == -1) { + MidiMessage temp; + return temp; + } + + return midiBuffer[getPort()]->extract(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getBufferSize -- returns the maximum possible number +// of MIDI messages that can be stored in the buffer +// + +int MidiInPort_alsa::getBufferSize(void) { + if (getPort() == -1) return 0; + + return midiBuffer[getPort()]->getSize(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiInPort_alsa::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getCount -- returns the number of unexamined +// MIDI messages waiting in the input buffer. +// + +int MidiInPort_alsa::getCount(void) { + if (getPort() == -1) return 0; + return midiBuffer[getPort()]->getCount(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getName -- returns the name of the port. +// returns "" if no name. Name is valid until all instances +// of MIDI classes are. +// + +const char* MidiInPort_alsa::getName(void) { + if (getPort() == -1) { + return "Null ALSA MIDI Input"; + } + return getInputName(getPort()); +} + + +const char* MidiInPort_alsa::getName(int i) { + return getInputName(i); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getNumPorts -- returns the number of available +// ports for MIDI input +// + +int MidiInPort_alsa::getNumPorts(void) { + return getNumInputs(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiInPort_alsa::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getPortStatus -- 0 if closed, 1 if open +// + +int MidiInPort_alsa::getPortStatus(void) { + return is_open_in(getPort()); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getSysex -- returns the sysex message contents +// of a given buffer. You should check to see that the size is +// non-zero before looking at the data. The data pointer will +// be NULL if there is no data in the buffer. +// + +uchar* MidiInPort_alsa::getSysex(int buffer) { + buffer &= 0x7f; // limit the buffer access to indices 0 to 127. + if (getPort() == -1) { + return NULL; + } + + if (sysexBuffers[getPort()][buffer].getSize() < 2) { + return NULL; + } else { + return sysexBuffers[getPort()][buffer].getBase(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getSysexSize -- returns the sysex message byte +// count of a given buffer. Buffers are in the range from +// 0 to 127. +// + +int MidiInPort_alsa::getSysexSize(int buffer) { + if (getPort() == -1) { + return 0; + } else { + return sysexBuffers[getPort()][buffer & 0x7f].getSize(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getTrace -- returns true if trace is on or false +// if trace is off. if trace is on, then prints to standard +// output the Midi message received. +// + +int MidiInPort_alsa::getTrace(void) { + if (getPort() == -1) return -1; + + return trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::insert +// + +void MidiInPort_alsa::insert(const MidiMessage& aMessage) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->insert(aMessage); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::installSysex -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_alsa::installSysex(uchar* anArray, int aSize) { + if (getPort() == -1) { + return -1; + } else { + return installSysexPrivate(getPort(), anArray, aSize); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::installSysexPrivate -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_alsa::installSysexPrivate(int port, uchar* anArray, int aSize) { + // choose a buffer to install sysex data into: + int bufferNumber = sysexWriteBuffer[port]; + sysexWriteBuffer[port]++; + if (sysexWriteBuffer[port] >= 128) { + sysexWriteBuffer[port] = 0; + } + + // copy contents of sysex message into the chosen buffer + sysexBuffers[port][bufferNumber].setSize(aSize); + uchar* dataptr = sysexBuffers[port][bufferNumber].getBase(); + uchar* indataptr = anArray; + for (int i=0; i<aSize; i++) { + *dataptr = *indataptr; + dataptr++; + indataptr++; + } + + // return the buffer number that was used + return bufferNumber; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::message -- look at an incoming MIDI message +// without extracting it from the input buffer. +// + +MidiMessage& MidiInPort_alsa::message(int index) { + if (getPort() == -1) { + static MidiMessage x; + return x; + } + + CircularBuffer<MidiMessage>& temp = *midiBuffer[getPort()]; + return temp[index]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::open -- returns true if MIDI input port was +// opened. +// + +int MidiInPort_alsa::open(void) { + if (getPort() == -1) return 0; + + int status = Sequencer_alsa::openInput(getPort()); + if (status) { + pauseQ[getPort()] = 0; + return 1; + } else { + pauseQ[getPort()] = 1; + return 0; + } + + return 0; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::pause -- stop the Midi input port from +// inserting MIDI messages into the buffer, but keeps the +// port open. Use unpause() to reverse the effect of pause(). +// + +void MidiInPort_alsa::pause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::setBufferSize -- sets the allocation +// size of the MIDI input buffer. +// + +void MidiInPort_alsa::setBufferSize(int aSize) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->setSize(aSize); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::setChannelOffset -- sets the MIDI chan offset, +// either 0 or 1. +// + +void MidiInPort_alsa::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + std::cout << "Error: Channel offset can be only 0 or 1." << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::setPort -- +// + +void MidiInPort_alsa::setPort(int aPort) { +// if (aPort == -1) return; + if (aPort < -1 || aPort >= getNumPorts()) { +// std::cerr << "Error: maximum port number is: " << getNumPorts()-1 +// << ", but you tried to access port: " << aPort << std::endl; +// exit(1); + } + else { + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::setTrace -- if false, then don't print MIDI messages +// to the screen. +// + +int MidiInPort_alsa::setTrace(int aState) { + if (getPort() == -1) return -1; + + + int oldtrace = trace[getPort()]; + if (aState == 0) { + trace[getPort()] = 0; + } else { + trace[getPort()] = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::toggleTrace -- switches the state of trace +// Returns the previous value of the trace variable. +// + +void MidiInPort_alsa::toggleTrace(void) { + if (getPort() == -1) return; + + trace[getPort()] = !trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::unpause -- enables the Midi input port +// to inserting MIDI messages into the buffer after the +// port is already open. +// + +void MidiInPort_alsa::unpause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 0; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiInPort_alsa::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_alsa::deinitialize(void) { + closeAll(); + + for (int i=0; i<getNumPorts(); i++) { + if (sysexBuffers != NULL && sysexBuffers[i] != NULL) { + delete [] sysexBuffers[i]; + sysexBuffers[i] = NULL; + } + } + + if (sysexBuffers != NULL) { + delete [] sysexBuffers; + sysexBuffers = NULL; + } + + if (midiBuffer != NULL) { + delete [] midiBuffer; + midiBuffer = NULL; + } + + if (portObjectCount != NULL) { + delete [] portObjectCount; + portObjectCount = NULL; + } + + if (trace != NULL) { + delete [] trace; + trace = NULL; + } + + if (pauseQ != NULL) { + delete [] pauseQ; + pauseQ = NULL; + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_alsa::initialize(void) { + // set the number of ports + numDevices = Sequencer_alsa::indevcount; + + if (getNumPorts() <= 0) { +// std::cerr << "Warning: no MIDI input devices" << std::endl; + } else { + + // allocate space for pauseQ, the port pause status + if (pauseQ != NULL) { + delete [] pauseQ; + } + pauseQ = new int[numDevices]; + + // allocate space for object count on each port: + if (portObjectCount != NULL) { + delete [] portObjectCount; + } + portObjectCount = new int[numDevices]; + + // allocate space for object count on each port: + if (trace != NULL) { + delete [] trace; + } + trace = new int[numDevices]; + + // allocate space for the Midi input buffers + if (midiBuffer != NULL) { + delete [] midiBuffer; + } + midiBuffer = new CircularBuffer<MidiMessage>*[numDevices]; + + // allocate space for Midi input sysex buffer write indices + if (sysexWriteBuffer != NULL) { + delete [] sysexWriteBuffer; + } + sysexWriteBuffer = new int[numDevices]; + + // allocate space for Midi input sysex buffers + if (sysexBuffers != NULL) { + std::cout << "Error: memory leak on sysex buffers initialization" << std::endl; + exit(1); + } + sysexBuffers = new Array<uchar>*[numDevices]; + + int flag; + midiInThread.setSize(getNumPorts()); + threadinitport.setSize(getNumPorts()); + // initialize the static arrays + for (int i=0; i<getNumPorts(); i++) { + portObjectCount[i] = 0; + trace[i] = 0; + pauseQ[i] = 0; + midiBuffer[i] = new CircularBuffer<MidiMessage>; + midiBuffer[i]->setSize(DEFAULT_INPUT_BUFFER_SIZE); + + sysexWriteBuffer[i] = 0; + sysexBuffers[i] = new Array<uchar>[128]; + for (int n=0; n<128; n++) { + sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow + sysexBuffers[i][n].setAllocSize(32); + sysexBuffers[i][n].setSize(0); + sysexBuffers[i][n].setGrowth(32); // in case it will ever grow + } + + threadinitport[i] = i; + flag = pthread_create(&midiInThread[i], NULL, + interpretMidiInputStreamPrivateALSA, &threadinitport[i]); + if (flag == -1) { + std::cout << "Unable to create MIDI input thread." << std::endl; + exit(1); + } + } + + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// friendly functions +// + + +////////////////////////////// +// +// interpretMidiInputStreamPrivateALSA -- handles the MIDI input stream +// for the various input devices from the ALSA MIDI driver. +// +// Note about system exclusive messages: +// System Exclusive messages are stored in a separate buffer from +// Other Midi messages since they can be variable in length. If +// The Midi Input returns a message with command byte 0xf0, then +// the p1() byte indicates the system exclusive buffer number that is +// holding the system exclusive data for that Midi message. There +// are 128 system exclusive buffers that are numbered between +// 0 and 127. These buffers are filled in a cycle. +// To extract a System exclusive message from MidiInPort_alsa, +// you first will receive a Message with a command byte of 0xf0. +// you can then access the data for that sysex by the command: +// MidiInPort_alsa::getSysex(buffer_number), this will return +// a pointer to the beginning of the sysex data. The first byte +// of the sysex data should be 0xf0, and the last byte of the data +// is 0xf7. All other bytes of data should be in the range from +// 0 to 127. You can also get the size of the sysex buffer by the +// following command: MidiInPort_alsa::getSysexSize(buffer_number). +// This command will tell you the number of bytes in the system +// exclusive message including the starting 0xf0 and the ending 0xf7. +// +// If you want to minimize memory useage of the system exclusive +// buffers you can run the command: +// MidiInPort_alsa::clearSysex(buffer_number); Otherwise the sysex +// buffer will be erased automatically the next time that the +// buffer number is cycled through when receiving more system exclusives. +// Allocated the allocated size of the system exclusive storage will +// not be adjusted when the computer replaces the system exclusive +// message unless more storage size is needed, clearSysex however, +// will resize the sysex buffer to its default size (currently 32 bytes). +// clearSysex() without arguments will resize all buffers so that +// they are allocated to the default size and will erase data from +// all buffers. You can spoof a system exclusive message coming in +// by installing a system exclusive message and then inserting +// the system message command into the input buffer of the MidiInPort +// class, int sysex_buffer = MidiInPort_alsa::installSysex( +// uchar *data, int size); will put the data into a sysex buffer and +// return the buffer number that it was placed into. +// +// This function assumes that System Exclusive messages cannot be sent +// as a running status messages. +// +// Note about MidiMessage time stamps: +// The MidiMessage::time field is a recording of the time that the +// first byte of the MidiMessage arrived. If the message is from +// running status mode, then the time that the first parameter byte +// arrived is stored. System exclusive message arrival times are +// recoreded at the time of the last byte (0xf7) arriving. This is +// because other system messages can be coming in while the sysex +// message is coming in. Anyway, sysex messages are not really to +// be used for real time MIDI messaging, so the exact moment that the +// first byte of the sysex came in is not important to me. +// +// + +void *interpretMidiInputStreamPrivateALSA(void * arg) { + int portToWatch = *(int*)arg; + if (portToWatch < 0 || portToWatch > 1000) { + // the port to watch is invalid -- because the program has died + // before the thread function could start. Cause of invalid port + // data should be examined more carefully. + return NULL; + } + + int* argsExpected = NULL; // MIDI parameter bytes expected to follow + int* argsLeft = NULL; // MIDI parameter bytes left to wait for + uchar packet[1]; // bytes for sequencer driver + MidiMessage* message = NULL; // holder for current MIDI message + int newSigTime = 0; // for millisecond timer + int lastSigTime = -1; // for millisecond timer + int zeroSigTime = -1; // for timing incoming events + int device = -1; // for sorting out the bytes by input device + Array<uchar>* sysexIn; // MIDI Input sysex temporary storage + + // Note on the use of argsExpected and argsLeft for sysexs: + // If argsExpected is -1, then a sysex message is coming in. + // If argsLeft < 0, then the sysex message has not finished comming + // in. If argsLeft == 0 and argsExpected == -1, then the sysex + // has finished coming in and is to be sent to the correct + // location. + + // allocate space for MIDI messages, each device has a different message + // holding spot in case the messages overlap in the input stream + message = new MidiMessage[MidiInPort_alsa::numDevices]; + argsExpected = new int[MidiInPort_alsa::numDevices]; + argsLeft = new int[MidiInPort_alsa::numDevices]; + + sysexIn = new Array<uchar>[MidiInPort_alsa::numDevices]; + for (int j=0; j<MidiInPort_alsa::numDevices; j++) { + sysexIn[j].allowGrowth(); + sysexIn[j].setSize(32); + sysexIn[j].setSize(0); + sysexIn[j].setGrowth(512); + } + + // interpret MIDI bytes as they come into the computer + // and repackage them as MIDI messages. + int packetReadCount; + while (1) { +top_of_loop: + packetReadCount = 0; + + // If the all Sequencer_alsa classes have been deleted, + // then Sequencer_alsa::rawmidi_in will have zero size. + // If the size is zero, then that means the thread will be + // killed soon, and we do not want any processing to happen + // in this thread. If the port to watch is NULL, then that + // means that the MIDI input is not open, and we should not + // add any MIDI data to the input buffers. These cases are + // handled by the following if-else statement: + if (Sequencer_alsa::rawmidi_in.getSize() > 0 && + Sequencer_alsa::rawmidi_in[portToWatch] != NULL) { + packetReadCount = snd_rawmidi_read( + Sequencer_alsa::rawmidi_in[portToWatch], packet, 1); + } else { + usleep(100000); // sleep for 1/10th of a second if the Input + // port is not open. + continue; + } + + + if (packetReadCount != 1) { + // this if statement is used to prevent cases where the + // read function above will time out and return 0 bytes + // read. This if statment will also take care of -1 + // error return values by ignoring them. + continue; + } + + if (Sequencer_alsa::initialized == 0) { + continue; + } + + // determination of a full MIDI message from the input MIDI + // stream is based here on the observation that MIDI status + // bytes and subsequent data bytes are NOT returned in the same + // read() call. Rather, they are spread out over multiple read() + // returns, with only a single value per return. So if we + // find a status byte, we then determine the number of expected + // operands and process that number of subsequent read()s to + // to determine the complete midi message. + + // store the MIDI input device to which the incoming MIDI + // byte belongs. + device = portToWatch; + + // ignore the active sensing 0xfe and MIDI clock 0xf8 commands: + if (packet[0] == 0xfe || packet[0] == 0xf8) { + continue; + } + + if (packet[0] & 0x80) { // a command byte has arrived + switch (packet[0] & 0xf0) { + case 0xf0: + if (packet[0] == 0xf0) { + argsExpected[device] = -1; + argsLeft[device] = -1; + if (sysexIn[device].getSize() != 0) { + // ignore the command for now. It is most + // likely an active sensing message. + goto top_of_loop; + } else { + uchar datum = 0xf0; + sysexIn[device].append(datum); + } + } if (packet[0] == 0xf7) { + argsLeft[device] = 0; // indicates sysex is done + uchar datum = 0xf7; + sysexIn[device].append(datum); + } else if (argsExpected[device] != -1) { + // this is a system message that may or may + // not be coming while a sysex is coming in + argsExpected[device] = 0; + } else { + // this is a system message that is not coming + // while a system exclusive is coming in + //argsExpected[device] = 0; + } + break; + case 0xc0: + if (argsExpected[device] < 0) { + std::cout << "Error: received program change during sysex" + << std::endl; + exit(1); + } else { + argsExpected[device] = 1; + } + break; + case 0xd0: + if (argsExpected[device] < 0) { + std::cout << "Error: received aftertouch message during" + " sysex" << std::endl; + exit(1); + } else { + argsExpected[device] = 1; + } + break; + default: + if (argsExpected[device] < 0) { + std::cout << "Error: received another message during sysex" + << std::endl; + exit(1); + } else { + argsExpected[device] = 2; + } + break; + } + if (argsExpected[device] >= 0) { + argsLeft[device] = argsExpected[device]; + } + + newSigTime = MidiInPort_alsa::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + + if (packet[0] != 0xf7) { + message[device].p0() = packet[0]; + } + message[device].p1() = 0; + message[device].p2() = 0; + message[device].p3() = 0; + + if (packet[0] == 0xf7) { + goto sysex_done; + } + } else if (argsLeft[device]) { // not a command byte coming in + if (message[device].time == 0) { + // store the receipt time of the first message byte + newSigTime = MidiInPort_alsa::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + } + + if (argsExpected[device] < 0) { + // continue processing a sysex message + sysexIn[device].append(packet[0]); + } else { + // handle a message other than a sysex message + if (argsLeft[device] == argsExpected[device]) { + message[device].p1() = packet[0]; + } else { + message[device].p2() = packet[0]; + } + argsLeft[device]--; + } + + // if MIDI message is complete, setup for running status, and + // insert note into proper buffer. + + if (argsExpected[device] >= 0 && !argsLeft[device]) { + + // store parameter data for running status + switch (message[device].p0() & 0xf0) { + case 0xc0: argsLeft[device] = 1; break; + case 0xd0: argsLeft[device] = 1; break; // fix by dan + default: argsLeft[device] = 2; break; + // 0x80 expects two arguments + // 0x90 expects two arguments + // 0xa0 expects two arguments + // 0xb0 expects two arguments + // 0xe0 expects two arguments + } + + lastSigTime = newSigTime; + + sysex_done: // come here when a sysex is completely done + + // insert the MIDI message into the appropriate buffer + // do not insert into buffer if the MIDI input device + // is paused (which can mean closed). Or if the + // pauseQ array is pointing to NULL (which probably means that + // things are about to shut down). + if (MidiInPort_alsa::pauseQ != NULL && + MidiInPort_alsa::pauseQ[device] == 0) { + if (argsExpected[device] < 0) { + // store the sysex in the MidiInPort_alsa + // buffer for sysexs and return the storage + // location: + int sysexlocation = + MidiInPort_alsa::installSysexPrivate(device, + sysexIn[device].getBase(), + sysexIn[device].getSize()); + + message[device].p0() = 0xf0; + message[device].p1() = sysexlocation; + + sysexIn[device].setSize(0); // empty the sysex storage + argsExpected[device] = 0; // no run status for sysex + argsLeft[device] = 0; // turn off sysex input flag + } + MidiInPort_alsa::midiBuffer[device]->insert( + message[device]); +// if (MidiInPort_alsa::callbackFunction != NULL) { +// MidiInPort_alsa::callbackFunction(device); +// } + if (MidiInPort_alsa::trace[device]) { + std::cout << '[' << std::hex << (int)message[device].p0() + << ':' << std::dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << std::flush; + } + message[device].time = 0; + } else { + if (MidiInPort_alsa::trace[device]) { + std::cout << '[' << std::hex << (int)message[device].p0() + << 'P' << std::dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << std::flush; + } + } + } + } + + } // end while (1) + + // This code is not yet reached, but should be made to do so eventually + + if (message != NULL) { + delete message; + message = NULL; + } + + if (argsExpected != NULL) { + delete argsExpected; + argsExpected = NULL; + } + + if (argsLeft != NULL) { + delete argsLeft; + argsLeft = NULL; + } + + if (sysexIn != NULL) { + delete sysexIn; + sysexIn = NULL; + } + + + return NULL; +} + + + +#endif // LINUX && ALSA + + + +// md5sum: 14663a91d1f5283e05ca36399d5ab767 - MidiInPort_alsa.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_alsa05.cpp b/src/midiio/src/MidiInPort_alsa05.cpp new file mode 100644 index 0000000..1aad849 --- /dev/null +++ b/src/midiio/src/MidiInPort_alsa05.cpp @@ -0,0 +1,995 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun May 14 22:03:16 PDT 2000 +// Last Modified: Wed Oct 3 22:28:20 PDT 2001 (frozen for ALSA 0.5) +// Last Modified: Fri Oct 26 14:41:36 PDT 2001 (running status for 0xa0 and 0xd0 +// fixed by Daniel Gardner) +// Filename: ...sig/code/control/MidiInPort/linux/MidiInPort_alsa05.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiInPort_alsa05.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux ALSA sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#if defined(LINUX) && defined(ALSA05) + +#include "MidiInPort_alsa05.h" +#include <iostream.h> +#include <stdlib.h> +#include <pthread.h> +#include <sys/asoundlib.h> + +#define DEFAULT_INPUT_BUFFER_SIZE (1024) + +// initialized static variables + +int MidiInPort_alsa05::numDevices = 0; +int MidiInPort_alsa05::objectCount = 0; +int* MidiInPort_alsa05::portObjectCount = NULL; +CircularBuffer<MidiMessage>** MidiInPort_alsa05::midiBuffer = NULL; +int MidiInPort_alsa05::channelOffset = 0; +SigTimer MidiInPort_alsa05::midiTimer; +int* MidiInPort_alsa05::pauseQ = NULL; +int* MidiInPort_alsa05::trace = NULL; +ostream* MidiInPort_alsa05::tracedisplay = &cout; +Array<pthread_t> MidiInPort_alsa05::midiInThread; +int* MidiInPort_alsa05::sysexWriteBuffer = NULL; +Array<uchar>** MidiInPort_alsa05::sysexBuffers = NULL; + +Array<int> MidiInPort_alsa05::threadinitport; + + + +////////////////////////////// +// +// MidiInPort_alsa05::MidiInPort_alsa05 +// default values: autoOpen = 1 +// + +MidiInPort_alsa05::MidiInPort_alsa05(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiInPort_alsa05::MidiInPort_alsa05(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::~MidiInPort_alsa05 +// + +MidiInPort_alsa05::~MidiInPort_alsa05() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + cerr << "Error: bad MidiInPort_alsa05 object count!: " + << objectCount << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::clearSysex -- clears the data from a sysex +// message and sets the allocation size to the default size (of 32 +// bytes). +// + +void MidiInPort_alsa05::clearSysex(int buffer) { + buffer = 0x7f | buffer; // limit buffer range from 0 to 127 + + if (getPort() == -1) { + return; + } + + sysexBuffers[getPort()][buffer].setSize(0); + if (sysexBuffers[getPort()][buffer].getAllocSize() != 32) { + // shrink the storage buffer's size if necessary + sysexBuffers[getPort()][buffer].setAllocSize(32); + } +} + + +void MidiInPort_alsa05::clearSysex(void) { + // clear all sysex buffers + for (int i=0; i<128; i++) { + clearSysex(i); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::close +// + +void MidiInPort_alsa05::close(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::closeAll -- +// + +void MidiInPort_alsa05::closeAll(void) { + Sequencer_alsa05::close(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::extract -- returns the next MIDI message +// received since that last extracted message. +// + +MidiMessage MidiInPort_alsa05::extract(void) { + if (getPort() == -1) { + MidiMessage temp; + return temp; + } + + return midiBuffer[getPort()]->extract(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getBufferSize -- returns the maximum possible number +// of MIDI messages that can be stored in the buffer +// + +int MidiInPort_alsa05::getBufferSize(void) { + if (getPort() == -1) return 0; + + return midiBuffer[getPort()]->getSize(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiInPort_alsa05::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getCount -- returns the number of unexamined +// MIDI messages waiting in the input buffer. +// + +int MidiInPort_alsa05::getCount(void) { + if (getPort() == -1) return 0; + return midiBuffer[getPort()]->getCount(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getName -- returns the name of the port. +// returns "" if no name. Name is valid until all instances +// of MIDI classes are. +// + +const char* MidiInPort_alsa05::getName(void) { + if (getPort() == -1) { + return "Null ALSA MIDI Input"; + } + return getInputName(getPort()); +} + + +const char* MidiInPort_alsa05::getName(int i) { + return getInputName(i); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getNumPorts -- returns the number of available +// ports for MIDI input +// + +int MidiInPort_alsa05::getNumPorts(void) { + return getNumInputs(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiInPort_alsa05::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getPortStatus -- 0 if closed, 1 if open +// + +int MidiInPort_alsa05::getPortStatus(void) { + return is_open_in(0); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getSysex -- returns the sysex message contents +// of a given buffer. You should check to see that the size is +// non-zero before looking at the data. The data pointer will +// be NULL if there is no data in the buffer. +// + +uchar* MidiInPort_alsa05::getSysex(int buffer) { + buffer &= 0x7f; // limit the buffer access to indices 0 to 127. + if (getPort() == -1) { + return NULL; + } + + if (sysexBuffers[getPort()][buffer].getSize() < 2) { + return NULL; + } else { + return sysexBuffers[getPort()][buffer].getBase(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getSysexSize -- returns the sysex message byte +// count of a given buffer. Buffers are in the range from +// 0 to 127. +// + +int MidiInPort_alsa05::getSysexSize(int buffer) { + if (getPort() == -1) { + return 0; + } else { + return sysexBuffers[getPort()][buffer & 0x7f].getSize(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getTrace -- returns true if trace is on or false +// if trace is off. if trace is on, then prints to standard +// output the Midi message received. +// + +int MidiInPort_alsa05::getTrace(void) { + if (getPort() == -1) return -1; + + return trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::insert +// + +void MidiInPort_alsa05::insert(const MidiMessage& aMessage) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->insert(aMessage); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::installSysex -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_alsa05::installSysex(uchar* anArray, int aSize) { + if (getPort() == -1) { + return -1; + } else { + return installSysexPrivate(getPort(), anArray, aSize); + } +} + +////////////////////////////// +// +// MidiInPort_alsa05::installSysexPrivate -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_alsa05::installSysexPrivate(int port, uchar* anArray, int aSize) { + // choose a buffer to install sysex data into: + int bufferNumber = sysexWriteBuffer[port]; + sysexWriteBuffer[port]++; + if (sysexWriteBuffer[port] >= 128) { + sysexWriteBuffer[port] = 0; + } + + // copy contents of sysex message into the chosen buffer + sysexBuffers[port][bufferNumber].setSize(aSize); + uchar* dataptr = sysexBuffers[port][bufferNumber].getBase(); + uchar* indataptr = anArray; + for (int i=0; i<aSize; i++) { + *dataptr = *indataptr; + dataptr++; + indataptr++; + } + + // return the buffer number that was used + return bufferNumber; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::message +// + +MidiMessage& MidiInPort_alsa05::message(int index) { + if (getPort() == -1) { + static MidiMessage x; + return x; + } + + CircularBuffer<MidiMessage>& temp = *midiBuffer[getPort()]; + return temp[index]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::open -- returns true if MIDI input port was +// opened. +// + +int MidiInPort_alsa05::open(void) { + if (getPort() == -1) return 0; + + return Sequencer_alsa05::open(); + pauseQ[getPort()] = 0; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::pause -- stop the Midi input port from +// inserting MIDI messages into the buffer, but keeps the +// port open. Use unpause() to reverse the effect of pause(). +// + +void MidiInPort_alsa05::pause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::setBufferSize -- sets the allocation +// size of the MIDI input buffer. +// + +void MidiInPort_alsa05::setBufferSize(int aSize) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->setSize(aSize); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::setChannelOffset -- sets the MIDI chan offset, +// either 0 or 1. +// + +void MidiInPort_alsa05::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + cout << "Error: Channel offset can be only 0 or 1." << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::setPort -- +// + +void MidiInPort_alsa05::setPort(int aPort) { +// if (aPort == -1) return; + if (aPort < -1 || aPort >= getNumPorts()) { + cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::setTrace -- if false, then don't print MIDI messages +// to the screen. +// + +int MidiInPort_alsa05::setTrace(int aState) { + if (getPort() == -1) return -1; + + + int oldtrace = trace[getPort()]; + if (aState == 0) { + trace[getPort()] = 0; + } else { + trace[getPort()] = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::toggleTrace -- switches the state of trace +// Returns the previous value of the trace variable. +// + +void MidiInPort_alsa05::toggleTrace(void) { + if (getPort() == -1) return; + + trace[getPort()] = !trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::unpause -- enables the Midi input port +// to inserting MIDI messages into the buffer after the +// port is already open. +// + +void MidiInPort_alsa05::unpause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 0; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiInPort_alsa05::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_alsa05::deinitialize(void) { + closeAll(); + + for (int i=0; i<getNumPorts(); i++) { + if (sysexBuffers != NULL && sysexBuffers[i] != NULL) { + delete [] sysexBuffers[i]; + sysexBuffers[i] = NULL; + } + } + + if (sysexBuffers != NULL) { + delete [] sysexBuffers; + sysexBuffers = NULL; + } + + if (midiBuffer != NULL) { + delete [] midiBuffer; + midiBuffer = NULL; + } + + if (portObjectCount != NULL) { + delete [] portObjectCount; + portObjectCount = NULL; + } + + if (trace != NULL) { + delete [] trace; + trace = NULL; + } + + if (pauseQ != NULL) { + delete [] pauseQ; + pauseQ = NULL; + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_alsa05::initialize(void) { + // set the number of ports + numDevices = Sequencer_alsa05::indevcount; + + if (getNumPorts() <= 0) { + cerr << "Warning: no MIDI input devices" << endl; + } else { + + // allocate space for pauseQ, the port pause status + if (pauseQ != NULL) { + delete [] pauseQ; + } + pauseQ = new int[numDevices]; + + // allocate space for object count on each port: + if (portObjectCount != NULL) { + delete [] portObjectCount; + } + portObjectCount = new int[numDevices]; + + // allocate space for object count on each port: + if (trace != NULL) { + delete [] trace; + } + trace = new int[numDevices]; + + // allocate space for the Midi input buffers + if (midiBuffer != NULL) { + delete [] midiBuffer; + } + midiBuffer = new CircularBuffer<MidiMessage>*[numDevices]; + + // allocate space for Midi input sysex buffer write indices + if (sysexWriteBuffer != NULL) { + delete [] sysexWriteBuffer; + } + sysexWriteBuffer = new int[numDevices]; + + // allocate space for Midi input sysex buffers + if (sysexBuffers != NULL) { + cout << "Error: memory leak on sysex buffers initialization" << endl; + exit(1); + } + sysexBuffers = new Array<uchar>*[numDevices]; + + int flag; + midiInThread.setSize(getNumPorts()); + threadinitport.setSize(getNumPorts()); + // initialize the static arrays + for (int i=0; i<getNumPorts(); i++) { + portObjectCount[i] = 0; + trace[i] = 0; + pauseQ[i] = 0; + midiBuffer[i] = new CircularBuffer<MidiMessage>; + midiBuffer[i]->setSize(DEFAULT_INPUT_BUFFER_SIZE); + + sysexWriteBuffer[i] = 0; + sysexBuffers[i] = new Array<uchar>[128]; + for (int n=0; n<128; n++) { + sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow + sysexBuffers[i][n].setAllocSize(32); + sysexBuffers[i][n].setSize(0); + sysexBuffers[i][n].setGrowth(32); // in case it will ever grow + } + + threadinitport[i] = i; + flag = pthread_create(&midiInThread[i], NULL, + interpretMidiInputStreamPrivateALSA05, &threadinitport[i]); + if (flag == -1) { + cout << "Unable to create MIDI input thread." << endl; + exit(1); + } + } + + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// friendly functions +// + + +////////////////////////////// +// +// interpretMidiInputStreamPrivateALSA05 -- handles the MIDI input stream +// for the various input devices from the ALSA MIDI driver. +// +// Note about system exclusive messages: +// System Exclusive messages are stored in a separate buffer from +// Other Midi messages since they can be variable in length. If +// The Midi Input returns a message with command byte 0xf0, then +// the p1() byte indicates the system exclusive buffer number that is +// holding the system exclusive data for that Midi message. There +// are 128 system exclusive buffers that are numbered between +// 0 and 127. These buffers are filled in a cycle. +// To extract a System exclusive message from MidiInPort_alsa05, +// you first will receive a Message with a command byte of 0xf0. +// you can then access the data for that sysex by the command: +// MidiInPort_alsa05::getSysex(buffer_number), this will return +// a pointer to the beginning of the sysex data. The first byte +// of the sysex data should be 0xf0, and the last byte of the data +// is 0xf7. All other bytes of data should be in the range from +// 0 to 127. You can also get the size of the sysex buffer by the +// following command: MidiInPort_alsa05::getSysexSize(buffer_number). +// This command will tell you the number of bytes in the system +// exclusive message including the starting 0xf0 and the ending 0xf7. +// +// If you want to minimize memory useage of the system exclusive +// buffers you can run the command: +// MidiInPort_alsa05::clearSysex(buffer_number); Otherwise the sysex +// buffer will be erased automatically the next time that the that +// buffer number is cycled through when receiving more system exclusives. +// Allocated the allocated size of the system exclusive storage will +// not be adjusted when the computer replaces the system exclusive +// message unless more storage size is needed, clearSysex however, +// will resize the sysex buffer to its default size (currently 32 bytes). +// clearSysex() without arguments will resize all buffers so that +// they are allocated to the default size and will erase data from +// all buffers. You can spoof a system exclusive message coming in +// by installing a system exclusive message and then inserting +// the system message command into the input buffer of the MidiInPort +// class, int sysex_buffer = MidiInPort_alsa05::installSysex( +// uchar *data, int size); will put the data into a sysex buffer and +// return the buffer number that it was placed into. +// +// This function assumes that System Exclusive messages cannot be sent +// as a running status messages. +// +// Note about MidiMessage time stamps: +// The MidiMessage::time field is a recording of the time that the +// first byte of the MidiMessage arrived. If the message is from +// running status mode, then the time that the first parameter byte +// arrived is stored. System exclusive message arrival times are +// recoreded at the time of the last byte (0xf7) arriving. This is +// because other system messages can be coming in while the sysex +// message is coming in. Anyway, sysex messages are not really to +// be used for real time MIDI messaging, so the exact moment that the +// first byte of the sysex came in is not important to me. +// +// + +void *interpretMidiInputStreamPrivateALSA05(void * arg) { + int portToWatch = *(int*)arg; + + int* argsExpected = NULL; // MIDI parameter bytes expected to follow + int* argsLeft = NULL; // MIDI parameter bytes left to wait for + uchar packet[1]; // bytes for sequencer driver + MidiMessage* message = NULL; // holder for current MIDI message + int newSigTime = 0; // for millisecond timer + int lastSigTime = -1; // for millisecond timer + int zeroSigTime = -1; // for timing incoming events + int device = -1; // for sorting out the bytes by input device + Array<uchar>* sysexIn; // MIDI Input sysex temporary storage + + // Note on the use of argsExpected and argsLeft for sysexs: + // If argsExpected is -1, then a sysex message is coming in. + // If argsLeft < 0, then the sysex message has not finished comming + // in. If argsLeft == 0 and argsExpected == -1, then the sysex + // has finished coming in and is to be sent to the correct + // location. + + // allocate space for MIDI messages, each device has a different message + // holding spot in case the messages overlap in the input stream + message = new MidiMessage[MidiInPort_alsa05::numDevices]; + argsExpected = new int[MidiInPort_alsa05::numDevices]; + argsLeft = new int[MidiInPort_alsa05::numDevices]; + + sysexIn = new Array<uchar>[MidiInPort_alsa05::numDevices]; + for (int j=0; j<MidiInPort_alsa05::numDevices; j++) { + sysexIn[j].allowGrowth(); + sysexIn[j].setSize(32); + sysexIn[j].setSize(0); + sysexIn[j].setGrowth(512); + } + + // interpret MIDI bytes as they come into the computer + // and repackage them as MIDI messages. + int packetReadCount; + while (1) { +top_of_loop: + packetReadCount = snd_rawmidi_read( + Sequencer_alsa05::rawmidi_in[portToWatch], packet, 1); + if (packetReadCount != 1) { + // this if statement is used to prevent cases where the + // read function above will time out and return 0 bytes + // read. This if statment will also take care of -1 + // error return values by ignoring them. + continue; + } + + if (Sequencer_alsa05::initialized == 0) { + continue; + } + + // determination of a full MIDI message from the input MIDI + // stream is based here on the observation that MIDI status + // bytes and subsequent data bytes are NOT returned in the same + // read() call. Rather, they are spread out over multiple read() + // returns, with only a single value per return. So if we + // find a status byte, we then determine the number of expected + // operands and process that number of subsequent read()s to + // to determine the complete midi message. + + // store the MIDI input device to which the incoming MIDI + // byte belongs. + device = portToWatch; + + // ignore the active sensing 0xfe and MIDI clock 0xf8 commands: + if (packet[0] == 0xfe || packet[0] == 0xf8) { + continue; + } + + if (packet[0] & 0x80) { // a command byte has arrived + switch (packet[0] & 0xf0) { + case 0xf0: + if (packet[0] == 0xf0) { + argsExpected[device] = -1; + argsLeft[device] = -1; + if (sysexIn[device].getSize() != 0) { + // ignore the command for now. It is most + // likely an active sensing message. + goto top_of_loop; + } else { + uchar datum = 0xf0; + sysexIn[device].append(datum); + } + } if (packet[0] == 0xf7) { + argsLeft[device] = 0; // indicates sysex is done + uchar datum = 0xf7; + sysexIn[device].append(datum); + } else if (argsExpected[device] != -1) { + // this is a system message that may or may + // not be coming while a sysex is coming in + argsExpected[device] = 0; + } else { + // this is a system message that is not coming + // while a system exclusive is coming in + //argsExpected[device] = 0; + } + break; + case 0xc0: + if (argsExpected[device] < 0) { + cout << "Error: received program change during sysex" + << endl; + exit(1); + } else { + argsExpected[device] = 1; + } + break; + case 0xd0: + if (argsExpected[device] < 0) { + cout << "Error: received aftertouch message during" + " sysex" << endl; + exit(1); + } else { + argsExpected[device] = 1; + } + break; + default: + if (argsExpected[device] < 0) { + cout << "Error: received another message during sysex" + << endl; + exit(1); + } else { + argsExpected[device] = 2; + } + break; + } + if (argsExpected[device] >= 0) { + argsLeft[device] = argsExpected[device]; + } + + newSigTime = MidiInPort_alsa05::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + + if (packet[0] != 0xf7) { + message[device].p0() = packet[0]; + } + message[device].p1() = 0; + message[device].p2() = 0; + message[device].p3() = 0; + + if (packet[0] == 0xf7) { + goto sysex_done; + } + } else if (argsLeft[device]) { // not a command byte coming in + if (message[device].time == 0) { + // store the receipt time of the first message byte + newSigTime = MidiInPort_alsa05::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + } + + if (argsExpected[device] < 0) { + // continue processing a sysex message + sysexIn[device].append(packet[0]); + } else { + // handle a message other than a sysex message + if (argsLeft[device] == argsExpected[device]) { + message[device].p1() = packet[0]; + } else { + message[device].p2() = packet[0]; + } + argsLeft[device]--; + } + + // if MIDI message is complete, setup for running status, and + // insert note into proper buffer. + + if (argsExpected[device] >= 0 && !argsLeft[device]) { + + // store parameter data for running status + switch (message[device].p0() & 0xf0) { + case 0xc0: argsLeft[device] = 1; break; + case 0xd0: argsLeft[device] = 1; break; // fix by dan + default: argsLeft[device] = 2; break; + // 0x80 expects two arguments + // 0x90 expects two arguments + // 0xa0 expects two arguments + // 0xb0 expects two arguments + // 0xe0 expects two arguments + } + + lastSigTime = newSigTime; + + sysex_done: // come here when a sysex is completely done + + // insert the MIDI message into the appropriate buffer + // do not insert into buffer if the MIDI input device + // is paused (which can mean closed). Or if the + // pauseQ array is pointing to NULL (which probably means that + // things are about to shut down). + if (MidiInPort_alsa05::pauseQ != NULL && + MidiInPort_alsa05::pauseQ[device] == 0) { + if (argsExpected[device] < 0) { + // store the sysex in the MidiInPort_alsa05 + // buffer for sysexs and return the storage + // location: + int sysexlocation = + MidiInPort_alsa05::installSysexPrivate(device, + sysexIn[device].getBase(), + sysexIn[device].getSize()); + + message[device].p0() = 0xf0; + message[device].p1() = sysexlocation; + + sysexIn[device].setSize(0); // empty the sysex storage + argsExpected[device] = 0; // no run status for sysex + argsLeft[device] = 0; // turn off sysex input flag + } + MidiInPort_alsa05::midiBuffer[device]->insert( + message[device]); +// if (MidiInPort_alsa05::callbackFunction != NULL) { +// MidiInPort_alsa05::callbackFunction(device); +// } + if (MidiInPort_alsa05::trace[device]) { + cout << '[' << hex << (int)message[device].p0() + << ':' << dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << flush; + } + message[device].time = 0; + } else { + if (MidiInPort_alsa05::trace[device]) { + cout << '[' << hex << (int)message[device].p0() + << 'P' << dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << flush; + } + } + } + } + + } // end while (1) + + // This code is not yet reached, but should be made to do so eventually + + if (message != NULL) { + delete message; + message = NULL; + } + + if (argsExpected != NULL) { + delete argsExpected; + argsExpected = NULL; + } + + if (argsLeft != NULL) { + delete argsLeft; + argsLeft = NULL; + } + + if (sysexIn != NULL) { + delete sysexIn; + sysexIn = NULL; + } + + + return NULL; +} + + + +#endif /* LINUX and ALSA05 */ + + + +// md5sum: cc5ea6a6078cb534fc6c39543aa57a83 - MidiInPort_alsa05.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_linux.cpp b/src/midiio/src/MidiInPort_linux.cpp new file mode 100644 index 0000000..01274e2 --- /dev/null +++ b/src/midiio/src/MidiInPort_linux.cpp @@ -0,0 +1,491 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun May 14 22:35:27 PDT 2000 +// Last Modified: Thu May 18 23:36:00 PDT 2000 +// Last Modified: Sat Nov 2 20:37:49 PST 2002 (added ifdef ALSA OSS) +// Filename: ...sig/maint/code/control/MidiInPort/MidiInPort_linux.cpp +// Web Address: http://sig.sapp.org/include/sig/MidiInPort_linux.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of an +// operating-system specific MIDI input method. +// Provides control of all low-level MIDI input +// functionality such that it will work on all +// computers in the same manner. +// + +#ifdef LINUX +#if defined(ALSA) && defined(OSS) + +#include <sys/types.h> +#include <sys/stat.h> +#include "MidiInPort_linux.h" + + +// initialize static variables oss_input->close(); break; +int MidiInPort_linux::objectCount = 0; +int MidiInPort_linux::current = MIDI_IN_OSS_SELECT; +int MidiInPort_linux::alsaQ = 0; +int MidiInPort_linux::ossQ = 0; +MidiInPort_oss *MidiInPort_linux::oss_input = NULL; +MidiInPort_alsa *MidiInPort_linux::alsa_input = NULL; +MidiInPort_unsupported *MidiInPort_linux::unknown_input = NULL; + + +MidiInPort_linux::MidiInPort_linux(void) { + if (objectCount == 0) { + determineDrivers(); + } else if (objectCount < 0) { + cout << "Error: unusual MidiInPort_linux object count" << endl; + exit(1); + } + + objectCount++; +} + + +MidiInPort_linux::MidiInPort_linux(int aPort, int autoOpen = 1) { + if (objectCount == 0) { + determineDrivers(); + setAndOpenPort(aPort); + } else if (objectCount < 0) { + cout << "Error: unusual MidiInPort_linux object count" << endl; + exit(1); + } + + objectCount++; +} + + +MidiInPort_linux::~MidiInPort_linux() { + objectCount--; + if (objectCount == 0) { + if (oss_input != NULL) { + delete oss_input; + oss_input = NULL; + } + if (alsa_input != NULL) { + delete alsa_input; + alsa_input = NULL; + } + if (unknown_input != NULL) { + delete unknown_input; + unknown_input = NULL; + } + } + + if (objectCount < 0) { + cout << "Error: unusual MidiOutPort_linux count when destructing" << endl; + exit(1); + } +} + + +void MidiInPort_linux::clearSysex(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->clearSysex(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->clearSysex(); break; + default: unknown_input->clearSysex(); break; + } +} + + +void MidiInPort_linux::clearSysex(int buffer) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->clearSysex(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->clearSysex(); break; + default: unknown_input->clearSysex(); break; + } +} + + +void MidiInPort_linux::close(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->close(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->close(); break; + default: unknown_input->close(); break; + } +} + + +void MidiInPort_linux::closeAll(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->closeAll(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->closeAll(); break; + default: unknown_input->closeAll(); break; + } +} + + +MidiMessage MidiInPort_linux::extract(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->extract(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->extract(); break; + default: return unknown_input->extract(); break; + } +} + + +int MidiInPort_linux::getBufferSize(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getBufferSize(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getBufferSize(); break; + default: return unknown_input->getBufferSize(); break; + } +} + + +int MidiInPort_linux::getChannelOffset(void) const { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getChannelOffset(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getChannelOffset(); break; + default: return unknown_input->getChannelOffset(); break; + } +} + + +int MidiInPort_linux::getCount(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getCount(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getCount(); break; + default: return unknown_input->getCount(); break; + } +} + + +const char* MidiInPort_linux::getName(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getName(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getName(); break; + default: return unknown_input->getName(); break; + } +} + + +const char* MidiInPort_linux::getName(int i) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getName(i); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getName(i); break; + default: return unknown_input->getName(i); break; + } +} + + +int MidiInPort_linux::getNumPorts(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getNumPorts(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getNumPorts(); break; + default: return unknown_input->getNumPorts(); break; + } +} + + +int MidiInPort_linux::getPort(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getPort(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getPort(); break; + default: return unknown_input->getPort(); break; + } +} + + +int MidiInPort_linux::getPortStatus(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getPortStatus(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getPortStatus(); break; + default: return unknown_input->getPortStatus(); break; + } +} + + +uchar* MidiInPort_linux::getSysex(int buffer) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getSysex(buffer); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getSysex(buffer); break; + default: return unknown_input->getSysex(buffer); break; + } +} + + +int MidiInPort_linux::getSysexSize(int buffer) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getSysexSize(buffer); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getSysexSize(buffer); break; + default: return unknown_input->getSysexSize(buffer); break; + } +} + + +int MidiInPort_linux::getTrace(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getTrace(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getTrace(); break; + default: return unknown_input->getTrace(); break; + } +} + + +void MidiInPort_linux::insert(const MidiMessage& aMessage) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->insert(aMessage); break; + case MIDI_IN_ALSA_SELECT: alsa_input->insert(aMessage); break; + default: unknown_input->insert(aMessage); break; + } +} + + +int MidiInPort_linux::installSysex(uchar* anArray, int aSize) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: + return oss_input->installSysex(anArray, aSize); + break; + case MIDI_IN_ALSA_SELECT: + return alsa_input->installSysex(anArray, aSize); + break; + default: + return unknown_input->installSysex(anArray, aSize); + break; + } +} + + +MidiMessage& MidiInPort_linux::message(int index) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->message(index); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->message(index); break; + default: return unknown_input->message(index); break; + } +} + +int MidiInPort_linux::open(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->open(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->open(); break; + default: return unknown_input->open(); break; + } +} + + +MidiMessage& MidiInPort_linux::operator[](int index) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->message(index); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->message(index); break; + default: return unknown_input->message(index); break; + } +} + + +void MidiInPort_linux::pause(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->pause(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->pause(); break; + default: unknown_input->pause(); break; + } +} + + +void MidiInPort_linux::setBufferSize(int aSize) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->setBufferSize(aSize); break; + case MIDI_IN_ALSA_SELECT: alsa_input->setBufferSize(aSize); break; + default: unknown_input->setBufferSize(aSize); break; + } +} + + +void MidiInPort_linux::setChannelOffset(int anOffset) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->setChannelOffset(anOffset); break; + case MIDI_IN_ALSA_SELECT: alsa_input->setChannelOffset(anOffset); break; + default: unknown_input->setChannelOffset(anOffset); break; + } +} + + +void MidiInPort_linux::setAndOpenPort(int aPort) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: + oss_input->setPort(aPort); + oss_input->open(); + break; + case MIDI_IN_ALSA_SELECT: + alsa_input->setPort(aPort); + alsa_input->open(); + break; + default: + unknown_input->setPort(aPort); + unknown_input->open(); + break; + } +} + + +void MidiInPort_linux::setPort(int aPort) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->setPort(aPort); break; + case MIDI_IN_ALSA_SELECT: alsa_input->setPort(aPort); break; + default: unknown_input->setPort(aPort); break; + } +} + + +int MidiInPort_linux::setTrace(int aState) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->setTrace(aState); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->setTrace(aState); break; + default: return unknown_input->setTrace(aState); break; + } +} + + +void MidiInPort_linux::toggleTrace(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->toggleTrace(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->toggleTrace(); break; + default: unknown_input->toggleTrace(); break; + } +} + + +void MidiInPort_linux::unpause(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->unpause(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->unpause(); break; + default: unknown_input->unpause(); break; + } +} + + + +////////////////////////////// +// +// MidiInPort_linux::getSelect -- return the type of MIDI which +// is being used to send MIDI output. +// + +int MidiInPort_linux::getSelect(void) { + return current; +} + + +////////////////////////////// +// +// MidiInPort_linux::selectOSS -- select the OSS MIDI output +// returns 1 if OSS is available, otherwise returns 0. +// + +int MidiInPort_linux::selectOSS(void) { + if (ossQ) { + current = MIDI_IN_OSS_SELECT; + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_linux::selectALSA -- select the ALSA MIDI output +// returns 1 if ALSA is available, otherwise returns 0. +// + +int MidiInPort_linux::selectALSA(void) { + if (alsaQ) { + current = MIDI_IN_ALSA_SELECT; + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_linux::selectUnknown -- select the Unknown MIDI output +// returns 1 always. +// + +int MidiInPort_linux::selectUnknown(void) { + current = MIDI_IN_UNKNOWN_SELECT; + return 1; +} + + +////////////////////////////////////////////////////////////////////////// +// +// Private Functions +// + +////////////////////////////// +// +// MidiInPort_linux::determineDrivers -- see if OSS/ALSA are +// available. If /dev/sequencer is present, assume that OSS is +// available. If /dev/snd/sdq is present, assume that ALSA is +// available. +// + +void MidiInPort_linux::determineDrivers(void) { + struct stat filestats; + int status; + status = stat("/dev/sequencer", &filestats); + + if (status != 0) { + ossQ = 0; + } else { + ossQ = 1; + } + + status = stat("/dev/snd/seq", &filestats); + + if (status != 0) { + alsaQ = 0; + } else { + alsaQ = 1; + } + + + current = MIDI_IN_UNKNOWN_SELECT; + + if (ossQ) { + current = MIDI_IN_OSS_SELECT; + } + + if (alsaQ) { + current = MIDI_IN_ALSA_SELECT; + } + + // create MIDI output types which are available: + + if (oss_input != NULL) { + delete oss_input; + oss_input = NULL; + } + if (alsa_input != NULL) { + delete alsa_input; + alsa_input = NULL; + } + if (unknown_input != NULL) { + delete unknown_input; + unknown_input = NULL; + } + + if (ossQ) { + oss_input = new MidiInPort_oss; + } + if (alsaQ) { + alsa_input = new MidiInPort_alsa; + } + + unknown_input = new MidiInPort_unsupported; + +} + + +#endif /* ALSA and OSS */ +#endif /* LINUX */ + + +// md5sum: d634dd5c3b7e8c4d75b99d7459c3f073 - MidiInPort_linux.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_oss.cpp b/src/midiio/src/MidiInPort_oss.cpp new file mode 100644 index 0000000..d16c865 --- /dev/null +++ b/src/midiio/src/MidiInPort_oss.cpp @@ -0,0 +1,1036 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed Jan 21 22:46:30 GMT-0800 1998 +// Last Modified: Sat Jan 9 06:05:24 PST 1999 +// Last Modified: Tue Jun 29 16:18:45 PDT 1999 (added sysex capability) +// Last Modified: Mon Dec 6 16:28:45 PST 1999 +// Last Modified: Wed Jan 12 10:59:33 PST 2000 (orphan 0xf0 behavior change) +// Last Modified: Wed May 10 17:10:05 PDT 2000 (name change from _linux to _oss) +// Last Modified: Fri Oct 26 14:41:36 PDT 2001 (running status for 0xa0 and 0xd0 +// fixed by Daniel Gardner) +// Filename: ...sig/code/control/MidiInPort/linux/MidiInPort_oss.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiInPort_oss.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux OSS sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#ifdef LINUX + +#include "MidiInPort_oss.h" +#include <iostream> +#include <stdlib.h> +#include <pthread.h> +#include <linux/soundcard.h> + + +#define DEFAULT_INPUT_BUFFER_SIZE (1024) + +// initialized static variables + +int MidiInPort_oss::numDevices = 0; +int MidiInPort_oss::objectCount = 0; +int* MidiInPort_oss::portObjectCount = NULL; +CircularBuffer<MidiMessage>** MidiInPort_oss::midiBuffer = NULL; +int MidiInPort_oss::channelOffset = 0; +SigTimer MidiInPort_oss::midiTimer; +int* MidiInPort_oss::pauseQ = NULL; +int* MidiInPort_oss::trace = NULL; +std::ostream* MidiInPort_oss::tracedisplay = &std::cout; +pthread_t MidiInPort_oss::midiInThread; +int* MidiInPort_oss::sysexWriteBuffer = NULL; +Array<uchar>** MidiInPort_oss::sysexBuffers = NULL; + + + +////////////////////////////// +// +// MidiInPort_oss::MidiInPort_oss +// default values: autoOpen = 1 +// + +MidiInPort_oss::MidiInPort_oss(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiInPort_oss::MidiInPort_oss(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::~MidiInPort_oss +// + +MidiInPort_oss::~MidiInPort_oss() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cerr << "Error: bad MidiInPort_oss object count!: " + << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::clearSysex -- clears the data from a sysex +// message and sets the allocation size to the default size (of 32 +// bytes). +// + +void MidiInPort_oss::clearSysex(int buffer) { + buffer = 0x7f | buffer; // limit buffer range from 0 to 127 + if (getPort() == -1) { + return; + } + + sysexBuffers[getPort()][buffer].setSize(0); + if (sysexBuffers[getPort()][buffer].getAllocSize() != 32) { + // shrink the storage buffer's size if necessary + sysexBuffers[getPort()][buffer].setAllocSize(32); + } +} + + +void MidiInPort_oss::clearSysex(void) { + // clear all sysex buffers + for (int i=0; i<128; i++) { + clearSysex(i); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::close +// + +void MidiInPort_oss::close(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; +} + + + +////////////////////////////// +// +// MidiInPort_oss::closeAll -- +// + +void MidiInPort_oss::closeAll(void) { + Sequencer_oss::close(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::extract -- returns the next MIDI message +// received since that last extracted message. +// + +MidiMessage MidiInPort_oss::extract(void) { + if (getPort() == -1) { + MidiMessage temp; + return temp; + } + + return midiBuffer[getPort()]->extract(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getBufferSize -- returns the maximum possible number +// of MIDI messages that can be stored in the buffer +// + +int MidiInPort_oss::getBufferSize(void) { + if (getPort() == -1) return 0; + + return midiBuffer[getPort()]->getSize(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiInPort_oss::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiInPort_oss::getCount -- returns the number of unexamined +// MIDI messages waiting in the input buffer. +// + +int MidiInPort_oss::getCount(void) { + if (getPort() == -1) return 0; + + return midiBuffer[getPort()]->getCount(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getName -- returns the name of the port. +// returns "" if no name. Name is valid until all instances +// of MIDI classes are. +// + +const char* MidiInPort_oss::getName(void) { + if (getPort() == -1) { + return "Null OSS MIDI Input"; + } + return getInputName(getPort()); +} + + +const char* MidiInPort_oss::getName(int i) { + return getInputName(i); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getNumPorts -- returns the number of available +// ports for MIDI input +// + +int MidiInPort_oss::getNumPorts(void) { + return getNumInputs(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiInPort_oss::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiInPort_oss::getPortStatus -- 0 if closed, 1 if open +// + +int MidiInPort_oss::getPortStatus(void) { + return is_open(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getSysex -- returns the sysex message contents +// of a given buffer. You should check to see that the size is +// non-zero before looking at the data. The data pointer will +// be NULL if there is no data in the buffer. +// + +uchar* MidiInPort_oss::getSysex(int buffer) { + buffer &= 0x7f; // limit the buffer access to indices 0 to 127. + + if (getPort() == -1) { + return NULL; + } + + if (sysexBuffers[getPort()][buffer].getSize() < 2) { + return NULL; + } else { + return sysexBuffers[getPort()][buffer].getBase(); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::getSysexSize -- returns the sysex message byte +// count of a given buffer. Buffers are in the range from +// 0 to 127. +// + +int MidiInPort_oss::getSysexSize(int buffer) { + if (getPort() == -1) { + return 0; + } else { + return sysexBuffers[getPort()][buffer & 0x7f].getSize(); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::getTrace -- returns true if trace is on or false +// if trace is off. if trace is on, then prints to standard +// output the Midi message received. +// + +int MidiInPort_oss::getTrace(void) { + if (getPort() == -1) return -1; + + return trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_oss::insert +// + +void MidiInPort_oss::insert(const MidiMessage& aMessage) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->insert(aMessage); +} + + + +////////////////////////////// +// +// MidiInPort_oss::installSysex -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_oss::installSysex(uchar* anArray, int aSize) { + if (getPort() == -1) { + return -1; + } else { + return installSysexPrivate(getPort(), anArray, aSize); + } +} + +////////////////////////////// +// +// MidiInPort_oss::installSysexPrivate -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_oss::installSysexPrivate(int port, uchar* anArray, int aSize) { + // choose a buffer to install sysex data into: + int bufferNumber = sysexWriteBuffer[port]; + sysexWriteBuffer[port]++; + if (sysexWriteBuffer[port] >= 128) { + sysexWriteBuffer[port] = 0; + } + + // copy contents of sysex message into the chosen buffer + sysexBuffers[port][bufferNumber].setSize(aSize); + uchar* dataptr = sysexBuffers[port][bufferNumber].getBase(); + uchar* indataptr = anArray; + for (int i=0; i<aSize; i++) { + *dataptr = *indataptr; + dataptr++; + indataptr++; + } + + // return the buffer number that was used + return bufferNumber; +} + + + +////////////////////////////// +// +// MidiInPort_oss::message +// + +MidiMessage& MidiInPort_oss::message(int index) { + if (getPort() == -1) { + static MidiMessage x; + return x; + } + + CircularBuffer<MidiMessage>& temp = *midiBuffer[getPort()]; + return temp[index]; +} + + + +////////////////////////////// +// +// MidiInPort_oss::open -- returns true if MIDI input port was +// opened. +// + +int MidiInPort_oss::open(void) { + if (getPort() == -1) return 0; + + return Sequencer_oss::open(); + pauseQ[getPort()] = 0; +} + + + +////////////////////////////// +// +// MidiInPort_oss::pause -- stop the Midi input port from +// inserting MIDI messages into the buffer, but keeps the +// port open. Use unpause() to reverse the effect of pause(). +// + +void MidiInPort_oss::pause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; +} + + + +////////////////////////////// +// +// MidiInPort_oss::setBufferSize -- sets the allocation +// size of the MIDI input buffer. +// + +void MidiInPort_oss::setBufferSize(int aSize) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->setSize(aSize); +} + + + +////////////////////////////// +// +// MidiInPort_oss::setChannelOffset -- sets the MIDI chan offset, +// either 0 or 1. +// + +void MidiInPort_oss::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + std::cout << "Error: Channel offset can be only 0 or 1." << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::setPort +// + +void MidiInPort_oss::setPort(int aPort) { +// if (aPort == -1) return; + if (aPort < -1 || aPort >= getNumPorts()) { +// std::cerr << "Error: maximum port number is: " << getNumPorts()-1 +// << ", but you tried to access port: " << aPort << std::endl; +// exit(1); + } + else { + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::setTrace -- if false, then don't print MIDI messages +// to the screen. +// + +int MidiInPort_oss::setTrace(int aState) { + if (getPort() == -1) return -1; + + + int oldtrace = trace[getPort()]; + if (aState == 0) { + trace[getPort()] = 0; + } else { + trace[getPort()] = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiInPort_oss::toggleTrace -- switches the state of trace +// Returns the previous value of the trace variable. +// + +void MidiInPort_oss::toggleTrace(void) { + if (getPort() == -1) return; + + trace[getPort()] = !trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_oss::unpause -- enables the Midi input port +// to inserting MIDI messages into the buffer after the +// port is already open. +// + +void MidiInPort_oss::unpause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 0; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiInPort_oss::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_oss::deinitialize(void) { + closeAll(); + + for (int i=0; i<getNumPorts(); i++) { + if (sysexBuffers != NULL && sysexBuffers[i] != NULL) { + delete [] sysexBuffers[i]; + sysexBuffers[i] = NULL; + } + } + + if (sysexBuffers != NULL) { + delete [] sysexBuffers; + sysexBuffers = NULL; + } + + if (midiBuffer != NULL) { + delete [] midiBuffer; + midiBuffer = NULL; + } + + if (portObjectCount != NULL) { + delete [] portObjectCount; + portObjectCount = NULL; + } + + if (trace != NULL) { + delete [] trace; + trace = NULL; + } + + if (pauseQ != NULL) { + delete [] pauseQ; + pauseQ = NULL; + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_oss::initialize(void) { + // set the number of ports + numDevices = Sequencer_oss::indevcount; + + if (getNumPorts() <= 0) { +// std::cerr << "Warning: no MIDI input devices" << std::endl; + } else { + + // allocate space for pauseQ, the port pause status + if (pauseQ != NULL) { + delete [] pauseQ; + } + pauseQ = new int[numDevices]; + + // allocate space for object count on each port: + if (portObjectCount != NULL) { + delete [] portObjectCount; + } + portObjectCount = new int[numDevices]; + + // allocate space for object count on each port: + if (trace != NULL) { + delete [] trace; + } + trace = new int[numDevices]; + + // allocate space for the Midi input buffers + if (midiBuffer != NULL) { + delete [] midiBuffer; + } + midiBuffer = new CircularBuffer<MidiMessage>*[numDevices]; + + // allocate space for Midi input sysex buffer write indices + if (sysexWriteBuffer != NULL) { + delete [] sysexWriteBuffer; + } + sysexWriteBuffer = new int[numDevices]; + + // allocate space for Midi input sysex buffers + if (sysexBuffers != NULL) { + std::cout << "Error: memory leak on sysex buffers initialization" << std::endl; + exit(1); + } + sysexBuffers = new Array<uchar>*[numDevices]; + + // initialize the static arrays + for (int i=0; i<getNumPorts(); i++) { + portObjectCount[i] = 0; + trace[i] = 0; + pauseQ[i] = 0; + midiBuffer[i] = new CircularBuffer<MidiMessage>; + midiBuffer[i]->setSize(DEFAULT_INPUT_BUFFER_SIZE); + + sysexWriteBuffer[i] = 0; + sysexBuffers[i] = new Array<uchar>[128]; + for (int n=0; n<128; n++) { + sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow + sysexBuffers[i][n].setAllocSize(32); + sysexBuffers[i][n].setSize(0); + sysexBuffers[i][n].setGrowth(32); // in case it will ever grow + } + } + + int flag = pthread_create(&midiInThread, NULL, + interpretMidiInputStreamPrivate, NULL); + if (flag == -1) { + std::cout << "Unable to create MIDI input thread." << std::endl; + exit(1); + } + + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// friendly functions +// + + +////////////////////////////// +// +// interpretMidiInputStreamPrivate -- handles the MIDI input stream +// for the various input devices. +// +// Note about system exclusive messages: +// System Exclusive messages are stored in a separate buffer from +// Other Midi messages since they can be variable in length. If +// The Midi Input returns a message with command byte 0xf0, then +// the p1() byte indicates the system exclusive buffer number that is +// holding the system exclusive data for that Midi message. There +// are 128 system exclusive buffers that are numbered between +// 0 and 127. These buffers are filled in a cycle. +// To extract a System exclusive message from MidiInPort_oss, +// you first will receive a Message with a command byte of 0xf0. +// you can then access the data for that sysex by the command: +// MidiInPort_oss::getSysex(buffer_number), this will return +// a pointer to the beginning of the sysex data. The first byte +// of the sysex data should be 0xf0, and the last byte of the data +// is 0xf7. All other bytes of data should be in the range from +// 0 to 127. You can also get the size of the sysex buffer by the +// following command: MidiInPort_oss::getSysexSize(buffer_number). +// This command will tell you the number of bytes in the system +// exclusive message including the starting 0xf0 and the ending 0xf7. +// +// If you want to minimize memory useage of the system exclusive +// buffers you can run the command: +// MidiInPort_oss::clearSysex(buffer_number); Otherwise the sysex +// buffer will be erased automatically the next time that the that +// buffer number is cycled through when receiving more system exclusives. +// Allocated the allocated size of the system exclusive storage will +// not be adjusted when the computer replaces the system exclusive +// message unless more storage size is needed, clearSysex however, +// will resize the sysex buffer to its default size (currently 32 bytes). +// clearSysex() without arguments will resize all buffers so that +// they are allocated to the default size and will erase data from +// all buffers. You can spoof a system exclusive message coming in +// by installing a system exclusive message and then inserting +// the system message command into the input buffer of the MidiInPort +// class, int sysex_buffer = MidiInPort_oss::installSysex( +// uchar *data, int size); will put the data into a sysex buffer and +// return the buffer number that it was placed into. +// +// This function assumes that System Exclusive messages cannot be sent +// as a running status messages. +// +// Note about MidiMessage time stamps: +// The MidiMessage::time field is a recording of the time that the +// first byte of the MidiMessage arrived. If the message is from +// running status mode, then the time that the first parameter byte +// arrived is stored. System exclusive message arrival times are +// recoreded at the time of the last byte (0xf7) arriving. This is +// because other system messages can be coming in while the sysex +// message is coming in. Anyway, sysex messages are not really to +// be used for real time MIDI messaging, so the exact moment that the +// first byte of the sysex came in is not important to me. +// +// + +void *interpretMidiInputStreamPrivate(void *) { + + int* argsExpected = NULL; // MIDI parameter bytes expected to follow + int* argsLeft = NULL; // MIDI parameter bytes left to wait for + uchar packet[4]; // bytes for sequencer driver + MidiMessage* message = NULL; // holder for current MIDI message + int newSigTime = 0; // for millisecond timer + int lastSigTime = -1; // for millisecond timer + int zeroSigTime = -1; // for timing incoming events + int device = -1; // for sorting out the bytes by input device + Array<uchar>* sysexIn; // MIDI Input sysex temporary storage + + // Note on the use of argsExpected and argsLeft for sysexs: + // If argsExpected is -1, then a sysex message is coming in. + // If argsLeft < 0, then the sysex message has not finished comming + // in. If argsLeft == 0 and argsExpected == -1, then the sysex + // has finished coming in and is to be sent to the correct + // location. + + static int count = 0; + if (count != 0) { + std::cerr << "Cannot run this function more than once" << std::endl; + exit(1); + } else { + // allocate space for MIDI messages, each device has a different message + // holding spot in case the messages overlap in the input stream + message = new MidiMessage[MidiInPort_oss::numDevices]; + argsExpected = new int[MidiInPort_oss::numDevices]; + argsLeft = new int[MidiInPort_oss::numDevices]; + + sysexIn = new Array<uchar>[MidiInPort_oss::numDevices]; + for (int j=0; j<MidiInPort_oss::numDevices; j++) { + sysexIn[j].allowGrowth(); + sysexIn[j].setSize(32); + sysexIn[j].setSize(0); + sysexIn[j].setGrowth(512); + } + + count++; + } + + // interpret MIDI bytes as they come into the computer + // and repackage them as MIDI messages. + int packetReadCount; + while (1) { +top_of_loop: + packetReadCount = ::read(MidiInPort_oss::sequencer_fd, + &packet, sizeof(packet)); + + if (packetReadCount != 4) { + // this if statement is used to prevent cases where the + // read function above will time out and return 0 bytes + // read. This if statment will also take care of -1 + // error return values by ignoring them. + continue; + } + + +/* + std::cout << "packet bytes " + << " 0x" << std::hex << (int)packet[0] // packet type + << " 0x" << std::hex << (int)packet[1] // possible MIDI byte + << " 0x" << std::hex << (int)packet[2] // device number + << " 0x" << std::hex << (int)packet[3] // unused for MIDI bytes + << std::endl; +*/ + + switch (packet[0]) { + case SEQ_WAIT: + // MIDI clock ticks ... the first MIDI message deltaTime is + // calculated wrt the start of the MIDI clock. + if (zeroSigTime < 0) { + zeroSigTime = MidiInPort_oss::midiTimer.getTime(); + } +/* + int newTime; + newTime = packet[3]; + newTime = (newTime << 8) | packet[2]; + newTime = (newTime << 8) | packet[1]; +*/ + break; + + case SEQ_ECHO: + // echo events + break; + + case SEQ_MIDIPUTC: // SEQ_MIDIPUTC = 5 + // determination of a full MIDI message from the input MIDI + // stream is based here on the observation that MIDI status + // bytes and subsequent data bytes are NOT returned in the same + // read() call. Rather, they are spread out over multiple read() + // returns, with only a single value per return. So if we + // find a status byte, we then determine the number of expected + // operands and process that number of subsequent read()s to + // to determine the complete midi message. + +/* + std::cout << "MIDI byte: " << (int)packet[1] << std::endl; +*/ + + // store the MIDI input device to which the incoming MIDI + // byte belongs. + device = packet[2]; + + // ignore the active sensing 0xfe and MIDI clock 0xf8 commands: + if (packet[1] == 0xfe || packet[1] == 0xf8) { + break; + } + + if (packet[1] & 0x80) { // a command byte has arrived + switch (packet[1] & 0xf0) { + case 0xf0: + if (packet[1] == 0xf0) { + argsExpected[device] = -1; + argsLeft[device] = -1; + if (sysexIn[device].getSize() != 0) { + // ignore the command for now. It is most + // likely an active sensing message. + goto top_of_loop; + } else { + uchar datum = 0xf0; + sysexIn[device].append(datum); + } + } if (packet[1] == 0xf7) { + argsLeft[device] = 0; // indicates sysex is done + uchar datum = 0xf7; + sysexIn[device].append(datum); + } else if (argsExpected[device] != -1) { + // this is a system message that may or may + // not be coming while a sysex is coming in + argsExpected[device] = 0; + } else { + // this is a system message that is not coming + // while a system exclusive is coming in + //argsExpected[device] = 0; + } + break; + case 0xc0: + if (argsExpected[device] < 0) { + std::cout << "Error: received program change during sysex" + << std::endl; + exit(1); + } else { + argsExpected[device] = 1; + } + break; + case 0xd0: + if (argsExpected[device] < 0) { + std::cout << "Error: received aftertouch message during" + " sysex" << std::endl; + exit(1); + } else { + argsExpected[device] = 1; + } + break; + default: + if (argsExpected[device] < 0) { + std::cout << "Error: received another message during sysex" + << std::endl; + exit(1); + } else { + argsExpected[device] = 2; + } + break; + } + if (argsExpected[device] >= 0) { + argsLeft[device] = argsExpected[device]; + } + + newSigTime = MidiInPort_oss::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + + if (packet[1] != 0xf7) { + message[device].p0() = packet[1]; + } + message[device].p1() = 0; + message[device].p2() = 0; + message[device].p3() = 0; + + if (packet[1] == 0xf7) { + goto sysex_done; + } + } else if (argsLeft[device]) { // not a command byte coming in + if (message[device].time == 0) { + // store the receipt time of the first message byte + newSigTime = MidiInPort_oss::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + } + + if (argsExpected[device] < 0) { + // continue processing a sysex message + sysexIn[device].append(packet[1]); + } else { + // handle a message other than a sysex message + if (argsLeft[device] == argsExpected[device]) { + message[device].p1() = packet[1]; + } else { + message[device].p2() = packet[1]; + } + argsLeft[device]--; + } + + // if MIDI message is complete, setup for running status, and + // insert note into proper buffer. + + if (argsExpected[device] >= 0 && !argsLeft[device]) { + + // store parameter data for running status + switch (message[device].p0() & 0xf0) { + case 0xc0: argsLeft[device] = 1; break; + case 0xd0: argsLeft[device] = 1; break; // fix by dan + default: argsLeft[device] = 2; break; + // 0x80 expects two arguments + // 0x90 expects two arguments + // 0xa0 expects two arguments + // 0xb0 expects two arguments + // 0xe0 expects two arguments + } + + lastSigTime = newSigTime; + + sysex_done: // come here when a sysex is completely done + + // insert the MIDI message into the appropriate buffer + // do not insert into buffer if the MIDI input device + // is paused (which can mean closed). Or if the + // pauseQ array is pointing to NULL (which probably means that + // things are about to shut down). + if (MidiInPort_oss::pauseQ != NULL && + MidiInPort_oss::pauseQ[device] == 0) { + if (argsExpected[device] < 0) { + // store the sysex in the MidiInPort_oss + // buffer for sysexs and return the storage + // location: + int sysexlocation = + MidiInPort_oss::installSysexPrivate(device, + sysexIn[device].getBase(), + sysexIn[device].getSize()); + + message[device].p0() = 0xf0; + message[device].p1() = sysexlocation; + + sysexIn[device].setSize(0); // empty the sysex storage + argsExpected[device] = 0; // no run status for sysex + argsLeft[device] = 0; // turn off sysex input flag + } + MidiInPort_oss::midiBuffer[device]->insert( + message[device]); +// if (MidiInPort_oss::callbackFunction != NULL) { +// MidiInPort_oss::callbackFunction(device); +// } + if (MidiInPort_oss::trace[device]) { + std::cout << '[' << std::hex << (int)message[device].p0() + << ':' << std::dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << std::flush; + } + message[device].time = 0; + } else { + if (MidiInPort_oss::trace[device]) { + std::cout << '[' << std::hex << (int)message[device].p0() + << 'P' << std::dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << std::flush; + } + } + } + } + break; + + default: + break; + } // end switch + } // end while (1) + + // This code is not yet reached, but should be made to do so eventually + + if (message != NULL) { + delete message; + message = NULL; + } + + if (argsExpected != NULL) { + delete argsExpected; + argsExpected = NULL; + } + + if (argsLeft != NULL) { + delete argsLeft; + argsLeft = NULL; + } + + if (sysexIn != NULL) { + delete sysexIn; + sysexIn = NULL; + } + +} + + + +#endif // LINUX + + + +// md5sum: 2008f4a298bef0cd85620a5507815866 - MidiInPort_oss.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_unsupported.cpp b/src/midiio/src/MidiInPort_unsupported.cpp new file mode 100644 index 0000000..584a468 --- /dev/null +++ b/src/midiio/src/MidiInPort_unsupported.cpp @@ -0,0 +1,487 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed Jan 21 22:46:30 GMT-0800 1998 +// Last Modified: Thu Jan 22 22:53:53 GMT-0800 1998 +// Last Modified: Wed Jun 30 11:42:59 PDT 1999 (added sysex capability) +// Filename: ...sig/code/control/MidiInPort/unsupported/MidiInPort_unsupported.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiInPort_unsupported.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// an unknown sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// This class is used when there is no MIDI input, so +// that MIDI programs can otherwise be compiled and run. +// This file can also serve as a template for creating +// an OS specific class for MIDI input. +// + +#include "MidiInPort_unsupported.h" +#include <iostream> +#include <stdlib.h> + + +#define DEFAULT_INPUT_BUFFER_SIZE (1024) + +// initialized static variables +int MidiInPort_unsupported::numDevices = 0; +int MidiInPort_unsupported::objectCount = 0; +int* MidiInPort_unsupported::openQ = NULL; +int* MidiInPort_unsupported::portObjectCount = NULL; +CircularBuffer<MidiMessage>* MidiInPort_unsupported::midiBuffer = NULL; +int MidiInPort_unsupported::channelOffset = 0; +int* MidiInPort_unsupported::sysexWriteBuffer = NULL; +Array<uchar>** MidiInPort_unsupported::sysexBuffers = NULL; + + +////////////////////////////// +// +// MidiInPort_unsupported::MidiInPort_unsupported +// default values: autoOpen = 1 +// + +MidiInPort_unsupported::MidiInPort_unsupported(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiInPort_unsupported::MidiInPort_unsupported(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::~MidiInPort_unsupported +// + +MidiInPort_unsupported::~MidiInPort_unsupported() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cerr << "Error: bad MidiInPort_unsupported object count!: " + << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::close +// + +void MidiInPort_unsupported::close(void) { + if (getPortStatus() == 1) { + openQ[getPort()] = 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::closeAll +// + +void MidiInPort_unsupported::closeAll(void) { + for (int i=0; i<getNumPorts(); i++) { + if (openQ[i] == 1) { + openQ[i] = 0; + } + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::extract -- returns the next MIDI message +// received since that last extracted message. +// + +MidiMessage MidiInPort_unsupported::extract(void) { + return midiBuffer[getPort()].extract(); +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiInPort_unsupported::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::getCount -- returns the number of unexamined +// MIDI messages waiting in the input buffer. +// + +int MidiInPort_unsupported::getCount(void) { + return midiBuffer[getPort()].getCount(); +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::getName -- returns the name of the port. +// returns "" if no name. Name is valid until getName is called again. +// + +const char* MidiInPort_unsupported::getName(void) { + return "none"; +} + +const char* MidiInPort_unsupported::getName(int i) { + return "none"; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::getNumPorts -- returns the number of available +// ports for MIDI input +// + +int MidiInPort_unsupported::getNumPorts(void) { + return numDevices; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiInPort_unsupported::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::getPortStatus -- 0 if closed, 1 if open +// + +int MidiInPort_unsupported::getPortStatus(void) { + if (openQ[getPort()] == 1) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::getTrace -- returns true if trace is on or false +// if trace is off. if trace is on, then prints to standard +// output the Midi message received. +// + +int MidiInPort_unsupported::getTrace(void) { + return trace; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::insert +// + +void MidiInPort_unsupported::insert(const MidiMessage& aMessage) { + midiBuffer[getPort()].insert(aMessage); +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::message +// + +MidiMessage& MidiInPort_unsupported::message(int index) { + return midiBuffer[getPort()][index]; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::open -- returns true if MIDI input port was +// opened. +// + +int MidiInPort_unsupported::open(void) { + if (getPortStatus() == 0) { + openQ[getPort()] = 1; + } + return openQ[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::pause -- stop the Midi input port from +// inserting MIDI messages into the buffer, but keep the +// port open. Use unpause() to reverse the effect of pause(). +// + +void MidiInPort_unsupported::pause(void) { + // nothing +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::setBufferSize -- sets the allocation +// size of the MIDI input buffer. +// + +void MidiInPort_unsupported::setBufferSize(int aSize) { + midiBuffer[getPort()].setSize(aSize); +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::setChannelOffset -- sets the MIDI channel offset, either 0 or 1. +// + +void MidiInPort_unsupported::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + std::cout << "Error: Channel offset can be only 0 or 1." << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::setPort +// + +void MidiInPort_unsupported::setPort(int aPort) { + if (aPort < 0 || aPort >= getNumPorts()) { + std::cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << std::endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + portObjectCount[port]++; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::setTrace -- if false, then don't print MIDI messages +// to the screen. +// + +int MidiInPort_unsupported::setTrace(int aState) { + int oldtrace = trace; + if (aState == 0) { + trace = 0; + } else { + trace = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::toggleTrace -- switches the state of trace +// Returns the previous value of the trace variable. +// + +void MidiInPort_unsupported::toggleTrace(void) { + trace = !trace; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::unpause -- enables the Midi input port +// to inserting MIDI messages into the buffer after the +// port is already open. +// + +void MidiInPort_unsupported::unpause(void) { + // nothing +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiInPort_unsupported::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_unsupported::deinitialize(void) { + int deviceCount = numDevices; + closeAll(); + + if (sysexBuffers != NULL) { + for (int i=0; i<deviceCount; i++) { + if (sysexBuffers[i] != NULL) { + delete [] sysexBuffers[i]; + sysexBuffers[i] = NULL; + } + } + delete [] sysexBuffers; + sysexBuffers = NULL; + } + + if (sysexWriteBuffer != NULL) { + delete [] sysexWriteBuffer; + sysexWriteBuffer = NULL; + } + + if (openQ != NULL) { + delete [] openQ; + openQ = NULL; + } + + if (midiBuffer != NULL) { + delete [] midiBuffer; + midiBuffer = NULL; + } + + if (portObjectCount != NULL) { + delete [] portObjectCount; + portObjectCount = NULL; + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_unsupported::initialize(void) { + // get the number of ports + numDevices = 9; + if (getNumPorts() <= 0) { + std::cerr << "Error: no MIDI input devices" << std::endl; + exit(1); + } + + + // allocate space for sysexBuffers, the port open/close status + if (sysexBuffers != NULL) { + std::cout << "Error: sysexBuffers are not empty, don't know size" << std::endl; + exit(1); + } + sysexBuffers = new Array<uchar>*[numDevices]; + + // allocate space for sysexWriteBuffer, the port open/close status + if (sysexWriteBuffer != NULL) delete [] sysexWriteBuffer; + sysexWriteBuffer = new int[numDevices]; + + // allocate space for openQ, the port open/close status + if (openQ != NULL) delete [] openQ; + openQ = new int[numDevices]; + + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + // allocate space for the Midi input buffers + if (midiBuffer != NULL) delete [] midiBuffer; + midiBuffer = new CircularBuffer<MidiMessage>[numDevices]; + + // initialize the static arrays + for (int i=0; i<getNumPorts(); i++) { + openQ[i] = 0; + portObjectCount[i] = 0; + midiBuffer[i].setSize(DEFAULT_INPUT_BUFFER_SIZE); + + sysexWriteBuffer[i] = 0; + sysexBuffers[i] = new Array<uchar>[128]; + for (int n=0; n<128; n++) { + sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow + sysexBuffers[i][n].setAllocSize(32); + sysexBuffers[i][n].setSize(0); + sysexBuffers[i][n].setGrowth(32); // in case it will ever grow + } + + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::setPortStatus +// + +void MidiInPort_unsupported::setPortStatus(int aStatus) { + if (aStatus) { + openQ[getPort()] = 1; + } else { + openQ[getPort()] = 0; + } +} + + +// md5sum: d8b8f65af70a9b3c33e62794c2a4a91e - MidiInPort_unsupported.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_visual.cpp b/src/midiio/src/MidiInPort_visual.cpp new file mode 100644 index 0000000..b4659bf --- /dev/null +++ b/src/midiio/src/MidiInPort_visual.cpp @@ -0,0 +1,1267 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed Jan 21 22:46:30 GMT-0800 1998 +// Last Modified: Wed Jun 30 11:29:51 PDT 1999 (added sysex capability) +// Last Modified: Wed Oct 13 10:18:22 PDT 1999 (midiInUnprepareHeader change) +// Last Modified: Tue Nov 23 15:01:17 PST 1999 (fixed sysex NULL init) +// Filename: ...sig/code/control/MidiInPort/visual/MidiInPort_visual.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiInPort_visual.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// Windows 95/NT/98 specific MIDI input methods. +// as defined in winmm.lib. This class is inherited +// privately by the MidiInPort class. +// + +#ifdef VISUAL + + +#include "MidiInPort_visual.h" + +#include <windows.h> +#include <mmsystem.h> + +#include <iostream.h> + + +// initialized static variables +int MidiInPort_visual::numDevices = 0; +int MidiInPort_visual::objectCount = 0; +int* MidiInPort_visual::openQ = NULL; +int* MidiInPort_visual::inrunningQ = NULL; +int* MidiInPort_visual::portObjectCount = NULL; +HMIDIIN* MidiInPort_visual::device = NULL; +MIDIHDR** MidiInPort_visual::sysexDriverBuffer1 = NULL; +MIDIHDR** MidiInPort_visual::sysexDriverBuffer2 = NULL; +int* MidiInPort_visual::sysexDBnumber = NULL; +HANDLE* MidiInPort_visual::hMutex = NULL; +CircularBuffer<MidiMessage>* MidiInPort_visual::midiBuffer = NULL; +int MidiInPort_visual::channelOffset = 0; +int* MidiInPort_visual::sysexWriteBuffer = NULL; +Array<uchar>** MidiInPort_visual::sysexBuffers = NULL; +int* MidiInPort_visual::sysexStatus = NULL; + + +////////////////////////////// +// +// MidiInPort_visual::MidiInPort_visual +// default values: autoOpen = 1 +// + +MidiInPort_visual::MidiInPort_visual(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + trace = 0; + port = -1; + setPort(0); +} + + +MidiInPort_visual::MidiInPort_visual(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + trace = 0; + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::~MidiInPort_visual +// + +MidiInPort_visual::~MidiInPort_visual() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + cerr << "Error: bad MidiInPort_visual object count!: " + << objectCount << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::clearSysex -- clears the data from a sysex +// message and sets the allocation size to the default size (of 32 +// bytes). +// + +void MidiInPort_visual::clearSysex(int buffer) { + buffer = 0x7f | buffer; // limit buffer range from 0 to 127 + + if (getPort() == -1) { + return; + } + + sysexBuffers[getPort()][buffer].setSize(0); + if (sysexBuffers[getPort()][buffer].getAllocSize() != 32) { + // shrink the storage buffer's size if necessary + sysexBuffers[getPort()][buffer].setAllocSize(32); + } +} + + +void MidiInPort_visual::clearSysex(void) { + // clear all sysex buffers + for (int i=0; i<128; i++) { + clearSysex(i); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::close +// + +void MidiInPort_visual::close(void) { + if (getPort() == -1) { + return; + } + if (getPortStatus() == 1 && device[getPort()] != NULL) { + midiInReset(device[getPort()]); + midiInClose(device[getPort()]); + uninstallSysexStuff(device[getPort()], port); + openQ[getPort()] = 0; + inrunningQ[getPort()] = 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::closeAll +// + +void MidiInPort_visual::closeAll(void) { + for (int i=0; i<getNumPorts(); i++) { + if (openQ[i] == 1 && device[i] != NULL) { + midiInReset(device[i]); + midiInClose(device[i]); + if (getPort() != 1) { + uninstallSysexStuff(device[getPort()], port); + } + openQ[i] = 0; + inrunningQ[i] = 0; + } + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::extract -- returns the next MIDI message +// received since that last extracted message. +// + +MidiMessage MidiInPort_visual::extract(void) { + MidiMessage output; + + waitForMutex(); + if (getPort() != -1) { + output = midiBuffer[getPort()].extract(); + } + releaseMutex(); + + return output; +} + + + +////////////////////////////// +// +// MidiInPort_visual::getBufferSize +// + +int MidiInPort_visual::getBufferSize(void) { + if (getPort() != -1) { + return midiBuffer[getPort()].getSize(); + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiInPort_visual::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiInPort_visual::getCount -- returns the number of unexamined +// MIDI messages waiting in the input buffer. +// + +int MidiInPort_visual::getCount(void) { + int output; + + waitForMutex(); + if (getPort() != -1) { + output = midiBuffer[getPort()].getCount(); + } else { + output = 0; + } + releaseMutex(); + + return output; +} + + + +////////////////////////////// +// +// MidiInPort_visual::getName -- returns the name of the port. +// returns "" if no name. Name is valid until getName is called again. +// + +const char* MidiInPort_visual::getName(void) { + static MIDIINCAPS inputCapabilities; + + if (getPort() == -1) { + return "Null MIDI Input"; + } + + if (openQ[getPort()]) { // port already open + midiInGetDevCaps(getPort(), &inputCapabilities, sizeof(MIDIINCAPS)); + } else { // port is currently closed + if(open()) {; + midiInGetDevCaps(getPort(), &inputCapabilities, sizeof(MIDIINCAPS)); + close(); + } else { + return ""; + } + } + return inputCapabilities.szPname; +} + + +const char* MidiInPort_visual::getName(int i) { + static MIDIINCAPS inputCapabilities; + + if (i < 0 || i > getNumPorts()) { + cerr << "Error invalid index for getName: " << i << endl; + exit(1); + } + + midiInGetDevCaps(i, &inputCapabilities, sizeof(MIDIINCAPS)); + + return inputCapabilities.szPname; +} + + + +////////////////////////////// +// +// MidiInPort_visual::getNumPorts -- returns the number of available +// ports for MIDI input +// + +int MidiInPort_visual::getNumPorts(void) { + return midiInGetNumDevs(); +} + + + +////////////////////////////// +// +// MidiInPort_visual::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiInPort_visual::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiInPort_visual::getPortStatus -- 0 if closed, 1 if open, 2 if +// specifically not connected to any MIDI port. +// + +int MidiInPort_visual::getPortStatus(void) { + if (getPort() == -1) { + return 2; + } + + if (openQ[getPort()] == 1) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::getSysex -- returns the sysex message contents +// of a given buffer. You should check to see that the size is +// non-zero before looking at the data. The data pointer will +// be NULL if there is no data in the buffer. +// + +uchar* MidiInPort_visual::getSysex(int buffer) { + buffer &= 0x7f; // limit the buffer access to indices 0 to 127. + + if (getPort() == -1) { + return NULL; + } + + if (sysexBuffers[getPort()][buffer].getSize() < 2) { + return NULL; + } else { + return sysexBuffers[getPort()][buffer].getBase(); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::getSysexSize -- returns the sysex message byte +// count of a given buffer. Buffers are in the range from +// 0 to 127. +// + +int MidiInPort_visual::getSysexSize(int buffer) { + if (getPort() == -1) { + return 0; + } else { + return sysexBuffers[getPort()][buffer & 0x7f].getSize(); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::getTrace -- returns true if trace is on or false +// if trace is off. if trace is on, then prints to standard +// output the Midi message received. +// + +int MidiInPort_visual::getTrace(void) { + return trace; +} + + + +////////////////////////////// +// +// MidiInPort_visual::insert +// + +void MidiInPort_visual::insert(const MidiMessage& aMessage) { + waitForMutex(); + if (getPort() == -1) { + // do nothing + } else { + midiBuffer[getPort()].insert(aMessage); + } + releaseMutex(); +} + + + +////////////////////////////// +// +// MidiInPort_visual::installSysex -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_visual::installSysex(uchar* anArray, int aSize) { + return installSysexPrivate(getPort(), anArray, aSize); +} + + + +////////////////////////////// +// +// MidiInPort_visual::installSysexPrivate -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_visual::installSysexPrivate(int port, uchar* anArray, int aSize){ + if (port == -1) { + return -1; + } + + // choose a buffer to install sysex data into: + int bufferNumber = sysexWriteBuffer[port]; + sysexWriteBuffer[port]++; + if (sysexWriteBuffer[port] >= 128) { + sysexWriteBuffer[port] = 0; + } + + // copy contents of sysex message into the chosen buffer + sysexBuffers[port][bufferNumber].setSize(aSize); + uchar* dataptr = sysexBuffers[port][bufferNumber].getBase(); + uchar* indataptr = anArray; + for (int i=0; i<aSize; i++) { + *dataptr = *indataptr; + dataptr++; + indataptr++; + } + + // return the buffer number that was used + return bufferNumber; +} + + + +////////////////////////////// +// +// MidiInPort_visual::message +// + +MidiMessage& MidiInPort_visual::message(int index) { + if (getPort() != -1) { + return midiBuffer[getPort()][index]; + } else { + static MidiMessage nullmessage; + return nullmessage; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::open -- returns true if MIDI input port was +// opened. +// + +int MidiInPort_visual::open(void) { + if (getPort() == -1) { + return 1; + } + + if (getPortStatus() == 0) { + int flag; + flag = midiInOpen(&device[getPort()], getPort(), + (DWORD)&midiInputCallback, (DWORD)this, CALLBACK_FUNCTION); + if (flag == MMSYSERR_NOERROR) { + openQ[getPort()] = 1; + installSysexStuff(device[getPort()], port); + unpause(); + return 1; + } else { // failed to open + openQ[getPort()] = 0; + device[getPort()] = NULL; + return 0; + } + } else { // already open + return 1; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::pause -- stop the Midi input port from +// inserting MIDI messages into the buffer, but keep the +// port open. Use unpause() to reverse the effect of pause(). +// + +void MidiInPort_visual::pause(void) { + if (getPort() == -1) { + return; + } + + if (openQ[getPort()]) { + if (inrunningQ[getPort()] == 1) { + midiInStop(device[getPort()]); + inrunningQ[getPort()] = 0; + } + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::setBufferSize -- sets the allocation +// size of the MIDI input buffer. +// + +void MidiInPort_visual::setBufferSize(int aSize) { + if (getPort() != -1) { + midiBuffer[getPort()].setSize(aSize); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::setChannelOffset -- sets the MIDI channel offset, either 0 or 1. +// + +void MidiInPort_visual::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + cout << "Error: Channel offset can be only 0 or 1." << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::setPort -- +// + +void MidiInPort_visual::setPort(int aPort) { + if (aPort < -1 || aPort >= getNumPorts()) { + cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::setTrace -- if false, then don't print MIDI messages +// to the screen. +// + +int MidiInPort_visual::setTrace(int aState) { + int oldtrace = trace; + if (aState == 0) { + trace = 0; + } else { + trace = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiInPort_visual::toggleTrace -- switches the state of trace +// Returns the previous value of the trace variable. +// + +void MidiInPort_visual::toggleTrace(void) { + trace = !trace; +} + + + +////////////////////////////// +// +// MidiInPort_visual::unpause -- enables the Midi input port +// to inserting MIDI messages into the buffer after the +// port is already open. +// + +void MidiInPort_visual::unpause(void) { + if (getPort() == -1) { + return; + } + + if (openQ[getPort()]) { + if (inrunningQ[getPort()] == 0) { + midiInStart(device[getPort()]); + inrunningQ[getPort()] = 1; + } + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiInPort_visual::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_visual::deinitialize(void) { + int num = numDevices; + + closeAll(); + + if (sysexBuffers != NULL) { + for (int i=0; i<numDevices; i++) { + if (sysexBuffers[i] != NULL) { + delete sysexBuffers[i]; + sysexBuffers[i] = NULL; + } + } + delete [] sysexBuffers; + sysexBuffers = NULL; + } + + + if (sysexDriverBuffer1 != NULL) { + for (int i=0; i<numDevices; i++) { + if (sysexDriverBuffer1[i] != NULL) { + delete sysexDriverBuffer1[i]; + sysexDriverBuffer1[i] = NULL; + } + } + delete [] sysexDriverBuffer1; + sysexDriverBuffer1 = NULL; + } + + if (sysexDriverBuffer2 != NULL) { + for (int i=0; i<numDevices; i++) { + if (sysexDriverBuffer2[i] != NULL) { + delete sysexDriverBuffer2[i]; + sysexDriverBuffer2[i] = NULL; + } + } + delete [] sysexDriverBuffer2; + sysexDriverBuffer2 = NULL; + } + + if (sysexDBnumber != NULL) { + delete [] sysexDBnumber; + sysexDBnumber = NULL; + } + + + if (sysexWriteBuffer != NULL) { + delete [] sysexWriteBuffer; + sysexWriteBuffer = NULL; + } + + if (sysexStatus != NULL) { + delete [] sysexStatus; + sysexStatus = NULL; + } + + if (device != NULL) { + delete [] device; + device = NULL; + } + + if (openQ != NULL) { + delete [] openQ; + openQ = NULL; + } + + if (inrunningQ != NULL) { + delete [] inrunningQ; + inrunningQ = NULL; + } + + if (hMutex != NULL) { + delete [] hMutex; + hMutex = NULL; + } + + if (midiBuffer != NULL) { + delete [] midiBuffer; + midiBuffer = NULL; + } + + if (portObjectCount != NULL) { + delete [] portObjectCount; + portObjectCount = NULL; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_visual::initialize(void) { + int i; + + // get the number of ports + numDevices = midiInGetNumDevs(); + if (getNumPorts() <= 0) { + cerr << "Error: no MIDI input devices" << endl; + exit(1); + } + + // allocate space for Windoze MIDI input structures + if (device != NULL) { + cerr << "Error: device array should be NULL when calling " + << "initialize() in MidiInPort_visual." << endl; + exit(1); + } + device = new HMIDIIN[numDevices]; + + // allocate space for openQ, the port open/close status + if (openQ != NULL) delete [] openQ; + openQ = new int[numDevices]; + + // allocate space to keep track of an active/inactive input port + if (inrunningQ != NULL) delete [] inrunningQ; + inrunningQ = new int[numDevices]; + + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + // allocate space for mutual exclusive + if (hMutex != NULL) delete [] hMutex; + hMutex = new HANDLE[numDevices]; + + // allocate space for the Midi input buffers + if (midiBuffer != NULL) delete [] midiBuffer; + midiBuffer = new CircularBuffer<MidiMessage>[numDevices]; + + // allocate space for the MIDI sysex buffer indices + if (sysexWriteBuffer != NULL) delete [] sysexWriteBuffer; + sysexWriteBuffer = new int[numDevices]; + + // allocate space for the sysex MIM_LONGDATA message tracking + if (sysexStatus != NULL) delete [] sysexStatus; + sysexStatus = new int[numDevices]; + + // allocate space for sysex buffers + if (sysexBuffers != NULL) { + cout << "Error: memory leak on sysex buffers initialization" << endl; + exit(1); + } + sysexBuffers = new Array<uchar>*[numDevices]; + + // allocate system exclusive buffers for MIDI driver + if (sysexDriverBuffer1 != NULL) { + cout << "Error: memory leak on sysex buffer for drivers creation" << endl; + exit(1); + } + sysexDriverBuffer1 = new MIDIHDR*[numDevices]; + for (i=0; i<numDevices; i++) { + sysexDriverBuffer1[i] = NULL; + } + + // allocate system exclusive buffers for MIDI driver + if (sysexDriverBuffer2 != NULL) { + cout << "Error: memory leak on sysex buffer for drivers creation" << endl; + exit(1); + } + sysexDriverBuffer2 = new MIDIHDR*[numDevices]; + for (i=0; i<numDevices; i++) { + sysexDriverBuffer2[i] = NULL; + } + + // allocate space for keeping track of which buffer to look at + if (sysexDBnumber != NULL) delete [] sysexDBnumber; + sysexDBnumber = new int[numDevices]; + + + // initialize the static arrays + for (i=0; i<getNumPorts(); i++) { + device[i] = NULL; + openQ[i] = 0; + inrunningQ[i] = 0; + portObjectCount[i] = 0; + hMutex[i] = CreateMutex(NULL, FALSE, "M"); + midiBuffer[i].setSize(DEFAULT_INPUT_BUFFER_SIZE); + + sysexStatus[i] = -1; + sysexWriteBuffer[i] = 0; + sysexDBnumber[i] = 0; + sysexBuffers[i] = new Array<uchar>[128]; + for (int n=0; n<128; n++) { + sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow + sysexBuffers[i][n].setAllocSize(32); + sysexBuffers[i][n].setSize(0); + sysexBuffers[i][n].setGrowth(32); // in case it will ever grow + } + + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::installSysexStuff -- install all the mess that +// a MIDIIN structure needs in order to receive system exclusives. +// + +void MidiInPort_visual::installSysexStuff(HMIDIIN dev, int port) { + if (sysexDriverBuffer1 != NULL) { + if (sysexDriverBuffer1[port] != NULL) { + // some memory leaks here + delete sysexDriverBuffer1[port]; + sysexDriverBuffer1[port] = NULL; + } + } + if (sysexDriverBuffer2 != NULL) { + if (sysexDriverBuffer2[port] != NULL) { + // some memory leaks here + delete sysexDriverBuffer2[port]; + sysexDriverBuffer2[port] = NULL; + } + } + + // allocate space for Drivers sysex byte buffer + sysexDriverBuffer1[port] = (LPMIDIHDR)GlobalLock(GlobalAlloc(GMEM_MOVEABLE | + GMEM_SHARE, sizeof(MIDIHDR))); + sysexDriverBuffer2[port] = (LPMIDIHDR)GlobalLock(GlobalAlloc(GMEM_MOVEABLE | + GMEM_SHARE, sizeof(MIDIHDR))); + + if (sysexDriverBuffer1[port] == NULL) { + cout << "Error: could not allocate sysex driver's buffer" << endl; + exit(1); + } + + if (sysexDriverBuffer2[port] == NULL) { + cout << "Error: could not allocate sysex driver's buffer" << endl; + exit(1); + } + + // allocate buffer inside of sysexDriverBuffer + sysexDriverBuffer1[port]->lpData = (LPSTR)GlobalLock(GlobalAlloc( + GMEM_MOVEABLE | GMEM_SHARE, (DWORD)1024)); + sysexDriverBuffer2[port]->lpData = (LPSTR)GlobalLock(GlobalAlloc( + GMEM_MOVEABLE | GMEM_SHARE, (DWORD)1024)); + + if (sysexDriverBuffer1[port]->lpData == NULL) { + cout << "Error: there was not enought space to allocate sysex buffer" + << endl; + // leaking memory here + exit(1); + } + + if (sysexDriverBuffer2[port]->lpData == NULL) { + cout << "Error: there was not enought space to allocate sysex buffer" + << endl; + // leaking memory here + exit(1); + } + + + // setup other sysexDriverBuffer data fields + sysexDriverBuffer1[port]->dwBufferLength = 1024; // total size of buffer + sysexDriverBuffer1[port]->dwBytesRecorded = 0L; // number of byte in buffer + sysexDriverBuffer1[port]->dwFlags = 0L; // initialize flags + sysexDriverBuffer1[port]->dwUser = 0L; // userdata: used for sysex time + + // setup other sysexDriverBuffer data fields + sysexDriverBuffer2[port]->dwBufferLength = 1024; // total size of buffer + sysexDriverBuffer2[port]->dwBytesRecorded = 0L; // number of byte in buffer + sysexDriverBuffer2[port]->dwFlags = 0L; // initialize flags + sysexDriverBuffer2[port]->dwUser = 0L; // userdata: used for sysex time + + // prepare the header + int status = midiInPrepareHeader(device[port], sysexDriverBuffer1[port], + sizeof(MIDIHDR)); + + if (status != 0) { + cout << "Error preparing sysex buffer number: " << port << endl; + // leaking some memory here? + exit(1); + } + + // prepare the header + status = midiInPrepareHeader(device[port], sysexDriverBuffer2[port], + sizeof(MIDIHDR)); + + if (status != 0) { + cout << "Error preparing sysex buffer number: " << port << endl; + // leaking some memory here? + exit(1); + } + + // add the sysex buffer to the driver + status = midiInAddBuffer(device[port], sysexDriverBuffer1[port], + sizeof(MIDIHDR)); + + if (status != 0) { + cout << "Error adding sysex buffer to driver: " << port << endl; + // leaking some memory here? + exit(1); + } + + status = midiInAddBuffer(device[port], sysexDriverBuffer2[port], + sizeof(MIDIHDR)); + + if (status != 0) { + cout << "Error adding sysex buffer to driver: " << port << endl; + // leaking some memory here? + exit(1); + } + +} + + + +////////////////////////////// +// +// MidiInPort_visual::uninstallSysexStuff -- uninstalls all the mess that +// a MIDIIN structure needs in order to receive system exclusives. +// + +void MidiInPort_visual::uninstallSysexStuff(HMIDIIN dev, int port) { + if (port == -1) { + return; + } + // unprepare the headers + midiInUnprepareHeader(device[port], sysexDriverBuffer1[port], + sizeof(MIDIHDR)); + midiInUnprepareHeader(device[port], sysexDriverBuffer2[port], + sizeof(MIDIHDR)); + + // deallocate buffer inside of sysexDriverBuffer + /* Following code caused problems: perhaps lpData was deleted by driver + delete [] sysexDriverBuffer1[port]->lpData; + sysexDriverBuffer1[port]->lpData = NULL; + delete [] sysexDriverBuffer2[port]->lpData; + sysexDriverBuffer2[port]->lpData = NULL; + */ + + // deallocate space for Drivers sysex byte buffer + delete sysexDriverBuffer1[port]; + delete sysexDriverBuffer2[port]; + sysexDriverBuffer1[port] = NULL; + sysexDriverBuffer2[port] = NULL; +} + + + +////////////////////////////// +// +// MidiInPort_visual::releaseMutex +// + +void MidiInPort_visual::releaseMutex(void) { +/* int flag = */ ReleaseMutex(hMutex[getPort()]); +/* + if (flag != 0) { + cerr << "Error relasing mutex in MIDI input; flag was: " << flag << endl; + } +*/ +} + + + +////////////////////////////// +// +// MidiInPort_visual::setPortStatus +// + +void MidiInPort_visual::setPortStatus(int aStatus) { + if (getPort() == -1) { + return; + } + + if (aStatus) { + openQ[getPort()] = 1; + } else { + openQ[getPort()] = 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::waitForMutex +// + +void MidiInPort_visual::waitForMutex(void) { +/* + DWORD mutexResult = WaitForSingleObject(hMutex[getPort()], 5000L); + if (mutexResult != WAIT_OBJECT_0) { + cerr << "Error waiting for mutex in MIDI input" << endl; + } +*/ +} + + + +/////////////////////////////////////////////////////////////////////////// + + +////////////////////////////// +// +// midiInputCallback -- the function the MIDI input driver calls when +// it has a message from the Midi in cable ready +// + +void CALLBACK midiInputCallback(HMIDIIN hMidiIn, UINT inputStatus, + DWORD instancePtr, DWORD midiMessage, DWORD timestamp) { + static MidiMessage newMessage; + + switch (inputStatus) { + case MIM_MOREDATA: + // There is more data waiting at the device. + // If this case is exists, then that means that the MIDI + // device is too slow and some data was lost. + // Windows sends a MIM_MOREDATA event only if you specify + // the MIDI_IO_STATUS flag to midiInOpen(). + + // no break; + case MIM_DATA: + + // One regular (non sysex) message has been completely + // received. + + // ignore the Yamaha Active Sensing command and MIDI time clock + // at least for now. + if ((midiMessage & 0xff) == 0xfe || (midiMessage & 0xff) == 0xf8) { + break; + } + + newMessage.time = timestamp; + newMessage.data = midiMessage; + ((MidiInPort_visual*)instancePtr)->insert(newMessage); + if (((MidiInPort_visual*)instancePtr)->getTrace()) { + cout << "[" << hex << (int)newMessage.command() << dec + << ":" << (int)newMessage.p1() << "," + << (int)newMessage.p2() << "]"; + cout.flush(); + } + break; + + case MIM_LONGDATA: + { + // A sysex or part of a sysex message is coming in. + // The timestamp variable contains a pointer to a + // MIDIHDR pointer + + MIDIHDR* midiheader = (MIDIHDR*)midiMessage; + int dataCount = midiheader->dwBytesRecorded; + char* data = midiheader->lpData; + int port = ((MidiInPort_visual*)instancePtr)->getPort(); + if (port == -1) { + break; + } + int* sysexStatus = ((MidiInPort_visual*)instancePtr)->sysexStatus; +// MIDIHDR** sysexDriverBuffer = ((MidiInPort_visual*)instancePtr)-> +// sysexDriverBuffer; + HMIDIIN devicex = ((MidiInPort_visual*)instancePtr)->device[port]; + + if (dataCount == 0) { + // can't handle a zero-length sysex + break; + } + + // step 1: determine if this is the first part of the sysex + // message or a continuation + int continuation = 0; + if (data[0] == (char)0xf0) { + continuation = 0; + if (sysexStatus[port] != -1) { + cout << "Error: there is another sysex command being " + "received on port " << port << endl; + exit(1); + } + } else { + if (sysexStatus[port] == -1) { + cout << "Error: no sysex command is being " + "received on port " << port << endl; + if (data[0] < 128) { + cout << "First byte is: " << dec << (int)data[0] << endl; + } else { + cout << "First byte is: " << hex << (int)data[0] << endl; + } + if (data[1] < 128) { + cout << "Second byte is: " << dec << (int)data[1] << endl; + } else { + cout << "Second byte is: " << hex << (int)data[1] << endl; + } + + exit(1); + } + continuation = 1; + } + + // step 2: if continuing, add the data to the preallocated + // sysex buffer, otherwise, get a new buffer location + int buffer = -1; + if (continuation) { + buffer = sysexStatus[port]; + if (buffer < 0 || buffer > 127) { + cout << "Sysex buffer was out of range: " << buffer << endl; + } + for (int i=0; i<dataCount; i++) { + unsigned char datum = data[i]; + ((MidiInPort_visual*)instancePtr)-> + sysexBuffers[port][buffer].append(datum); + if (datum == 0xf7) { + for (int k=i; k<dataCount; k++) { + data[k-i] = data[k]; + } + midiheader->dwBytesRecorded = dataCount - i - 1; + + goto insert_sysex_message; + } + } + } else { // if not a continuation of a sysex event + buffer = ((MidiInPort_visual*)instancePtr)->sysexWriteBuffer[port]; + ((MidiInPort_visual*)instancePtr)->sysexWriteBuffer[port]++; + if (buffer == 127) { + ((MidiInPort_visual*)instancePtr)->sysexWriteBuffer[port] = 0; + } + + ((MidiInPort_visual*)instancePtr)-> + sysexBuffers[port][buffer].setSize(0); + for (int j=0; j<dataCount; j++) { + unsigned char datum = data[j]; + ((MidiInPort_visual*)instancePtr)-> + sysexBuffers[port][buffer].append(datum); + if (datum == 0xf7) { + for (int k=j; k<dataCount; k++) { + data[k-j] = data[k]; + } + + goto insert_sysex_message; + } + } + + } + + // recycle the MIDI input buffer for the driver + { + midiInPrepareHeader(devicex, midiheader, sizeof(MIDIHDR)); + int dstatus = midiInAddBuffer(devicex, midiheader, sizeof(MIDIHDR)); + if (dstatus != MMSYSERR_NOERROR) { + cout << "Error when calling midiInAddBuffer" << endl; + exit(1); + } + } + + break; + + insert_sysex_message: + + // recycle the MIDI input buffer for the driver + { + midiInPrepareHeader(devicex, midiheader, sizeof(MIDIHDR)); + int estatus = midiInAddBuffer(devicex, midiheader, sizeof(MIDIHDR)); + if (estatus != MMSYSERR_NOERROR) { + cout << "Error when calling midiInAddBuffer" << endl; + exit(1); + } + } + + // now that a sysex message is finished, send a midimessage + // out to the instancePtr MIDI buffer telling the user + // that a sysex message has come in. + + // newMessage.time = timestamp; use last time stamp that came + // in because the timestamp variable is used for storing + // the pointer of the sysex data. + + newMessage.time = timestamp; + newMessage.p0() = 0xf0; + newMessage.p1() = buffer; + newMessage.p2() = 0; + newMessage.p3() = 0; + + ((MidiInPort_visual*)instancePtr)->insert(newMessage); + if (((MidiInPort_visual*)instancePtr)->getTrace()) { + cout << "[" << hex << (int)newMessage.command() << dec + << ":" << (int)newMessage.p1() << "," + << (int)newMessage.p2() << "]"; + cout.flush(); + } + + } // end of local variable range + break; + + case MIM_ERROR: + // An invalid regular MIDI message was received. + + break; + + case MIM_LONGERROR: + { + // An invalid sysex MIDI message was received. + + // if a sysex message was continuing from a previous part, + // then kill that message. + + int port = ((MidiInPort_visual*)instancePtr)->getPort(); + if (port == -1) { + break; + } + int buffer = ((MidiInPort_visual*)instancePtr)->sysexStatus[port]; + if (buffer != -1) { + ((MidiInPort_visual*)instancePtr)-> + sysexBuffers[port][buffer].setSize(0); + ((MidiInPort_visual*)instancePtr)->sysexStatus[port] = -1; + } + + HMIDIIN devicex = ((MidiInPort_visual*)instancePtr)->device[port]; + MIDIHDR* midiheader = (MIDIHDR*)midiMessage; + + // recycle the MIDI input buffer for the driver + midiInPrepareHeader(devicex, midiheader, sizeof(MIDIHDR)); + int status = midiInAddBuffer(devicex, midiheader, sizeof(MIDIHDR)); + if (status != MMSYSERR_NOERROR) { + cout << "Error when calling midiInAddBuffer" << endl; + exit(1); + } + + + break; + } + default: ; + // case MIM_OPEN: // MIDI device is opening + // case MIM_CLOSE: // MIDI device is closing + } +} + + + +#endif // VISUAL + + +// md5sum: db55d9f375b86f54c0c8340547c5701f - MidiInPort_visual.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInput.cpp b/src/midiio/src/MidiInput.cpp new file mode 100644 index 0000000..93fce87 --- /dev/null +++ b/src/midiio/src/MidiInput.cpp @@ -0,0 +1,224 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 18 December 1997 +// Last Modified: Sun Jan 25 15:31:49 GMT-0800 1998 +// Last Modified: Thu Apr 27 17:56:03 PDT 2000 (added scale function) +// Filename: ...sig/code/control/MidiInput/MidiInput.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiInput.cpp +// Syntax: C++ +// +// Description: A higher-level MIDI input interface than the +// MidiInPort class. Can be used to allow multiple +// objects to share a single MIDI input stream, or +// to fake a MIDI input connection. +// + +#include "MidiInput.h" +#include <stdlib.h> +#include <iostream> + + +////////////////////////////// +// +// MidiInput::MidiInput -- opens the specified MIDI input device and +// sets the size of the input buffer. +// + +MidiInput::MidiInput(void) : MidiInPort() { + orphanBuffer = NULL; +} + + +MidiInput::MidiInput(int aPort, int autoOpen) : MidiInPort(aPort, autoOpen) { + orphanBuffer = NULL; +} + + + +////////////////////////////// +// +// MidiInput::~MidiInput +// + +MidiInput::~MidiInput() { + if (orphanBuffer != NULL) { + delete orphanBuffer; + orphanBuffer = NULL; + } +} + + + +////////////////////////////// +// +// MidiInput::getBufferSize +// + +int MidiInput::getBufferSize(void) { + if (isOrphan()) { + return orphanBuffer->getSize(); + } else { + return MidiInPort::getBufferSize(); + } +} + + + +////////////////////////////// +// +// MidiInput::getCount +// + +int MidiInput::getCount(void) { + if (isOrphan()) { + return orphanBuffer->getCount(); + } else { + return MidiInPort::getCount(); + } +} + + + +////////////////////////////// +// +// MidiInput::extract +// + +MidiMessage MidiInput::extract(void) { + if (isOrphan()) { + return orphanBuffer->extract(); + } else { + return MidiInPort::extract(); + } +} + + + +////////////////////////////// +// +// fscale -- converts a value in the range from 0 to 127 +// into a number in a new range. For example the value +// 64 scaled to the range from 0 to 2 would be 1. +// + +double MidiInput::fscale(int value, double min, double max) { + return value >= 127 ? max : (value/127.0*(max-min)+min); +} + + + +////////////////////////////// +// +// fscale14 -- converts a value in the range from 0 to 2^15-1 +// into a number in a new range. +// + +double MidiInput::fscale14(int value, double min, double max) { + return value >= 16383 ? max : (value/16383.0*(max-min)+min); +} + + + +////////////////////////////// +// +// MidiInput::insert +// + +void MidiInput::insert(const MidiMessage& aMessage) { + if (isOrphan()) { + orphanBuffer->insert(aMessage); + } else { + MidiInPort::insert(aMessage); + } +} + + + +////////////////////////////// +// +// MidiInput::isOrphan +// + +int MidiInput::isOrphan(void) const { + if (orphanBuffer == NULL) { + return 0; + } else { + return 1; + } +} + + + +////////////////////////////// +// +// MidiInput::makeOrphanBuffer +// default value: aSize = 1024 +// + +void MidiInput::makeOrphanBuffer(int aSize) { + if (!isOrphan()) { + if (orphanBuffer == NULL) { + delete orphanBuffer; + orphanBuffer = NULL; + } + orphanBuffer = new CircularBuffer<MidiMessage>(aSize); + } +} + + + +////////////////////////////// +// +// MidiInput::removeOrphanBuffer +// + +void MidiInput::removeOrphanBuffer(void) { + if (isOrphan()) { + delete orphanBuffer; + orphanBuffer = NULL; + } +} + + + +////////////////////////////// +// +// scale -- converts a value in the range from 0 to 127 +// into a number in a new range. For example the value +// 64 scaled to the range from 0 to 2 would be 1. +// + +int MidiInput::scale(int value, int min, int max) { + return value >= 127 ? max : (int)(value/127.0*(max-min+1)+min); +} + + + +////////////////////////////// +// +// scale14 -- converts a value in the range from 0 to 2^15-1 +// into a number in a new range. +// + +int MidiInput::scale14(int value, int min, int max) { + return value >= 16383 ? max : (int)(value/16383.0*(max-min+1)+min); +} + + + +////////////////////////////// +// +// MidiInput::setBufferSize +// + +void MidiInput::setBufferSize(int aSize) { + if (isOrphan()) { + orphanBuffer->setSize(aSize); + } else { + MidiInPort::setBufferSize(aSize); + } +} + + + +// md5sum: 826d403708263eaf0089b4742179c58c - MidiInput.cpp =css= 20030102 diff --git a/src/midiio/src/MidiMessage.cpp b/src/midiio/src/MidiMessage.cpp new file mode 100644 index 0000000..5f3df19 --- /dev/null +++ b/src/midiio/src/MidiMessage.cpp @@ -0,0 +1,406 @@ +// +// Copyright 1997-1998 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 19 December 1997 +// Last Modified: Fri Jan 23 00:26:12 GMT-0800 1998 +// Last Modified: Sun Sep 20 12:17:26 PDT 1998 +// Last Modified: Mon Oct 15 14:29:12 PDT 2001 (added is_note functions) +// Filename: ...sig/src/sigControl/MidiMessage.cpp +// Web Address: http://sig.sapp.org/src/sigControl/MidiMessage.cpp +// Syntax: C++ +// +// Description: A structure for handling MIDI input messages. +// This class stores a time stamp plus up to +// four MIDI message bytes. System Exclusive messages +// are stored in a separate array in the MidiInPort +// class, and their storage index is passed to the +// user through a MIDI message for later extraction +// of the full sysex message. +// + +#include "MidiMessage.h" + + +////////////////////////////// +// +// MidiMessage::MidiMessage +// + +MidiMessage::MidiMessage(void) { + // no initialization. Note that the default contents are undefined. +} + + +// default value aTime = 0 +MidiMessage::MidiMessage(int aCommand, int aP1, int aP2, int aTime) { + time = aTime; + command() = (uchar)aCommand; + p1() = (uchar)aP1; + p2() = (uchar)aP2; +} + + +MidiMessage::MidiMessage(const MidiMessage& aMessage) { + time = aMessage.time; + data = aMessage.data; +} + + + +////////////////////////////// +// +// MidiMessage::~MidiMessage -- Destructor. +// + +MidiMessage::~MidiMessage() { + // do nothing +} + + + +////////////////////////////// +// +// MidiMessage::command -- returns the MIDI command byte +// + +uchar& MidiMessage::command(void) { + return p0(); +} + + + +////////////////////////////// +// +// MidiMessage::operator= -- defines how objects are to be copied +// + +MidiMessage& MidiMessage::operator=(const MidiMessage& aMessage) { + time = aMessage.time; + data = aMessage.data; + return *this; +} + + + +////////////////////////////// +// +// MidiMessage::operator[] -- access to byte data +// can only access index 0 to 3, other number will be +// chopped. +// + +uchar& MidiMessage::operator[](int index) { + return *(((uchar*)&data)+(index & 0x3)); +} + + + +////////////////////////////// +// +// MidiMessage::p0 -- returns the command byte of the +// midi message. Same as the command() function. +// + +uchar& MidiMessage::p0(void) { + return *(((uchar*)&data)+0); +} + + + +////////////////////////////// +// +// MidiMessage::p1 -- returns the first parameter of the +// midi message. Valid if the command requires a parameter. +// + +uchar& MidiMessage::p1(void) { + return *(((uchar*)&data)+1); +} + + + +////////////////////////////// +// +// MidiMessage::p2 -- returns the second parameter of the +// midi message. Valid if the command requires two parameters. +// + +uchar& MidiMessage::p2(void) { + return *(((uchar*)&data)+2); +} + + +////////////////////////////// +// +// MidiMessage::p3 -- returns the third parameter of the +// midi message. Valid if the command requires three parameters +// (but none of the MIDI command do). +// + +uchar& MidiMessage::p3(void) { + return *(((uchar*)&data)+3); +} + + + +////////////////////////////// +// +// MidiMessage:getArgCount -- +// + +int MidiMessage::getArgCount(void) const { + return getParameterCount(); +} + + + +////////////////////////////// +// +// MidiMessage::getParameterCount -- returns the number +// of valid parameters for the assiciated MIDI command +// stored in p0. Returns -1 if MIDI command is invalid, +// or the number of valid parameters is unknown. +// + +int MidiMessage::getParameterCount(void) const { + int output = -1; + switch (*(((uchar*)&data)+0) & 0xf0) { + case 0x80: // note-off + case 0x90: // note-on + case 0xa0: // aftertouch + case 0xb0: // continuous controller + case 0xe0: // pitch wheel + output = 2; + break; + case 0xc0: // patch change + case 0xd0: // channel pressure + output = 1; + break; + case 0xf0: + switch (*(((uchar*)&data)+0)) { + // System Common Messages + case 0xf0: return -1; // variable for sysex + case 0xf1: return 1; // MIDI Time Code Quarter Frame + case 0xf2: return 2; // Song Position Pointer + case 0xf3: return 1; // Song Select + case 0xf4: return 0; // Undefined + case 0xf5: return 0; // Undefined + case 0xf6: return 0; // Tune Request + case 0xf7: return 0; // End of System exclusive + // System Real-Time Messages + case 0xf8: return 0; // Timing Clock + case 0xf9: return 0; // Undefined + case 0xfa: return 0; // Start + case 0xfb: return 0; // Continue + case 0xfc: return 0; // Stop + case 0xfd: return 0; // Undefined + case 0xfe: return 0; // Active Sensing + case 0xff: return 0; // System Reset + } + return -1; + break; + default: // don't know or invalid command + output = -1; + break; + } + + return output; +} + + + +////////////////////////////// +// +// MidiMessage::getCommand -- same as command(). +// + +uchar MidiMessage::getCommand(void) const { + return getP0(); +} + + + +////////////////////////////// +// +// MidiMessage::getP0 -- same as p0(). +// + +uchar MidiMessage::getP0(void) const { + return *(((uchar*)&data)+0); +} + + + +////////////////////////////// +// +// MidiMessage::getP1 -- same as p1(). +// + +uchar MidiMessage::getP1(void) const { + return *(((uchar*)&data)+1); +} + + + +////////////////////////////// +// +// MidiMessage::getP2 -- same as p2(). +// + +uchar MidiMessage::getP2(void) const { + return *(((uchar*)&data)+2); +} + + + +////////////////////////////// +// +// MidiMessage::getP3 -- same as p3(). +// + +uchar MidiMessage::getP3(void) const { + return *(((uchar*)&data)+3); +} + + + +////////////////////////////// +// +// MidiMessage::setCommand -- same as command(). +// + +void MidiMessage::setCommand(uchar aCommand) { + command() = aCommand; +} + + + +////////////////////////////// +// +// MidiMessage::setData -- sets the message bytes +// default values: aP1 = 0, aP2 = 0, aP3 = 0. +// + +void MidiMessage::setData(uchar aCommand, uchar aP1, uchar aP2, uchar aP3) { + setCommand(aCommand); + setP1(aP1); + setP2(aP2); + setP3(aP3); +} + + + +////////////////////////////// +// +// MidiMessage::setP0 -- same as p0(). +// + +void MidiMessage::setP0(uchar aP0) { + p0() = aP0; +} + + + +////////////////////////////// +// +// MidiMessage::setP1 -- same as p1(). +// + +void MidiMessage::setP1(uchar aP1) { + p1() = aP1; +} + + + +////////////////////////////// +// +// MidiMessage::setP2 -- same as p2(). +// + +void MidiMessage::setP2(uchar aP2) { + p2() = aP2; +} + + + +////////////////////////////// +// +// MidiMessage::setP3 -- same as p3(). +// + +void MidiMessage::setP3(uchar aP3) { + p3() = aP3; +} + + + +////////////////////////////// +// +// MidiMessage::is_note -- Returns true if the MIDI command is 0x80 or 0x90. +// + +int MidiMessage::is_note(void) { + if ((p0() & 0xf0) == 0x90) { // note-on or note-off + return 1; + } else if ((p0() & 0xf0) == 0x80) { // note-off + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiMessage::is_note_on -- Returns true if the MIDI command is a note +// on message (0x90 series with p2() > 0). +// + +int MidiMessage::is_note_on(void) { + if (((p0() & 0xf0) == 0x90) && p2() > 0) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiMessage::is_note_off -- Returns true if the MIDI command is a note +// off message (0x80 series or 0x90 series with p2() == 0). +// + +int MidiMessage::is_note_off(void) { + if ((p0() & 0xf0) == 0x80) { + return 1; + } else if (((p0() & 0xf0) == 0x90) && (p2() == 0)) { + return 1; + } else { + return 0; + } +} + + +/////////////////////////////////////////////////////////////////////////// + +////////////////////////////// +// +// operator<< MidiMessage +// + +std::ostream& operator<<(std::ostream& out, MidiMessage& aMessage) { + out << "(" << aMessage.time << ") " + << std::hex << (int)aMessage.getP0() << ": "; + for (int i=1; i<=aMessage.getArgCount(); i++) { + out << std::dec << (int)aMessage[i] << ' '; + } + + return out; +} + + + +// md5sum: 487f0fddeb8db20d81f9c039e2a460c9 - MidiMessage.cpp =css= 20030102 diff --git a/src/midiio/src/MidiOutPort_alsa.cpp b/src/midiio/src/MidiOutPort_alsa.cpp new file mode 100644 index 0000000..07f4e5d --- /dev/null +++ b/src/midiio/src/MidiOutPort_alsa.cpp @@ -0,0 +1,469 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Wed May 10 16:16:21 PDT 2000 +// Last Modified: Sun May 14 20:44:12 PDT 2000 +// Filename: ...sig/code/control/MidiOutPort/alsa/MidiOutPort_alsa.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiOutPort_alsa.cpp +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Linux using +// ALSA sound drivers. Privately inherited by the +// MidiOutPort class via the MidiOutPort_alsa class. +// + +#if defined(LINUX) && defined(ALSA) + +#include "MidiOutPort_alsa.h" +#include <iostream> +#include <stdlib.h> + +// initialized static variables +int MidiOutPort_alsa::numDevices = 0; +int MidiOutPort_alsa::objectCount = 0; +int* MidiOutPort_alsa::portObjectCount = NULL; +int MidiOutPort_alsa::channelOffset = 0; +int* MidiOutPort_alsa::trace = NULL; +std::ostream* MidiOutPort_alsa::tracedisplay = &std::cout; + + + +////////////////////////////// +// +// MidiOutPort_alsa::MidiOutPort_alsa +// default values: autoOpen = 1 +// + +#include <unistd.h> + +MidiOutPort_alsa::MidiOutPort_alsa(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiOutPort_alsa::MidiOutPort_alsa(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::~MidiOutPort_alsa -- +// + +MidiOutPort_alsa::~MidiOutPort_alsa() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cout << "Error: bad MidiOutPort object count!: " << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::close -- +// + +void MidiOutPort_alsa::close(void) { + Sequencer_alsa::closeOutput(getPort()); +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::closeAll -- +// + +void MidiOutPort_alsa::closeAll(void) { + int i; + for (i=0; i<getNumPorts(); i++) { + Sequencer_alsa::closeOutput(i); + } +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiOutPort_alsa::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::getName -- returns the name of the port. +// returns "" if no name. Name is valid until getName is called again. +// + +const char* MidiOutPort_alsa::getName(void) { + if (getPort() == -1) { + return "Null ALSA Midi Output"; + } + return getOutputName(getPort()); +} + + +const char* MidiOutPort_alsa::getName(int i) { + return Sequencer_alsa::getOutputName(i); +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::getNumPorts -- returns the number of available +// ports for MIDI output +// + +int MidiOutPort_alsa::getNumPorts(void) { + return Sequencer_alsa::getNumOutputs(); +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiOutPort_alsa::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::getPortStatus -- 0 if closed, 1 if open +// + +int MidiOutPort_alsa::getPortStatus(void) { + return is_open_out(getPort()); +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::getTrace -- returns true if trace is on or +// false if off. If trace is on, then prints to standard output +// the Midi message being sent. +// + +int MidiOutPort_alsa::getTrace(void) { + if (getPort() == -1) return -1; + + return trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::rawsend -- send the Midi command and its parameters +// + +int MidiOutPort_alsa::rawsend(int command, int p1, int p2) { + if (getPort() == -1) return 0; + + int status; + uchar mdata[3] = {(uchar)command, (uchar)p1, (uchar)p2}; + status = write(getPort(), mdata, 3); + + if (getTrace()) { + if (status == 1) { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << ":" + << (int)mdata[1] << "," << (int)mdata[2] << ")"; + std::cout.flush(); + } else { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << "X" + << (int)mdata[1] << "," << (int)mdata[2] << ")"; + std::cout.flush(); + } + } + + return status; +} + + +int MidiOutPort_alsa::rawsend(int command, int p1) { + if (getPort() == -1) return 0; + + int status; + uchar mdata[2] = {(uchar)command, (uchar)p1}; + + status = write(getPort(), mdata, 2); + + if (getTrace()) { + if (status == 1) { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << ":" + << (int)mdata[1] << ")"; + std::cout.flush(); + } else { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << "X" + << (int)mdata[1] << "," << (int)mdata[2] << ")"; + std::cout.flush(); + } + } + + return status; +} + + +int MidiOutPort_alsa::rawsend(int command) { + if (getPort() == -1) return 0; + + int status; + uchar mdata[1] = {(uchar)command}; + + status = write(getPort(), mdata, 1); + + if (getTrace()) { + if (status == 1) { + std::cout << "(" << std::hex << (int)mdata[0] << ")"; + std::cout.flush(); + } else { + std::cout << "(" << std::hex << (int)mdata[0] << ")"; + std::cout.flush(); + } + } + + return status; +} + + +int MidiOutPort_alsa::rawsend(uchar* array, int size) { + if (getPort() == -1) return 0; + + int status; + status = write(getPort(), array, size); + + if (getTrace()) { + if (status == 1) { + std::cout << "(array)"; + std::cout.flush(); + } else { + std::cout << "(XarrayX)"; + std::cout.flush(); + } + } + + return status; +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::open -- returns true if MIDI output port was +// opened. +// + +int MidiOutPort_alsa::open(void) { + if (getPort() == -1) { + return 2; + } else { + return Sequencer_alsa::openOutput(getPort()); + } +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::setChannelOffset -- sets the MIDI channel offset, +// either 0 or 1. +// + +void MidiOutPort_alsa::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + std::cout << "Error: Channel offset can be only 0 or 1." << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::setPort -- +// + +void MidiOutPort_alsa::setPort(int aPort) { + if (aPort == -1) return; + + if (aPort < 0 || aPort >= getNumPorts()) { + std::cout << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << std::endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::setTrace -- if false, then won't print +// Midi messages to standard output. +// + +int MidiOutPort_alsa::setTrace(int aState) { + if (getPort() == -1) return -1; + + int oldtrace = trace[getPort()]; + if (aState == 0) { + trace[getPort()] = 0; + } else { + trace[getPort()] = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::sysex -- send a system exclusive message. +// The message must start with a 0xf0 byte and end with +// a 0xf7 byte. +// + +int MidiOutPort_alsa::sysex(uchar* array, int size) { + if (getPort() == -1) { + return 2; + } + + if (size == 0 || array[0] != 0xf0 || array[size-1] != 0xf7) { + std::cout << "Error: invalid sysex message" << std::endl; + exit(1); + } + + return rawsend(array,size); +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::toggleTrace -- +// + +void MidiOutPort_alsa::toggleTrace(void) { + if (getPort() == -1) return; + + trace[getPort()] = !trace[getPort()]; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiOutPort_alsa::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_alsa::deinitialize(void) { + closeAll(); + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = NULL; + if (trace != NULL) delete [] trace; + trace = NULL; +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_alsa::initialize(void) { + // get the number of ports + numDevices = getNumOutputs(); + if (getNumPorts() <= 0) { + std::cout << "Warning: no MIDI output devices" << std::endl; + portObjectCount = NULL; + trace = NULL; + } else { + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + // allocate space for trace variable for each port: + if (trace != NULL) delete [] trace; + trace = new int[numDevices]; + + // initialize the static arrays + for (int i=0; i<getNumPorts(); i++) { + portObjectCount[i] = 0; + trace[i] = 0; + } + } +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::setPortStatus -- +// + +void MidiOutPort_alsa::setPortStatus(int aStatus) { + // not used in Linux implementation +} + + +#endif /* LINUX and ALSA */ + + + +// md5sum: 6f5d0ce75ae6e086ad949178e7deefcb - MidiOutPort_alsa.cpp =css= 20030102 diff --git a/src/midiio/src/MidiOutPort_linux.cpp b/src/midiio/src/MidiOutPort_linux.cpp new file mode 100644 index 0000000..43bba90 --- /dev/null +++ b/src/midiio/src/MidiOutPort_linux.cpp @@ -0,0 +1,381 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun May 14 20:58:32 PDT 2000 +// Last Modified: Thu May 18 23:37:11 PDT 2000 +// Last Modified: Sat Nov 2 20:40:01 PST 2002 (added ALSA OSS def) +// Filename: ...sig/code/control/MidiOutPort_linux/MidiOutPort_linux.cpp +// Web Address: http://sig.sapp.org/include/sig/MidiOutPort_linux.cpp +// Syntax: C++ +// +// Description: Linux MIDI output class which detects which +// type of MIDI drivers are available: either +// ALSA or OSS. +// + +#ifdef LINUX +#if defined(ALSA) && defined(OSS) + +#include "MidiOutPort_linux.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> + + +// initialize static members +int MidiOutPort_linux::objectCount = 0; +int MidiOutPort_linux::current = UNKNOWN_MIDI_SELECT; // MIDI out selected +int MidiOutPort_linux::alsaQ = 0; // boolean for if ALSA is present +int MidiOutPort_linux::ossQ = 0; // boolean for if OSS is present + +MidiOutPort_oss *MidiOutPort_linux::oss_output = NULL; +MidiOutPort_alsa *MidiOutPort_linux::alsa_output = NULL; +MidiOutPort_unsupported *MidiOutPort_linux::unknown_output = NULL; + + +MidiOutPort_linux::MidiOutPort_linux(void) { + if (objectCount == 0) { + determineDrivers(); + } else if (objectCount < 0) { + cout << "Error: unusual MidiOutPort_linux object count" << endl; + exit(1); + } + + objectCount++; +} + +MidiOutPort_linux::MidiOutPort_linux(int aPort, int autoOpen = 1) { + determineDrivers(); + setAndOpenPort(aPort); +} + +MidiOutPort_linux::~MidiOutPort_linux() { + objectCount--; + if (objectCount == 0) { + if (oss_output != NULL) { + delete oss_output; + oss_output = NULL; + } + + if (alsa_output != NULL) { + delete alsa_output; + alsa_output = NULL; + } + + if (unknown_output != NULL) { + delete unknown_output; + unknown_output = NULL; + } + } + + if (objectCount < 0) { + cout << "Error: unusual MidiOutPort_linux count when destructing" << endl; + exit(1); + } +} + + +void MidiOutPort_linux::close(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: oss_output->close(); break; + case ALSA_MIDI_SELECT: alsa_output->close(); break; + default: unknown_output->close(); break; + } +} + +void MidiOutPort_linux::closeAll(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: oss_output->closeAll(); break; + case ALSA_MIDI_SELECT: alsa_output->closeAll(); break; + default: unknown_output->closeAll(); break; + } +} + +int MidiOutPort_linux::getChannelOffset(void) const { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getChannelOffset(); break; + case ALSA_MIDI_SELECT: return alsa_output->getChannelOffset(); break; + default: return unknown_output->getChannelOffset(); break; + } +} + +const char* MidiOutPort_linux::getName(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getName(); break; + case ALSA_MIDI_SELECT: return alsa_output->getName(); break; + default: return unknown_output->getName(); break; + } +} + +const char* MidiOutPort_linux::getName(int i) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getName(i); break; + case ALSA_MIDI_SELECT: return alsa_output->getName(i); break; + default: return unknown_output->getName(i); break; + } +} + +int MidiOutPort_linux::getNumPorts(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getNumPorts(); break; + case ALSA_MIDI_SELECT: return alsa_output->getNumPorts(); break; + default: return unknown_output->getNumPorts(); break; + } +} + +int MidiOutPort_linux::getPort(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getPort(); break; + case ALSA_MIDI_SELECT: return alsa_output->getPort(); break; + default: return unknown_output->getPort(); break; + } +} + +int MidiOutPort_linux::getPortStatus(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getPortStatus(); break; + case ALSA_MIDI_SELECT: return alsa_output->getPortStatus(); break; + default: return unknown_output->getPortStatus(); break; + } +} + +int MidiOutPort_linux::getTrace(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getTrace(); break; + case ALSA_MIDI_SELECT: return alsa_output->getTrace(); break; + default: return unknown_output->getTrace(); break; + } +} + +int MidiOutPort_linux::open(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->open(); break; + case ALSA_MIDI_SELECT: return alsa_output->open(); break; + default: return unknown_output->open(); break; + } +} + +int MidiOutPort_linux::rawsend(int command, int p1, int p2) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->rawsend(command, p1, p2); break; + case ALSA_MIDI_SELECT: return alsa_output->rawsend(command, p1, p2); break; + default: return unknown_output->rawsend(command, p1, p2); break; + } +} + +int MidiOutPort_linux::rawsend(int command, int p1) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->rawsend(command, p1); break; + case ALSA_MIDI_SELECT: return alsa_output->rawsend(command, p1); break; + default: return unknown_output->rawsend(command, p1); break; + } +} + +int MidiOutPort_linux::rawsend(int command) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->rawsend(command); break; + case ALSA_MIDI_SELECT: return alsa_output->rawsend(command); break; + default: return unknown_output->rawsend(command); break; + } +} + +int MidiOutPort_linux::rawsend(uchar* array, int size) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->rawsend(array, size); break; + case ALSA_MIDI_SELECT: return alsa_output->rawsend(array, size); break; + default: return unknown_output->rawsend(array, size); break; + } +} + +void MidiOutPort_linux::setAndOpenPort(int aPort) { + switch (getSelect()) { + case OSS_MIDI_SELECT: + oss_output->setPort(aPort); + oss_output->open(); + break; + case ALSA_MIDI_SELECT: + alsa_output->setPort(aPort); + alsa_output->open(); + break; + default: + unknown_output->setPort(aPort); + unknown_output->open(); + break; + } +} + +void MidiOutPort_linux::setChannelOffset(int aChannel) { + switch (getSelect()) { + case OSS_MIDI_SELECT: oss_output->setChannelOffset(aChannel); break; + case ALSA_MIDI_SELECT: alsa_output->setChannelOffset(aChannel); break; + default: unknown_output->setChannelOffset(aChannel); break; + } +} + +void MidiOutPort_linux::setPort(int aPort) { + switch (getSelect()) { + case OSS_MIDI_SELECT: oss_output->setPort(aPort); break; + case ALSA_MIDI_SELECT: + alsa_output->setPort(aPort); break; + default: unknown_output->setPort(aPort); break; + } +} + +int MidiOutPort_linux::setTrace(int aState) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->setTrace(aState); break; + case ALSA_MIDI_SELECT: return alsa_output->setTrace(aState); break; + default: return unknown_output->setTrace(aState); break; + } +} + +int MidiOutPort_linux::sysex(uchar* array, int size) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->sysex(array, size); break; + case ALSA_MIDI_SELECT: return alsa_output->sysex(array, size); break; + default: return unknown_output->sysex(array, size); break; + } +} + +void MidiOutPort_linux::toggleTrace(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: oss_output->toggleTrace(); break; + case ALSA_MIDI_SELECT: alsa_output->toggleTrace(); break; + default: unknown_output->toggleTrace(); break; + } +} + + + +////////////////////////////// +// +// MidiOutPort_linux::getSelect -- return the type of MIDI which +// is being used to send MIDI output. +// + +int MidiOutPort_linux::getSelect(void) { + return current; +} + + + +////////////////////////////// +// +// MidiOutPort_linux::selectOSS -- select the OSS MIDI output +// returns 1 if OSS is available, otherwise returns 0. +// + +int MidiOutPort_linux::selectOSS(void) { + if (ossQ) { + current = OSS_MIDI_SELECT; + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiOutPort_linux::selectALSA -- select the ALSA MIDI output +// returns 1 if ALSA is available, otherwise returns 0. +// + +int MidiOutPort_linux::selectALSA(void) { + if (alsaQ) { + current = ALSA_MIDI_SELECT; + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiOutPort_linux::selectUnknown -- select the Unknown MIDI output +// returns 1 always. +// + +int MidiOutPort_linux::selectUnknown(void) { + current = UNKNOWN_MIDI_SELECT; + return 1; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private Functions +// + +#include <unistd.h> + +////////////////////////////// +// +// MidiOutPort_linux::determineDrivers -- see if OSS/ALSA are +// available. If /dev/sequencer is present, assume that OSS is +// available. If /dev/snd/sdq is present, assume that ALSA is +// available. +// + +void MidiOutPort_linux::determineDrivers(void) { + struct stat filestats; + int status; + status = stat("/dev/sequencer", &filestats); + + if (status != 0) { + ossQ = 0; + } else { + ossQ = 1; + } + + status = stat("/dev/snd/seq", &filestats); + + if (status != 0) { + alsaQ = 0; + } else { + alsaQ = 1; + } + + + current = UNKNOWN_MIDI_SELECT; + + if (ossQ) { + current = OSS_MIDI_SELECT; + } + + if (alsaQ) { + current = ALSA_MIDI_SELECT; + } + + // create MIDI output types which are available: + + if (oss_output != NULL) { + delete oss_output; + oss_output = NULL; + } + if (alsa_output != NULL) { + delete alsa_output; + alsa_output = NULL; + } + if (unknown_output != NULL) { + delete unknown_output; + unknown_output = NULL; + } + + if (ossQ) { + oss_output = new MidiOutPort_oss; + } + if (alsaQ) { + alsa_output = new MidiOutPort_alsa; + } + unknown_output = new MidiOutPort_unsupported; +} + + +#endif /* ALSA and OSS */ +#endif /* LINUX */ + +// md5sum: be1ccf667122f1c9cf56a95b2ffb8e79 - MidiOutPort_linux.cpp =css= 20030102 diff --git a/src/midiio/src/MidiOutPort_oss.cpp b/src/midiio/src/MidiOutPort_oss.cpp new file mode 100644 index 0000000..74f17c4 --- /dev/null +++ b/src/midiio/src/MidiOutPort_oss.cpp @@ -0,0 +1,462 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Fri Dec 18 19:22:20 PST 1998 +// Last Modified: Fri Jan 8 04:26:16 PST 1999 +// Last Modified: Wed May 10 17:00:11 PDT 2000 (name change from _linux to _oss) +// Filename: ...sig/code/control/MidiOutPort/linux/MidiOutPort_oss.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiOutPort_oss.cpp +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Linux using +// OSS sound drivers. Privately inherited by the +// MidiOutPort class. +// + +#ifdef LINUX + +#include "MidiOutPort_oss.h" +#include <iostream> +#include <stdlib.h> + +// initialized static variables +int MidiOutPort_oss::numDevices = 0; +int MidiOutPort_oss::objectCount = 0; +int* MidiOutPort_oss::portObjectCount = NULL; +int MidiOutPort_oss::channelOffset = 0; +int* MidiOutPort_oss::trace = NULL; +std::ostream* MidiOutPort_oss::tracedisplay = &std::cout; + + + +////////////////////////////// +// +// MidiOutPort_oss::MidiOutPort_oss +// default values: autoOpen = 1 +// + + +MidiOutPort_oss::MidiOutPort_oss(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiOutPort_oss::MidiOutPort_oss(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiOutPort_oss::~MidiOutPort_oss +// + +MidiOutPort_oss::~MidiOutPort_oss() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cerr << "Error: bad MidiOutPort object count!: " << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_oss::close +// + +void MidiOutPort_oss::close(void) { + // don't close anything, because the + // Linux driver keeps all of the ports open while the + // midi driver (/dev/sequencer) is running. +} + + + +////////////////////////////// +// +// MidiOutPort_oss::closeAll +// + +void MidiOutPort_oss::closeAll(void) { + // the Linux MIDI driver will close the /dev/sequencer device + // which will close all MIDI output ports at the same time. + Sequencer_oss::close(); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiOutPort_oss::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getName -- returns the name of the port. +// returns "" if no name. Name is valid until getName is called again. +// + +const char* MidiOutPort_oss::getName(void) { + if (getPort() == -1) { + return "Null OSS MIDI Output"; + } + return getOutputName(getPort()); +} + + +const char* MidiOutPort_oss::getName(int i) { + return Sequencer_oss::getOutputName(i); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getNumPorts -- returns the number of available +// ports for MIDI output +// + +int MidiOutPort_oss::getNumPorts(void) { + return Sequencer_oss::getNumOutputs(); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiOutPort_oss::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getPortStatus -- 0 if closed, 1 if open +// + +int MidiOutPort_oss::getPortStatus(void) { + // Linux MIDI devices are all open at the same time, + // so if one is open, then they all are. + return is_open(); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getTrace -- returns true if trace is on or +// false if off. If trace is on, then prints to standard output +// the Midi message being sent. +// + +int MidiOutPort_oss::getTrace(void) { + if (getPort() == -1) return -1; + + return trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::rawsend -- send the Midi command and its parameters +// + +int MidiOutPort_oss::rawsend(int command, int p1, int p2) { + if (getPort() == -1) return 0; + + int status; + uchar mdata[3] = {(uchar)command, (uchar)p1, (uchar)p2}; + status = write(getPort(), mdata, 3); + + if (getTrace()) { + if (status == 1) { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << ":" + << (int)mdata[1] << "," << (int)mdata[2] << ")"; + std::cout.flush(); + } else { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << "X" + << (int)mdata[1] << "," << (int)mdata[2] << ")"; + std::cout.flush(); + } + } + + return status; +} + + +int MidiOutPort_oss::rawsend(int command, int p1) { + if (getPort() == -1) return 0; + + int status; + uchar mdata[2] = {(uchar)command, (uchar)p1}; + + status = write(getPort(), mdata, 2); + + if (getTrace()) { + if (status == 1) { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << ":" + << (int)mdata[1] << ")"; + std::cout.flush(); + } else { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << "X" + << (int)mdata[1] << "," << (int)mdata[2] << ")"; + std::cout.flush(); + } + } + + return status; +} + + +int MidiOutPort_oss::rawsend(int command) { + if (getPort() == -1) return 0; + + int status; + uchar mdata[1] = {(uchar)command}; + + status = write(getPort(), mdata, 1); + + if (getTrace()) { + if (status == 1) { + std::cout << "(" << std::hex << (int)mdata[0] << ")"; + std::cout.flush(); + } else { + std::cout << "(" << std::hex << (int)mdata[0] << ")"; + std::cout.flush(); + } + } + + return status; +} + + +int MidiOutPort_oss::rawsend(uchar* array, int size) { + if (getPort() == -1) return 0; + + int status; + status = write(getPort(), array, size); + + if (getTrace()) { + if (status == 1) { + std::cout << "(array)"; + std::cout.flush(); + } else { + std::cout << "(XarrayX)"; + std::cout.flush(); + } + } + + return status; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::open -- returns true if MIDI output port was +// opened. +// + +int MidiOutPort_oss::open(void) { + return Sequencer_oss::open(); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::setChannelOffset -- sets the MIDI channel offset, +// either 0 or 1. +// + +void MidiOutPort_oss::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + std::cout << "Error: Channel offset can be only 0 or 1." << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_oss::setPort -- +// + +void MidiOutPort_oss::setPort(int aPort) { + if (aPort < -1 || aPort >= getNumPorts()) { + std::cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << std::endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } +} + + + +////////////////////////////// +// +// MidiOutPort_oss::setTrace -- if false, then won't print +// Midi messages to standard output. +// + +int MidiOutPort_oss::setTrace(int aState) { + if (getPort() == -1) return -1; + + int oldtrace = trace[getPort()]; + if (aState == 0) { + trace[getPort()] = 0; + } else { + trace[getPort()] = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::sysex -- send a system exclusive message. +// The message must start with a 0xf0 byte and end with +// a 0xf7 byte. +// + +int MidiOutPort_oss::sysex(uchar* array, int size) { + if (size == 0 || array[0] != 0xf0) { + std::cout << "Error: invalid sysex message" << std::endl; + exit(1); + } + + return rawsend(array,size); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::toggleTrace +// + +void MidiOutPort_oss::toggleTrace(void) { + if (getPort() == -1) return; + + trace[getPort()] = !trace[getPort()]; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiOutPort_oss::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_oss::deinitialize(void) { + closeAll(); + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = NULL; + if (trace != NULL) delete [] trace; + trace = NULL; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_oss::initialize(void) { + // get the number of ports + numDevices = getNumOutputs(); + if (getNumPorts() <= 0) { + std::cerr << "Warning: no MIDI output devices" << std::endl; + portObjectCount = NULL; + trace = NULL; + } else { + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + // allocate space for trace variable for each port: + if (trace != NULL) delete [] trace; + trace = new int[numDevices]; + + // initialize the static arrays + for (int i=0; i<getNumPorts(); i++) { + portObjectCount[i] = 0; + trace[i] = 0; + } + } +} + + + +////////////////////////////// +// +// MidiOutPort_oss::setPortStatus +// + +void MidiOutPort_oss::setPortStatus(int aStatus) { + // not used in Linux implementation +} + + +#endif // LINUX + + + +// md5sum: c09dbe18ce8a0ff6ff11030d43a98c4a - MidiOutPort_oss.cpp =css= 20030102 diff --git a/src/midiio/src/MidiOutPort_unsupported.cpp b/src/midiio/src/MidiOutPort_unsupported.cpp new file mode 100644 index 0000000..f4b8c28 --- /dev/null +++ b/src/midiio/src/MidiOutPort_unsupported.cpp @@ -0,0 +1,402 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Mon Jan 12 21:40:35 GMT-0800 1998 +// Last Modified: Mon Jan 12 21:40:39 GMT-0800 1998 +// Filename: ...sig/code/control/MidiOutPort/unsupported/MidiOutPort_unsupported.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiOutPort_unsupported.cpp +// Syntax: C++ +// +// Description: Operating-System specific interface for basic MIDI output +// capabilities in an unknown operating system. Privately +// inherited by the MidiOutPort class. Used for compiling +// and running MIDI programs on a computer with no +// MIDI output. +// + +#include "MidiOutPort_unsupported.h" + +#include <iostream> +#include <stdlib.h> +#include <string.h> +#include <sstream> + +// initialized static variables +int MidiOutPort_unsupported::numDevices = 0; +int MidiOutPort_unsupported::objectCount = 0; +int* MidiOutPort_unsupported::openQ = NULL; +int* MidiOutPort_unsupported::portObjectCount = NULL; +int MidiOutPort_unsupported::channelOffset = 0; + + +////////////////////////////// +// +// MidiOutPort_unsupported::MidiOutPort_unsupported +// default values: autoOpen = 1 +// + + +MidiOutPort_unsupported::MidiOutPort_unsupported(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiOutPort_unsupported::MidiOutPort_unsupported(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::~MidiOutPort_unsupported +// + +MidiOutPort_unsupported::~MidiOutPort_unsupported() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cerr << "Error: bad MidiOutPort object count!: " << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::close +// + +void MidiOutPort_unsupported::close(void) { + if (getPortStatus() == 1) { + setPortStatus(0); + } +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::closeAll +// + +void MidiOutPort_unsupported::closeAll(void) { + for (int i=0; i<getNumPorts(); i++) { + if (openQ[i] == 1) { + openQ[i] = 0; + } + } +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiOutPort_unsupported::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::getName -- returns the name of the port. +// returns "" if no name. Name is valid until getName is called again. +// + +const char* MidiOutPort_unsupported::getName(void) const { + static char* name = NULL; + std::stringstream temp; + temp << "Inactive MIDI output test port #"; + temp << getPort(); + if (name != NULL) delete [] name; + name = new char[temp.str().length()+1]; + strcpy(name, temp.str().c_str()); + return name; +} + +const char* MidiOutPort_unsupported::getName(int i) const { + static char* name = NULL; + std::stringstream temp; + temp << "Inactive MIDI output test port #"; + temp << i; + if (name != NULL) delete [] name; + name = new char[temp.str().length()+1]; + strcpy(name, temp.str().c_str()); + return name; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::getNumPorts -- returns the number of available +// ports for MIDI output +// + +int MidiOutPort_unsupported::getNumPorts(void) const { + return numDevices; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiOutPort_unsupported::getPort(void) const { + return port; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::getPortStatus -- 0 if closed, 1 if open +// + +int MidiOutPort_unsupported::getPortStatus(void) const { + if (openQ[getPort()] == 1) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::getTrace -- returns true if trace is on or +// false if off. If trace is on, then prints to standard output +// the Midi message being sent. +// + +int MidiOutPort_unsupported::getTrace(void) const { + return trace; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::rawsend -- send the Midi command and its parameters +// + +int MidiOutPort_unsupported::rawsend(int command, int p1, int p2) { + if (getTrace()) { + std::cout << "{" << std::hex << command << std::dec << ":" << (p1 & 0xff) + << "," << (p2 & 0xff) << "}"; + std::cout.flush(); + } + + return 1; +} + + +int MidiOutPort_unsupported::rawsend(int command, int p1) { + return 1; +} + + +int MidiOutPort_unsupported::rawsend(int command) { + return 1; +} + + +int MidiOutPort_unsupported::rawsend(uchar* array, int size) { + return 1; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::open -- returns true if MIDI output port was +// opened. +// + +int MidiOutPort_unsupported::open(void) { + if (getPortStatus() == 0) { + openQ[getPort()] = 1; + } + return 1; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::setChannelOffset -- sets the MIDI channel offset, either 0 or 1. +// + +void MidiOutPort_unsupported::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + std::cout << "Error: Channel offset can be only 0 or 1." << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::setPort -- +// + +void MidiOutPort_unsupported::setPort(int aPort) { + if (aPort < 0 || aPort >= getNumPorts()) { + std::cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << std::endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + portObjectCount[port]++; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::setTrace -- if false, then won't print +// Midi messages to standard output. +// + +int MidiOutPort_unsupported::setTrace(int aState) { + int oldtrace = trace; + if (aState == 0) { + trace = 0; + } else { + trace = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::sysex -- +// + +int MidiOutPort_unsupported::sysex(uchar* array, int size) { + return 1; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::toggleTrace -- +// + +void MidiOutPort_unsupported::toggleTrace(void) { + trace = !trace; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiOutPort_unsupported::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_unsupported::deinitialize(void) { + closeAll(); + if (openQ != NULL) delete [] openQ; + openQ = NULL; + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = NULL; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_unsupported::initialize(void) { + // get the number of ports + numDevices = 16; + if (getNumPorts() <= 0) { + std::cerr << "Error: no MIDI output devices" << std::endl; + exit(1); + } + + + // allocate space for openQ, the port open/close status + if (openQ != NULL) delete [] openQ; + openQ = new int[numDevices]; + + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + + // initialize the static arrays + for (int i=0; i<getNumPorts(); i++) { + openQ[i] = 0; + portObjectCount[i] = 0; + } +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::setPortStatus(int aStatus) { +// + +void MidiOutPort_unsupported::setPortStatus(int aStatus) { + if (aStatus) { + openQ[getPort()] = 1; + } else { + openQ[getPort()] = 0; + } +} + + + + +// md5sum: eff3d6cd2cab4c2def6ca60ef0ca197f - MidiOutPort_unsupported.cpp =css= 20030102 diff --git a/src/midiio/src/MidiOutPort_visual.cpp b/src/midiio/src/MidiOutPort_visual.cpp new file mode 100644 index 0000000..d080817 --- /dev/null +++ b/src/midiio/src/MidiOutPort_visual.cpp @@ -0,0 +1,532 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Dec 28 15:18:46 GMT-0800 1997 +// Last Modified: Mon Jan 12 15:42:44 GMT-0800 1998 +// Last Modified: Tue Jun 29 13:10:30 PDT 1999 (verified sysex sending) +// Last Modified: Tue Jun 4 22:10:16 PDT 2002 (getNumPorts fix for static use) +// Filename: ...sig/code/control/MidiOutPort/visual/MidiOutPort_visual.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiOutPort_visual.cpp +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Windows 95/NT/98 +// using winmm.lib. Privately inherited by the +// MidiOutPort class. +// + + +#ifdef VISUAL + +#include <iostream.h> +#include "MidiOutPort_visual.h" + +typedef unsigned long ulong; +typedef unsigned char uchar; + + +// initialized static variables +int MidiOutPort_visual::numDevices = 0; +int MidiOutPort_visual::objectCount = 0; +int* MidiOutPort_visual::openQ = NULL; +int* MidiOutPort_visual::portObjectCount = NULL; +HMIDIOUT* MidiOutPort_visual::device = NULL; +int MidiOutPort_visual::channelOffset = 0; + + + +////////////////////////////// +// +// MidiOutPort_visual::MidiOutPort_visual +// default values: autoOpen = 1 +// + + +MidiOutPort_visual::MidiOutPort_visual(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiOutPort_visual::MidiOutPort_visual(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::~MidiOutPort_visual +// + +MidiOutPort_visual::~MidiOutPort_visual() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + cerr << "Error: bad MidiOutPort object count!: " << objectCount << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::close +// + +void MidiOutPort_visual::close(void) { + if (getPort() == -1) { + return; + } + + if (getPortStatus() == 1 && device[getPort()] != NULL) { + + // The following function, midiOutClose, is not what I like. + // It will send note offs to any note which it thinks is + // on when the port is closed. Uncomment the line if + // you want this feature. + // midiOutReset(device[getPort()]); + + midiOutClose(device[getPort()]); + setPortStatus(0); + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::closeAll +// + +void MidiOutPort_visual::closeAll(void) { + for (int i=0; i<getNumPorts(); i++) { + if (openQ[i] == 1 && device[i] != NULL) { + midiOutReset(device[i]); + midiOutClose(device[i]); + openQ[i] = 0; + } + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiOutPort_visual::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::getName -- returns the name of the port. +// returns "" if no name. Name is valid until getName is called again. +// + +const char* MidiOutPort_visual::getName(void) { + static MIDIOUTCAPS outputCapabilities; + + if (getPort() == -1) { + return "Null MIDI Output"; + } + + if (openQ[getPort()]) { // port already open + midiOutGetDevCaps(getPort(), &outputCapabilities, sizeof(MIDIOUTCAPS)); + } else { // port is currently closed + if(open()) {; + midiOutGetDevCaps(getPort(), &outputCapabilities, sizeof(MIDIOUTCAPS)); + close(); + } else { + return ""; + } + } + return outputCapabilities.szPname; +} + + +const char* MidiOutPort_visual::getName(int i) { + static MIDIOUTCAPS outputCapabilities; + + midiOutGetDevCaps(i, &outputCapabilities, sizeof(MIDIOUTCAPS)); + + return outputCapabilities.szPname; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::getNumPorts -- returns the number of available +// ports for MIDI output +// + +int MidiOutPort_visual::getNumPorts(void) { + if (numDevices <= 0) { + return midiOutGetNumDevs(); + } + return numDevices; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiOutPort_visual::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::getPortStatus -- 0 if closed, 1 if open +// 2 if null connection +// + +int MidiOutPort_visual::getPortStatus(void) { + if (getPort() == -1) { + return 2; + } + + if (openQ[getPort()] == 1) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::getTrace -- returns true if trace is on or +// false if off. If trace is on, then prints to standard output +// the Midi message being sent. +// + +int MidiOutPort_visual::getTrace(void) { + return trace; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::rawsend -- send the Midi command and its parameters +// + +int MidiOutPort_visual::rawsend(int command, int p1, int p2) { + union { ulong word; uchar data[4]; } u; + u.data[0] = (uchar)command; + u.data[1] = (uchar)(p1 & 0x7f); // parameter limited to range 0-127; + u.data[2] = (uchar)(p2 & 0x7f); // parameter limited to range 0-127; + u.data[3] = 0; + + if (getPort() == -1) { + return 2; + } + + int flag = midiOutShortMsg(device[getPort()], u.word); + + if (getTrace()) { + if (flag == MMSYSERR_NOERROR) { + cout << "(" << hex << (int)u.data[0] << dec << ":" + << (int)u.data[1] << "," << (int)u.data[2] << ")"; + cout.flush(); + } else { + cout << "(" << hex << (int)u.data[0] << dec << "X" + << (int)u.data[1] << "," << (int)u.data[2] << ")"; + cout.flush(); + } + } + + return flag; +} + + +int MidiOutPort_visual::rawsend(int command, int p1) { + return rawsend(command, p1, 0); +} + + +int MidiOutPort_visual::rawsend(int command) { + return rawsend(command, 0, 0); +} + + +int MidiOutPort_visual::rawsend(uchar* array, int size) { + // Note: this function will work in Windows 95 and Windows NT. + // This function will not work in Windows 3.x because a + // different memory model is necessary. + + if (size > 64000 || size < 1) { + cerr << "Warning: cannot write a MIDI stream larger than 64kB" << endl; + return 0; + } + + MIDIHDR midiheader; // structure for sending an array of MIDI bytes + + midiheader.lpData = (char *)array; + midiheader.dwBufferLength = size; + // midiheader.dwBytesRecorded = size; // example program doesn't set + midiheader.dwFlags = 0; // flags must be set to 0 + + if (getPort() == -1) { + return -1; + } + + int status = midiOutPrepareHeader(device[getPort()], &midiheader, + sizeof(MIDIHDR)); + + if (status != MMSYSERR_NOERROR) { + return 0; + } + + status = midiOutLongMsg(device[getPort()], &midiheader, sizeof(MIDIHDR)); + + if (status != MMSYSERR_NOERROR) { + return 0; + } + + while (MIDIERR_STILLPLAYING == midiOutUnprepareHeader(device[getPort()], + &midiheader, sizeof(MIDIHDR))) { + Sleep(1); // sleep for 1 millisecond + } + + return 1; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::open -- returns true if MIDI output port was +// opened. +// + +int MidiOutPort_visual::open(void) { + if (getPort() == -1) { + return 2; + } + + if (getPortStatus() == 0) { + int flag; + flag = midiOutOpen(&device[getPort()], getPort(), 0, 0, CALLBACK_NULL); + if (flag == MMSYSERR_NOERROR) { + openQ[getPort()] = 1; + return 1; + } else { // faied to open + openQ[getPort()] = 0; + device[getPort()] = NULL; + return 0; + } + } else { // already open + return 1; + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::setChannelOffset -- sets the MIDI channel offset, +// either 0 or 1. +// + +void MidiOutPort_visual::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + cout << "Error: Channel offset can be only 0 or 1." << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::setPort +// + +void MidiOutPort_visual::setPort(int aPort) { + if (aPort < 0 || aPort >= getNumPorts()) { + cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + portObjectCount[port]++; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::setTrace -- if false, then won't print +// Midi messages to standard output. +// + +int MidiOutPort_visual::setTrace(int aState) { + int oldtrace = trace; + if (aState == 0) { + trace = 0; + } else { + trace = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::sysex -- send a system exclusive message. +// The first byte of the message must be a 0xf0 byte. +// + +int MidiOutPort_visual::sysex(uchar* array, int size) { + if (size == 0 || array[0] != 0xf0) { + cout << "Error: invalid system exclusive message," + " first byte must be 0xf0" << endl; + exit(1); + } + + return rawsend(array, size); +} + + + +////////////////////////////// +// +// MidiOutPort_visual::toggleTrace +// + +void MidiOutPort_visual::toggleTrace(void) { + trace = !trace; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiOutPort_visual::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_visual::deinitialize(void) { + closeAll(); + if (device != NULL) delete [] device; + device = NULL; + if (openQ != NULL) delete [] openQ; + openQ = NULL; + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = NULL; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_visual::initialize(void) { + // get the number of ports + numDevices = midiOutGetNumDevs(); + if (getNumPorts() <= 0) { + cerr << "Error: no MIDI output devices" << endl; + exit(1); + } + + // allocate space for Windoze MIDI output structures + if (device != NULL) { + cerr << "Error: device array should be NULL when calling " + << "initialize() in MidiOutPort." << endl; + exit(1); + } + device = new HMIDIOUT[numDevices]; + + // allocate space for openQ, the port open/close status + if (openQ != NULL) delete [] openQ; + openQ = new int[numDevices]; + + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + + // initialize the static arrays + for (int i=0; i<getNumPorts(); i++) { + device[i] = NULL; + openQ[i] = 0; + portObjectCount[i] = 0; + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::setPortStatus +// + +void MidiOutPort_visual::setPortStatus(int aStatus) { + if (getPort() == -1) { + return; + } + + if (aStatus) { + openQ[getPort()] = 1; + } else { + openQ[getPort()] = 0; + } +} + + +#endif // VISUAL + + + + +// md5sum: 8cb60bfb5dc9ea42808ffa4540e0fc52 - MidiOutPort_visual.cpp =css= 20030102 diff --git a/src/midiio/src/MidiOutput.cpp b/src/midiio/src/MidiOutput.cpp new file mode 100644 index 0000000..d78460f --- /dev/null +++ b/src/midiio/src/MidiOutput.cpp @@ -0,0 +1,1082 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 18 December 1997 +// Last Modified: Mon Jan 26 23:54:36 GMT-0800 1998 +// Last Modified: Tue Feb 2 08:30:28 PST 1999 +// Last Modified: Sun Jul 18 18:52:29 PDT 1999 (added RPN functions) +// Last Modified: Sun Dec 9 15:01:33 PST 2001 (switched con/des code) +// Filename: ...sig/code/control/MidiOutput/MidiOutput.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiOutput.cpp +// Syntax: C++ +// +// Description: The MIDI output interface for MIDI synthesizers/equipment +// which has many convienience functions defined for +// various types of MIDI output. +// + +#include "MidiOutput.h" +#include <iostream> +#include <iomanip> + +#define RECORD_ASCII (0) +#define RECORD_BINARY (1) +#define RECORD_MIDI_FILE (2) + + +// declaration of static variables +SigTimer MidiOutput::timer; +Array<int>* MidiOutput::rpn_lsb_status = NULL; +Array<int>* MidiOutput::rpn_msb_status = NULL; +int MidiOutput::objectCount = 0; + + +////////////////////////////// +// +// MidiOutput::MidiOutput -- +// + + +MidiOutput::MidiOutput(void) : MidiOutPort() { + outputRecordQ = 0; + + if (objectCount == 0) { + initializeRPN(); + } + objectCount++; +} + + + +MidiOutput::MidiOutput(int aPort, int autoOpen) : MidiOutPort(aPort, autoOpen) { + outputRecordQ = 0; + + if (objectCount == 0) { + initializeRPN(); + } + objectCount++; +} + + + +////////////////////////////// +// +// MidiOutput::~MidiOutput +// + +MidiOutput::~MidiOutput() { + objectCount--; + if (objectCount == 0) { + deinitializeRPN(); + } else if (objectCount < 0) { + std::cout << "Error in MidiOutput decontruction" << std::endl; + } + +} + + + +////////////////////////////// +// +// MidiOutput::cont -- send a controller command MIDI message. +// +// channel = the Midi channel ofset from 0 [0..15] +// controller = the continuous controller number [0..127] +// data = the value of the specified controller [0..127] +// + +int MidiOutput::cont(int channel, int controller, int data) { + return send(0xb0 | (channel & 0x0f), controller, data); +} + + + +////////////////////////////// +// +// MidiOutput::off -- sends a Note Off MIDI message (0x80). +// +// channel = MIDI channel to send note on. range is [0..15] +// keynum = MIDI key number to play (middle C = 60, C# = 61, etc.) [0..127] +// velocity = release velocity of the note, 127 = quickest possible +// +// Note: The more common method of turning off a note is to use the +// play() function (midi command 0x90) but send an attack velocity of 0. +// + +int MidiOutput::off(int channel, int keynum, int releaseVelocity) { + return send(0x80 | (channel & 0x0f), keynum, releaseVelocity); +} + + + +////////////////////////////// +// +// MidiOutput::pc -- send a patch change MIDI message. changes the timbre +// on the specified channel. +// +// channel = MIDI channel to which to send the patch change [0..15] +// timbre = the voice to select on the specified channel [0..127] +// + +int MidiOutput::pc(int channel, int timbre) { + return send(0xc0 | (channel & 0x0f), timbre); +} + + + +////////////////////////////// +// +// MidiOutput::play -- sends a Note On/Off MIDI message. +// +// channel = MIDI channel to send note on. range is [0..15] +// keynum = MIDI key number to play (middle C = 60, C# = 61, etc.) [0..127] +// velocity = attack velocity of the note, 0 = 0ff, 127 = loudest possible +// + +int MidiOutput::play(int channel, int keynum, int velocity) { + return send(0x90 | (channel & 0x0f), keynum, velocity); +} + + + +////////////////////////////// +// +// MidiOutput::pw -- Pitch Wheel: send a MIDI pitch bend. +// Parameters are: +// 1. channel -- MIDI channel offset from 0. +// 2. mostByte -- most significant 7 bits (coarse tuning) +// 3. leastByte -- least significant 7 bits (fine tuning) +// + +int MidiOutput::pw(int channel, int mostByte, int leastByte) { + return send(0xe0 | (channel & 0x0f), leastByte, mostByte); +} + + + +////////////////////////////// +// +// MidiOutput::pw -- Pitch Wheel: 14 bit number given as input +// range for 14 bit number is 0 to 16383. +// + +int MidiOutput::pw(int channel, int tuningData) { + uchar greaterBits = (uchar)((tuningData >> 7) & 0x7f); + uchar lesserBits = (uchar)(tuningData & 0x7f); + return pw(channel, greaterBits, lesserBits); +} + + + +////////////////////////////// +// +// MidiOutput::pw -- Pitch Wheel: range between -1 to 1 given as input. +// Range is then converted to a 14 bit number. +// +1 = highest value of pitch wheel +// 0 = rest position of pitch wheel +// -1 = lowest value of pitch wheel +// + +int MidiOutput::pw(int channel, double tuningData) { + if (tuningData < -1.0 || tuningData > 1.0) { + std::cerr << "Error: pitch wheel data is out of range: " << tuningData << std::endl; + exit(1); + } + + int output = (int)((tuningData+1.0)/2.0*16383 + 0.5); + return pw(channel, output); +} + + + +////////////////////////////// +// +// MidiOutput::recordStart +// + +void MidiOutput::recordStart(char *filename, int format) { + if (outputRecordQ) { // already recording, so close old file + recordStop(); + } + + outputRecordFile.open(filename, std::ios::out); + if (!outputRecordFile) { // open file failed + std::cerr << "Error: cannot open file " << filename << std::endl; + outputRecordQ = 0; + } else { + outputRecordQ = 1; + } + + if (outputRecordQ) { + switch (format) { + case RECORD_ASCII: // ascii + outputRecordType = RECORD_ASCII; + outputRecordFile <<"; delta time/MIDI output at delta time" << std::endl; + break; + case RECORD_BINARY: // binary + outputRecordType = RECORD_BINARY; + // record the magic number for binary format + outputRecordFile << (uchar)0xf8 << (uchar)0xf8 + << (uchar)0xf8 << (uchar)0xf8; + break; + case RECORD_MIDI_FILE: // standard MIDI file, type 0 + default: + outputRecordType = RECORD_MIDI_FILE; + // header stuff to be written here + break; + } + } + + lastFlushTime = timer.getTime(); +} + + + +////////////////////////////// +// +// MidiOutput::recordStop +// + +void MidiOutput::recordStop(void) { + if (outputRecordQ) { + outputRecordQ = 0; + outputRecordFile.close(); + } +} + + + +////////////////////////////// +// +// MidiOutput::reset -- sends the MIDI command 0xFF which +// should force the MIDI devices on the other side of the +// MIDI cable into their power-on reset condition, clear running +// status, turn off any sounding notes, set Local Control on, and +// otherwise clean up the state of things. +// + +void MidiOutput::reset(void) { + send(0xff, 0, 0); +} + + + +////////////////////////////// +// +// MidiOutput::send -- send a byte to the MIDI port but record it +// first. +// + +int MidiOutput::send(int command, int p1, int p2) { + if (outputRecordQ) { + switch (outputRecordType) { + case 0: // ascii + writeOutputAscii(command, p1, p2); + break; + case 1: // binary + writeOutputBinary(command, p1, p2); + break; + case 2: // standard MIDI file type 0 + writeOutputMidifile(command, p1, p2); + break; + } + lastFlushTime = timer.getTime(); // only keep track if recording + } + return rawsend(command, p1, p2); +} + + +int MidiOutput::send(int command, int p1) { + if (outputRecordQ) { + switch (outputRecordType) { + case 0: // ascii + writeOutputAscii(command, p1, -1); + break; + case 1: // binary + writeOutputBinary(command, p1, -1); + break; + case 2: // standard MIDI file type 0 + writeOutputMidifile(command, p1, -1); + break; + } + lastFlushTime = timer.getTime(); // only keep track if recording + } + return rawsend(command, p1); +} + + +int MidiOutput::send(int command) { + if (outputRecordQ) { + switch (outputRecordType) { + case 0: // ascii + writeOutputAscii(command, -1, -1); + break; + case 1: // binary + writeOutputBinary(command, -1, -1); + break; + case 2: // standard MIDI file type 0 + writeOutputMidifile(command, -1, -1); + break; + } + lastFlushTime = timer.getTime(); // only keep track if recording + } + return rawsend(command); +} + + + +////////////////////////////// +// +// MidiOutput::silence -- send a note off to all notes on all channels. +// default value: aChannel = -1 +// + +void MidiOutput::silence(int aChannel) { + int keyno; + if (aChannel == -1) { + for (int channel=0; channel<16; channel++) { + for (keyno=0; keyno<128; keyno++) { + play(channel, keyno, 0); + } + } + } else { + for (keyno=0; keyno<128; keyno++) { + play(aChannel, keyno, 0); + } + } +} + + + +////////////////////////////// +// +// MidiOutput::sustain -- set the MIDI sustain continuous controller on or off. +// Equivalent to the command cont(channel, 0x40, status). +// + +void MidiOutput::sustain(int channel, int status) { + if (status) { // turn on sustain + cont(channel, 0x40, 127); + } else { // turn off sustain + cont(channel, 0x40, 0); + } +} + + + +/////////////////////////////// +// +// MidiOutput::sysex -- sends a system exclusive MIDI message. +// you must supply the 0xf0 at the start of the array +// and the 0xf7 at the end of the array. +// + +int MidiOutput::sysex(char* data, int length) { + return rawsend((uchar*)data, length); +} + + +int MidiOutput::sysex(uchar* data, int length) { + return rawsend(data, length); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// RPN functions +// + + +////////////////////////////// +// +// NRPN -- sends a Non-registered parameter number where: +// parameter #1: channel (0-15) +// parameter #2: NRPN MSB indicator (controller #99 data) +// parameter #3: NRPN LSB indicator (controller #98 data) +// parameter #4: NRPN MSB data (controller #6 data) +// [parameter #5: NRPN LSB data (controller #38 data)] +// or: +// parameter #1: channel (0-15) +// parameter #2: NRPN MSB indicator (controller #99 data) +// parameter #3: NRPN LSB indicator (controller #98 data) +// parameter #4: NRPN Floating point in range (-1..1) (ccont#6 and #38 data) +// +// +// NRPN (Non-registered parameter number) -- General MIDI and +// Extended MIDI mess. It becomes the receiving synthesizer's +// responsibility to determine the meaning of continuous +// controller (ccont) #6 from data sent with cconts #98,99 (for +// NRPNS) and cconts #100,101 (for RPNS). NRPN parameters +// are not reset when the ccont#121 is sent to reset controllers. +// +// NRPN's are "non-standard" meaning that any synthesizer could +// do whatever they want with a given NRPN; However, the +// GS and XG specifications are given in the table further below. +// +// The data for NRPNs are transfered to synthesizer with +// data slider ccont #6(MSB) and ccont #38(LSB). Also data increment +// ccont#96 (data increment) and ccont#97 (data decrement) are in +// relation to the RPN or NRPN in effect. Increment and Decrement +// are not recommend to use with RPN's because of confusion in the +// MIDI industry over which 7-bit data (#6 or #38) to increment. +// +// Once you have selected an NRPN on a given channel, the +// channel will apply subsequent Data Entry to the +// selected parameter. After making the necessary settings +// you should set NRPN to NULL to reduce the risk of +// operational errors. a NUL RPN will disable the previous +// values of either RPN or NRPN data. +// +// The following NRPN values are supported in Yamaha's XG specification: +// CCont #98 = LSB of NRPN parameter ID +// CCont #99 = MSB of NRPN parameter ID +// +// NRPN +// MSB LSB Data Range +// #99 #98 Parameter (ccont#6=MSB, ccont#38=LSB) +// === ===== ====================== ====================== +// 1 8 Vibrato Rate -64.. 0..+63 logical range or (-50..+50) +// 0..64..127 MIDI data range ( 14..114) +// 1 9 Vibrato Depth same ranges as above +// 1 10 Vibrato Delay same ranges as above +// 1 32 Filter Cutoff Freq. same ranges as above +// 1 33 Filter Resonance same ranges as above +// 1 99 EG Attack Time same ranges as above +// 1 100 EG Decay Time same ranges as above +// 1 102 EG Release Time same ranges as above +// 20 xx Drum Filter Cutoff Freq same ranges as above +// xx = drum MIDI key number +// 21 xx Drum Filter Resonance same ranges as above +// xx = drum MIDI key number +// 22 xx Drum EG Attack Rage same ranges as above +// xx = drum MIDI key number +// 23 xx Drum EG Decay Rate same ranges as above +// xx = drum MIDI key number +// 24 xx Drum Pitch Coarse same ranges as above +// xx = drum MIDI key number +// 25 xx Drum Pitch Fine same ranges as above +// xx = drum MIDI key number +// 26 xx Drum Level 0..64..127 MIDI data range +// xx = drum MIDI key number +// 28 xx Drum Pan Random, Left..Center..Right +// 0.......1.....64......127 MIDI data range +// xx = drum MIDI key number +// 29 xx Drum Reverb Send Level 0..64..127 MIDI data range +// xx = drum MIDI key number +// 30 xx Drum Chorus Send Level 0..64..127 MIDI data range +// xx = drum MIDI key number +// 31 xx Drum Variation Send Level 0..64..127 MIDI data range +// xx = drum MIDI key number +// 127 127 Null RPN (disables RPN/NRPN parameters from being altered). +// +// + +int MidiOutput::NRPN(int channel, int nrpn_msb, int nrpn_lsb, + int data_msb, int data_lsb) { + channel = channel & 0x0f; + nrpn_msb = nrpn_msb & 0x7f; + nrpn_lsb = nrpn_msb & 0x7f; + data_msb = nrpn_msb & 0x7f; + data_lsb = nrpn_msb & 0x7f; + + int status = 1; + + // check to see if the nrpn_msb and nrpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != nrpn_msb) { + status &= cont(channel, 99, nrpn_msb); + rpn_msb_status[getPort()][channel] = nrpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != nrpn_lsb) { + status &= cont(channel, 98, nrpn_lsb); + rpn_lsb_status[getPort()][channel] = nrpn_lsb; + } + + // now that the NRPN state is set, send the NRPN data values + // but do not bother sending any data if the Null RPN is in effect. + if (nrpn_msb != 127 && nrpn_lsb != 127) { + status &= cont(channel, 6, data_msb); + status &= cont(channel, 38, data_msb); + } + + return status; +} + + +int MidiOutput::NRPN(int channel, int nrpn_msb, int nrpn_lsb, int data_msb) { + channel = channel & 0x0f; + nrpn_msb = nrpn_msb & 0x7f; + nrpn_lsb = nrpn_msb & 0x7f; + data_msb = nrpn_msb & 0x7f; + + int status = 1; + + // check to see if the nrpn_msb and nrpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != nrpn_msb) { + status &= cont(channel, 99, nrpn_msb); + rpn_msb_status[getPort()][channel] = nrpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != nrpn_lsb) { + status &= cont(channel, 98, nrpn_lsb); + rpn_lsb_status[getPort()][channel] = nrpn_lsb; + } + + // now that the NRPN state is set, send the NRPN data value, + // but do not bother sending any data if the Null RPN is in effect. + if (nrpn_msb != 127 && nrpn_lsb != 127) { + status &= cont(channel, 6, data_msb); + } + + return status; +} + + +int MidiOutput::NRPN(int channel, int nrpn_msb, int nrpn_lsb, double data) { + channel = channel & 0x0f; + nrpn_msb = nrpn_msb & 0x7f; + nrpn_lsb = nrpn_msb & 0x7f; + if (data < -1.0) { + data = -1.0; + } else if (data > 1.0) { + data = 1.0; + } + + int status = 1; + + // check to see if the nrpn_msb and nrpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != nrpn_msb) { + status &= cont(channel, 99, nrpn_msb); + rpn_msb_status[getPort()][channel] = nrpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != nrpn_lsb) { + status &= cont(channel, 98, nrpn_lsb); + rpn_lsb_status[getPort()][channel] = nrpn_lsb; + } + + // convert data into 14 bit number + int data14 = (int)((data+1.0)/2.0*16383 + 0.5); + + // send the NRPN data values, two message of 7 bits each + // but do not bother sending any data if the Null RPN is in effect. + if (nrpn_msb != 127 && nrpn_lsb != 127) { + status &= cont(channel, 6, data14 >> 7); + status &= cont(channel, 38, data14 & 0x7f); + } + + return status; +} + + +////////// +// +// Convenience functions for use of NRPN function. Note that these +// are "Non-Registered" Parameter Numbers which means that each +// synthesizer manufacture can do whatever they want, so these +// functions might not behave the way you expect them to do so. +// Yamaha XG and Roland GS NRPN specifications are given below. +// + +int MidiOutput::NRPN_null(int channel) { + return NRPN(channel, 127, 127, 0); +} + +int MidiOutput::NRPN_vibratoRate(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 8, value+64); +} + +int MidiOutput::NRPN_vibratoRate(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 8, value); +} + +int MidiOutput::NRPN_vibratoDepth(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 9, value+64); +} + +int MidiOutput::NRPN_vibratoDepth(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 9, value); +} + +int MidiOutput::NRPN_vibratoDelay(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 32, value+64); +} + +int MidiOutput::NRPN_vibratoDelay(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 32, value); +} + +int MidiOutput::NRPN_filterCutoff(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 33, value+64); +} + +int MidiOutput::NRPN_filterCutoff(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 33, value); +} + +int MidiOutput::NRPN_attack(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 99, value+64); +} + +int MidiOutput::NRPN_attack(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 99, value); +} + +int MidiOutput::NRPN_decay(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 100, value+64); +} + +int MidiOutput::NRPN_decay(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 100, value); +} + +int MidiOutput::NRPN_release(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 102, value+64); +} + +int MidiOutput::NRPN_release(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 102, value); +} + +int MidiOutput::NRPN_drumFilterCutoff(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 20, drum, value+64); +} + +int MidiOutput::NRPN_drumFilterCutoff(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 20, drum, value); +} + +int MidiOutput::NRPN_drumFilterResonance(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 21, drum, value+64); +} + +int MidiOutput::NRPN_drumFilterResonance(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 21, drum, value); +} + +int MidiOutput::NRPN_drumAttack(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 22, drum, value+64); +} + +int MidiOutput::NRPN_drumAttack(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 22, drum, value); +} + +int MidiOutput::NRPN_drumDecay(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 23, drum, value+64); +} + +int MidiOutput::NRPN_drumDecay(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 23, drum, value); +} + +int MidiOutput::NRPN_drumPitch(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 24, drum, value+64); +} + +int MidiOutput::NRPN_drumPitch(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 24, drum, value); +} + +int MidiOutput::NRPN_drumLevel(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 26, drum, value+64); +} + +int MidiOutput::NRPN_drumLevel(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 26, drum, value); +} + +int MidiOutput::NRPN_drumPan(int drum, int value) { + return NRPN(9, 28, drum, value+64); +} + +int MidiOutput::NRPN_drumPan(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 28, drum, value); +} + +int MidiOutput::NRPN_drumReverb(int drum, int value) { + // note offset from 0 not -64 + return NRPN(9, 29, drum, value); +} + +int MidiOutput::NRPN_drumReverb(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 29, drum, value); +} + +int MidiOutput::NRPN_drumChorus(int drum, int value) { + // note offset from 0 not -64 + return NRPN(9, 30, drum, value); +} + +int MidiOutput::NRPN_drumChorus(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 30, drum, value); +} + +int MidiOutput::NRPN_drumVariation(int drum, int value) { + // note offset from 0 not -64 + return NRPN(9, 31, drum, value); +} + +int MidiOutput::NRPN_drumVariation(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 31, drum, value); +} + +// +// Convenience functions for use of NRPN function. +// +////////// + + + +////////////////////////////// +// +// RPN -- sends a registered parameter number where: +// parameter #1: channel (0-15) +// parameter #2: RPN MSB indicator (controller #101 data) +// parameter #3: RPN LSB indicator (controller #100 data) +// parameter #4: RPN MSB data (controller #6 data) +// [parameter #5: RPN LSB data (controller #38 data)] +// or: +// parameter #1: channel (0-15) +// parameter #2: NRPN MSB indicator (controller #99 data) +// parameter #3: NRPN LSB indicator (controller #98 data) +// parameter #4: NRPN Floating point in range (-1..1) (ccont#6 and #38 data) +// +// +// RPN (registered parameter number) -- General MIDI and +// Extended MIDI mess. It becomes the receiving synthesizer's +// responsibility to determine the meaning of continuous +// controller (ccont) #6 from data sent with cconts #100,101 (for +// RPNS) and cconts #98,99 (for NRPNS). +// +// The data for RPNs are transfered to synthesizer with +// data slider ccont #6(MSB) and ccont #38(LSB). Also data increment +// ccont#96 (data increment) and ccont#97 (data decrement) are in +// relation to the RPN or NRPN in effect. Increment and Decrement +// are not recommend to use with RPN's because of confusion in the +// MIDI industry over which 7-bit data (#6 or #38) to increment. +// +// Once you have selected an RPN on a given channel, the +// channel will apply subsequent Data Entry to the +// selected parameter. After making the necessary settings +// you should set RPN's to NULL to reduce the risk of +// operational errors. a NULL RPN will disable the previous +// values of either RPN or NRPN data. +// +// The following RPN values are registered: +// CCont #100 = LSB of RPN parameter ID +// CCont #101 = MSB of RPN parameter ID +// +// RPN Data Range +// MSB LSB Parameter (ccont#6=MSB, ccont#38=LSB) +// === ===== ====================== ====================== + +// 0 0 Pitchbend Sensitivity 0-127 (default 2) (LSB ignored) +// (The number of +/- half steps in +// pitch wheel range). +// 0 1 Fine Tune -64.. 0..+63 logical range +// 0..64..127 MIDI data range +// 0 2 Coarse Tune same range as above. +// 0 3 Change Tuning Program 0..127 +// 0 4 Change Tuning Bank 0..127 +// + +int MidiOutput::RPN(int channel, int rpn_msb, int rpn_lsb, + int data_msb, int data_lsb) { + channel = channel & 0x0f; + rpn_msb = rpn_msb & 0x7f; + rpn_lsb = rpn_msb & 0x7f; + data_msb = rpn_msb & 0x7f; + data_lsb = rpn_msb & 0x7f; + + int status = 1; + + // check to see if the rpn_msb and rpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != rpn_msb) { + status &= cont(channel, 101, rpn_msb); + rpn_msb_status[getPort()][channel] = rpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != rpn_lsb) { + status &= cont(channel, 100, rpn_lsb); + rpn_lsb_status[getPort()][channel] = rpn_lsb; + } + + // now that the RPN state is set, send the RPN data values + // but do not bother sending any data if the Null RPN is in effect. + if (rpn_msb != 127 && rpn_lsb != 127) { + status &= cont(channel, 6, data_msb); + status &= cont(channel, 38, data_msb); + } + + return status; +} + + +int MidiOutput::RPN(int channel, int rpn_msb, int rpn_lsb, int data_msb) { + channel = channel & 0x0f; + rpn_msb = rpn_msb & 0x7f; + rpn_lsb = rpn_msb & 0x7f; + data_msb = rpn_msb & 0x7f; + + int status = 1; + + // check to see if the rpn_msb and rpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != rpn_msb) { + status &= cont(channel, 101, rpn_msb); + rpn_msb_status[getPort()][channel] = rpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != rpn_lsb) { + status &= cont(channel, 100, rpn_lsb); + rpn_lsb_status[getPort()][channel] = rpn_lsb; + } + + // now that the RPN state is set, send the RPN data value, + // but do not bother sending any data if the Null RPN is in effect. + if (rpn_msb != 127 && rpn_lsb != 127) { + status &= cont(channel, 6, data_msb); + } + + return status; +} + + +int MidiOutput::RPN(int channel, int rpn_msb, int rpn_lsb, double data) { + channel = channel & 0x0f; + rpn_msb = rpn_msb & 0x7f; + rpn_lsb = rpn_msb & 0x7f; + if (data < -1.0) { + data = -1.0; + } else if (data > 1.0) { + data = 1.0; + } + + int status = 1; + + // check to see if the rpn_msb and rpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != rpn_msb) { + status &= cont(channel, 101, rpn_msb); + rpn_msb_status[getPort()][channel] = rpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != rpn_lsb) { + status &= cont(channel, 100, rpn_lsb); + rpn_lsb_status[getPort()][channel] = rpn_lsb; + } + + // convert data into 14 bit number + int data14 = (int)((data+1.0)/2.0*16383 + 0.5); + + // send the RPN data values, two message of 7 bits each + // but do not bother sending any data if the Null RPN is in effect. + if (rpn_msb != 127 && rpn_lsb != 127) { + status &= cont(channel, 6, data14 >> 7); + status &= cont(channel, 38, data14 & 0x7f); + } + + return status; +} + + +////////// +// +// Convenience functions for use of RPN function. +// + +int MidiOutput::RPN_null(void) { + int status = 1; + for (int i=0; i<16; i++) { + status &= RPN_null(i); + } + return status; +} + +int MidiOutput::RPN_null(int channel) { + return RPN(channel, 127, 127, 0); +} + +int MidiOutput::pbRange(int channel, int steps) { + // default value for pitch bend sensitivity is 2 semitones. + return RPN(channel, 0, 0, steps); +} + +int MidiOutput::tuneFine(int channel, int cents) { + // data from -64 to + 63 + return RPN(channel, 0, 1, cents+64); +} + +int MidiOutput::fineTune(int channel, int cents) { + return tuneFine(channel, cents); +} + +int MidiOutput::tuneCoarse(int channel, int steps) { + // data from -64 to + 63 + return RPN(channel, 0, 1, steps+64); +} + +int MidiOutput::coarseTune(int channel, int steps) { + return tuneCoarse(channel, steps); +} + +int MidiOutput::tuningProgram(int channel, int program) { + return RPN(channel, 0, 3, program); +} + +int MidiOutput::tuningBank(int channel, int bank) { + return RPN(channel, 0, 4, bank); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + + +////////////////////////////// +// +// MidiOutput::initializeRPN -- set up the RPN status arrays +// ignores initiaization request if already initialized. +// + +void MidiOutput::initializeRPN(void) { + int i, channel; + + if (rpn_lsb_status == NULL) { + rpn_lsb_status = new Array<int>[getNumPorts()]; + for (i=0; i<getNumPorts(); i++) { + rpn_lsb_status[i].setSize(16); + rpn_lsb_status[i].allowGrowth(0); + for (channel=0; channel<16; channel++) { + rpn_lsb_status[i][channel] = 127; + } + } + } + + if (rpn_msb_status == NULL) { + rpn_msb_status = new Array<int>[getNumPorts()]; + for (i=0; i<getNumPorts(); i++) { + rpn_msb_status[i].setSize(16); + rpn_msb_status[i].allowGrowth(0); + for (channel=0; channel<16; channel++) { + rpn_msb_status[i][channel] = 127; + } + } + } +} + + + +////////////////////////////// +// +// MidiOutput::deinitializeRPN -- destroy the RPN status arrays +// do nothing if the arrays are not initialized +// + +void MidiOutput::deinitializeRPN(void) { + if (rpn_msb_status != NULL) { + delete [] rpn_msb_status; + rpn_msb_status = NULL; + } + + if (rpn_msb_status != NULL) { + delete [] rpn_msb_status; + rpn_msb_status = NULL; + } +} + + + +////////////////////////////// +// +// MidiOutput::writeOutputAscii +// + +void MidiOutput::writeOutputAscii(int command, int p1, int p2) { + outputRecordFile << std::dec; + outputRecordFile.width(6); + outputRecordFile << (timer.getTime()-lastFlushTime) <<'\t'; + outputRecordFile << "0x" << std::hex; + outputRecordFile.width(2); + outputRecordFile << command << ' '; + outputRecordFile << std::dec; + outputRecordFile.width(3); + outputRecordFile << p1 << ' '; + outputRecordFile << std::dec; + outputRecordFile.width(3); + outputRecordFile<< p2; + outputRecordFile << std::endl; +} + + + +////////////////////////////// +// +// MidiOutput::writeOutputBinary +// + +void MidiOutput::writeOutputBinary(int command, int p1, int p2) { + // don't store 0xf8 command since it will be used to mark the end of the + if (command == 0xf8) return; + + // write the delta time (four bytes) + outputRecordFile.writeBigEndian((ulong)(timer.getTime() - lastFlushTime)); + + // write midi data + // don't store 0xf8 command since it will be used to mark the end of the + // delta time data. + outputRecordFile << (uchar)p1; + outputRecordFile << (uchar)p2; + outputRecordFile << (uchar)0xf8; +} + + + +////////////////////////////// +// +// MidiOutput::writeOutputMidifile +// + +void MidiOutput::writeOutputMidifile(int command, int p1, int p2) { + // not yet implemented +} + + + +// md5sum: 1c518e5130ac9ba0d79c4e9ce7fa41cf - MidiOutput.cpp =css= 20030102 diff --git a/src/midiio/src/MidiPort.cpp b/src/midiio/src/MidiPort.cpp new file mode 100644 index 0000000..1a03dac --- /dev/null +++ b/src/midiio/src/MidiPort.cpp @@ -0,0 +1,189 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: 21 December 1997 +// Last Modified: Fri Jan 23 10:24:35 GMT-0800 1998 +// Filename: .../sig/code/control/MidiPort/MidiPort.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiPort.cpp +// Syntax: C++ +// +// Description: A unified object that handles basic MIDI input and output. +// Derived from the MidiInPort and MidiOutPort classes. +// + +#include "MidiPort.h" + + +////////////////////////////// +// +// MidiPort::MidiPort +// + +MidiPort::MidiPort(void) : MidiOutPort(), MidiInPort() { + // nothing +} + + +MidiPort::MidiPort(int outputPort, int inputPort) : + MidiOutPort(outputPort), MidiInPort(inputPort) { + // nothing +} + + + +////////////////////////////// +// +// MidiPort::~MidiPort +// + +MidiPort::~MidiPort() { + // nothing +} + + + +////////////////////////////// +// +// MidiPort::getChannelInOffset -- return the MIDI channel offset of +// the MIDI input. +// + +int MidiPort::getChannelInOffset(void) const { + return MidiInPort::getChannelOffset(); +} + + + +////////////////////////////// +// +// MidiPort::getChannelOutOffset -- return the MIDI channel offset of +// the MIDI output. +// + +int MidiPort::getChannelOutOffset (void) const { + return MidiOutPort::getChannelOffset(); +} + + + +////////////////////////////// +// +// MidiPort::getInputPort +// + +int MidiPort::getInputPort(void) { + return MidiInPort::getPort(); +} + + + +////////////////////////////// +// +// MidiPort::getInputTrace +// + +int MidiPort::getInputTrace(void) { + return MidiInPort::getTrace(); +} + + + +////////////////////////////// +// +// MidiPort::getOutputPort +// + +int MidiPort::getOutputPort(void) { + return MidiOutPort::getPort(); +} + + + +////////////////////////////// +// +// MidiPort::getOutputTrace +// + +int MidiPort::getOutputTrace(void) { + return MidiOutPort::getTrace(); +} + + + +////////////////////////////// +// +// MidiPort::setChannelOffset -- sets the MIDI channel offset +// + +void MidiPort::setChannelOffset(int anOffset) { + MidiInPort::setChannelOffset(anOffset); + MidiOutPort::setChannelOffset(anOffset); +} + + + +////////////////////////////// +// +// MidiPort::setInputPort +// + +void MidiPort::setInputPort(int aPort) { + MidiInPort::setPort(aPort); +} + + + +////////////////////////////// +// +// MidiPort::setInputTrace +// + +int MidiPort::setInputTrace(int aState) { + return MidiInPort::setTrace(aState); +} + + + +////////////////////////////// +// +// MidiPort::setOutputPort +// + +void MidiPort::setOutputPort(int aPort) { + MidiOutPort::setPort(aPort); +} + + + +////////////////////////////// +// +// MidiPort::setOutputTrace +// + +int MidiPort::setOutputTrace(int aState) { + return MidiOutPort::setTrace(aState); +} + + + +////////////////////////////// +// +// MidiPort::toggleInputTrace +// + +void MidiPort::toggleInputTrace(void) { + MidiInPort::toggleTrace(); +} + + +////////////////////////////// +// +// MidiPort::toggleOutputTrace +// + +void MidiPort::toggleOutputTrace(void) { + MidiOutPort::toggleTrace(); +} + + + +// md5sum: c2583f3ed21e238ba6b298915cb728aa - MidiPort.cpp =css= 20030102 diff --git a/src/midiio/src/Options.cpp b/src/midiio/src/Options.cpp new file mode 100644 index 0000000..0341fe3 --- /dev/null +++ b/src/midiio/src/Options.cpp @@ -0,0 +1,887 @@ +// +// Copyright 1998-2000 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Apr 5 13:07:18 PDT 1998 +// Last Modified: Sat Mar 27 18:17:06 PST 1999 +// Last Modified: Thu Apr 13 14:02:52 PDT 2000 (added 2nd define function) +// Last Modified: Fri May 5 17:52:01 PDT 2000 (added --options suppression) +// Last Modified: Tue May 1 01:25:58 PDT 2001 (fixed getArgumentCount()) +// Filename: ...sig/maint/code/sigBase/Options.cpp +// Web Address: http://sig.sapp.org/src/sigBase/Options.cpp +// Documentation: http://sig.sapp.org/doc/classes/Options +// Syntax: C++ +// +// Description: Handles command-line options in a graceful manner. +// + +int optionListCompare(const void* a, const void* b); + +#include "Options.h" +#include "Options_private.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <iostream> + + +////////////////////////////// +// +// Options::Options -- +// + +Options::Options(void) { + optionFlag = '-'; + gargc = -1; + gargv = NULL; + argument.setSize(0); + argument.allowGrowth(); + optionRegister.setSize(0); + optionRegister.allowGrowth(); + optionList.setSize(0); + optionList.allowGrowth(); + processedQ = 0; + sortedQ = 0; + commandString = NULL; + options_error_check = 1; + suppressQ = 0; + optionsArgument = 0; +} + + +Options::Options(int argc, char** argv) { + optionFlag = '-'; + gargc = -1; + gargv = NULL; + argument.setSize(0); + argument.allowGrowth(); + optionRegister.setSize(0); + optionRegister.allowGrowth(); + optionList.setSize(0); + optionList.allowGrowth(); + processedQ = 0; + sortedQ = 0; + commandString = NULL; + options_error_check = 1; + suppressQ = 0; + optionsArgument = 0; + + setOptions(argc, argv); +} + + + +////////////////////////////// +// +// Options::~Options -- +// + +Options::~Options() { + reset(); +} + + + +////////////////////////////// +// +// Options::argc -- returns the argument count as from main(). +// + +int Options::argc(void) const { + return gargc; +} + + + +////////////////////////////// +// +// Options::argv -- returns the arguments strings as from main(). +// + +char** Options::argv(void) const { + return gargv; +} + + + +////////////////////////////// +// +// Options::define -- define an option entry in the option register +// + +void Options::define(const char* aDefinition) { + sortedQ = 0; // have to sort option list later + option_register* definitionEntry; + option_list* optionListEntry; + + + // error if the definition string doesn't contain an equals sign. + if (strchr(aDefinition, '=') == NULL) { + std::cout << "Error: no \"=\" in option definition: " << aDefinition << std::endl; + exit(1); + } + + // get the length of the definition string + int len = strlen(aDefinition); + + // put space before and after the equals sign so that strtok works + char* definitionString; + definitionString = new char[len + 3]; + int i = 0; + while (aDefinition[i] != '=' && i < len) { + definitionString[i] = aDefinition[i]; + i++; + } + definitionString[i] = ' '; + i++; + definitionString[i] = '='; + i++; + definitionString[i] = ' '; + for (int k=i; k<len+2; k++) { + definitionString[k+1] = aDefinition[k-1]; + } + len += 2; + + // determine the registry index for the definition + int definitionIndex = optionRegister.getSize(); + + + // set up space for a definition entry + definitionEntry = new option_register(aDefinition, OPTION_UNKNOWN_TYPE, + "", NULL); + + + char *tempstr; // temporary storage for strtok use on defaultString + tempstr = new char[len + 1]; + strncpy(tempstr, definitionString, len); + + char *optionName; // option name to add to list + + // get the first option name + optionName = strtok(tempstr, " \t\n|"); + if (optionName[0] == '=') { + std::cout << "Error: must specify an option name in definition: " + << aDefinition << std::endl; + exit(1); + } + // store an entry for each option name alias + const char* tempsearch; + while (optionName != NULL && optionName[0] != '=') { + tempsearch = getDefinition(optionName); + if (tempsearch != NULL) { + std::cerr << "option name \"" << optionName + << "\" from definition: " << aDefinition << std::endl; + std::cerr << "is already defined in definition: " + << tempsearch << std::endl; + exit(1); + } + optionListEntry = new option_list(optionName, definitionIndex); + optionList.append(optionListEntry); + optionName = strtok(NULL, " \t\n|"); + } + if (optionName == NULL) { + std::cout << "Error: unknown error in definition: " << aDefinition << std::endl; + exit(1); + } + + // now process the option type and any default value. + i = 0; + + // find the equals sign + while (definitionString[i] != '=' && i < len) { + i++; + } + i++; + // skip over any white space + while (isspace(definitionString[i]) && i < len) { + i++; + } + + // this character must be the option type + char optionType = (char)tolower(definitionString[i]); + definitionEntry->setType(optionType); + i++; + + + // check to make sure that the type is correct. + if (optionType != OPTION_STRING_TYPE && + optionType != OPTION_INT_TYPE && + optionType != OPTION_FLOAT_TYPE && + optionType != OPTION_DOUBLE_TYPE && + optionType != OPTION_BOOLEAN_TYPE && + optionType != OPTION_CHAR_TYPE ) { + std::cout << "Error: unknown option type \'" << optionType + << "\' in defintion: " << aDefinition << std::endl; + exit(1); + } + + // skip any white space after option type. + while (isspace(definitionString[i]) && i < len) { + i++; + } + + + // there can only be two characters now: '\0' or ':' + if (i >= len || definitionString[i] == '\0') { + goto option_finish; + } else if (i<len && definitionString[i] == ':') { + i++; + } else { + std::cout << "Unknown error in definition: " << aDefinition << std::endl; + exit(1); + } + + + // now proces the default string. store it in a temp storage for copying + + // skip any white space after option type. + while (i < len && isspace(definitionString[i])) { + i++; + } + if (i >= len || definitionString[i] == '\0') { + goto option_finish; + } + + + // now at beginnng of default option string which continues + // until the end of the definition string. + definitionEntry->setDefault(&definitionString[i]); + +option_finish: + + optionRegister.append(definitionEntry); + + + delete [] definitionString; + delete [] tempstr; + +} + + +void Options::define(const char* aDefinition, const char* description) { + define(aDefinition); + + // now find some place to store the description... +} + + + +////////////////////////////// +// +// Options::getArg -- returns the specified argument. +// argurment 0 is the command name. +// + +char* Options::getArg(int index) { + if (index < 0 || index >= argument.getSize()) { + std::cout << "Error: argument " << index << " does not exist." << std::endl; + exit(1); + } + return argument[index]; +} + + + +////////////////////////////// +// +// Options::getArgument -- same as getArg +// + +char* Options::getArgument(int index) { + return getArg(index); +} + + + +////////////////////////////// +// +// Options::getArgCount -- number of arguments on command line. +// does not count the options or the command name. +// + +int Options::getArgCount(void) { + return argument.getSize() - 1; +} + + + +////////////////////////////// +// +// Options::getArgumentCount -- Same as getArgCount(). +// + +int Options::getArgumentCount(void) { + return getArgCount(); +} + + + +////////////////////////////// +// +// Options::getBoolean -- returns true if the option was +// used on the command line. +// + +int Options::getBoolean(const char* optionName) { + int index = getRegIndex(optionName); + if (index < 0) { + return 0; + } + if (optionRegister[index]->getModifiedQ() == 1) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// Options::getCommand -- returns argv[0] +// + +const char* Options::getCommand(void) { + if (argument.getSize() == 0) { + return ""; + } else { + return argument[0]; + } +} + + + +////////////////////////////// +// +// Options::getCommandLine -- returns a string which contains the +// command-line call to the program. +// + +const char* Options::getCommandLine(void) { + if (commandString != NULL) { + return commandString; + } + + int length = 0; + int i; + for (i=0; i<gargc; i++) { + length += strlen(gargv[i]) + 1; + } + length--; // remove the last space + commandString = new char[length + 1]; + strcpy(commandString, gargv[0]); + for (i=1; i<gargc; i++) { + strcat(commandString, " "); + strcat(commandString, gargv[i]); + } + + return commandString; +} + + + + +////////////////////////////// +// +// Options::getDefinition -- returns the definition +// for the specified option name. Returns NULL +// if there is no entry for the option name. +// It is assumed that the option list is unsorted. +// spaces count in the input option name. +// + +const char* Options::getDefinition(const char* optionName) { + int i; + for (i=0; i<optionList.getSize(); i++) { + if (strcmp(optionName, optionList[i]->getName()) == 0) { + return optionRegister[optionList[i]->getIndex()]->getDefinition(); + } + } + return (const char*)NULL; +} + + + +////////////////////////////// +// +// Options::getDouble -- returns the double float associated +// with the given option. Returns 0 if there is no +// number associated with the option. +// + +double Options::getDouble(const char* optionName) { + return strtod(getString(optionName), (char**)NULL); +} + + + +////////////////////////////// +// +// Options::getFlag -- +// + +char Options::getFlag(void) { + return optionFlag; +} + + + +////////////////////////////// +// +// Options::getFloat -- returns the floating point number +// associated with the given option. +// + +float Options::getFloat(const char* optionName) { + return (float)getDouble(optionName); +} + + + +////////////////////////////// +// +// Options::getInt -- returns the integer argument. Can handle +// hexadecimal, decimal, and octal written in standard +// C syntax. +// + +int Options::getInt(const char* optionName) { + return (int)strtol(getString(optionName), (char**)NULL, 0); +} + +int Options::getInteger(const char* optionName) { + return getInt(optionName); +} + + + +////////////////////////////// +// +// Options::getString -- +// + +const char* Options::getString(const char* optionName) { + int index = getRegIndex(optionName); + if (index < 0) { + return "UNKNOWN OPTION"; + } else { + return optionRegister[index]->getOption(); + } +} + + + +////////////////////////////// +// +// Options::optionsArg -- returns true if the --options is present +// on the command line, otherwise returns false. +// + +int Options::optionsArg(void) { + return optionsArgument; +} + + + +////////////////////////////// +// +// Options::print -- +// + +void Options::print(void) { + for (int i=0; i<optionRegister.getSize(); i++) { + std::cout << optionRegister[i]->getDefinition() << std::endl; + } +} + + + +////////////////////////////// +// +// Options::reset -- +// + +void Options::reset(void) { + int i; + for (i=0; i<optionRegister.getSize(); i++) { + delete optionRegister[i]; + } + optionRegister.setSize(0); + for (i=0; i<optionList.getSize(); i++) { + delete optionList[i]; + } + optionList.setSize(0); + for (i=0; i<argument.getSize(); i++) { + delete [] argument[i]; + } + argument.setSize(0); + + if (commandString != NULL) { + delete [] commandString; + } +} + + + +////////////////////////////// +// +// Options::setFlag -- set the character used to indicate an +// option. For unix this is usually '-', in MS-DOS, +// this is usually '/'; But the syntax of the Options +// class is for Unix-style options. +// + +void Options::setFlag(char aFlag) { + optionFlag = aFlag; +} + + + + +////////////////////////////// +// +// setModified -- +// + +void Options::setModified(const char* optionName, const char* aString) { + int index = getRegIndex(optionName); + if (index < 0) { + return; + } + + optionRegister[getRegIndex(optionName)]->setModified(aString); +} + + + + +////////////////////////////// +// +// setOptions -- +// + +void Options::setOptions(int argc, char** argv) { + processedQ = 0; + + gargc = argc; + gargv = argv; +} + + + +////////////////////////////// +// +// Options:getType -- returns the type of the option +// + +char Options::getType(const char* optionName) { + int index = getRegIndex(optionName); + if (index < 0) { + return -1; + } else { + return optionRegister[getRegIndex(optionName)]->getType(); + } +} + + + +////////////////////////////// +// +// Options::process -- same as verify +// default values: error_check = 1, suppress = 0; +// + +void Options::process(int argc, char** argv, int error_check, int suppress) { + setOptions(argc, argv); + verify(error_check, suppress); +} + + +void Options::process(int error_check, int suppress) { + verify(error_check, suppress); +} + + + +////////////////////////////// +// +// Options::verify -- +// default value: error_check = 1, suppress = 0; +// + +void Options::verify(int error_check, int suppress) { + options_error_check = error_check; + int gargp = 1; + int optionend = 0; + + if (suppress) { + suppressQ = 1; + } else { + suppressQ = 0; + } + + // if calling verify again, must remove previous argument list. + if (argument.getSize() != 0) { + for (int j=0; j<argument.getSize(); j++) { + delete argument[j]; + } + argument.setSize(0); + } + + char* tempargument; + tempargument = new char[strlen(gargv[0])+1]; + strcpy(tempargument, gargv[0]); + argument.append(tempargument); + + int oldgargp; + int position = 0; + int running = 0; + while (gargp < gargc && optionend == 0) { + if (optionQ(gargv[gargp], gargp)) { + oldgargp = gargp; + gargp = storeOption(gargp, position, running); + if (gargp != oldgargp) { + running = 0; + position = 0; + } + } else { + if ( strlen(gargv[gargp]) == 2 && gargv[gargp][0] == getFlag() && + gargv[gargp][2] == getFlag() ) { + optionend = 1; + gargp++; + break; + } else { // this is an argument + tempargument = new char[strlen(gargv[gargp])+1]; + strcpy(tempargument, gargv[gargp]); + argument.append(tempargument); + gargp++; + } + } + } + + while (gargp < gargc) { + tempargument = new char[strlen(gargv[gargp])+1]; + strcpy(tempargument, gargv[gargp]); + argument.append(tempargument); + gargp++; + } + +} + + +void Options::verify(int argc, char** argv, int error_check, int suppress) { + setOptions(argc, argv); + verify(error_check, suppress); +} + + + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + + +////////////////////////////// +// +// getRegIndex -- returns the index of the option associated +// with this name. +// + +int Options::getRegIndex(const char* optionName) { + if (suppressQ && strcmp("options", optionName) == 0) { + return -1; + } + + if (sortedQ == 0) { + sortOptionNames(); + } + option_list key(optionName, -1); + option_list* keyp = &key; + void* searchresult; + searchresult = bsearch(&keyp, optionList.getBase(), + optionList.getSize(), sizeof(option_list*), optionListCompare); + if (searchresult != NULL) { + return (*((option_list**)searchresult))->getIndex(); + } else if (strcmp("options", optionName) == 0) { + print(); + exit(1); + } + + if (options_error_check) { + std::cout << "Error: unknown option \"" << optionName << "\"." << std::endl; + print(); + exit(1); + } + + return -1; +} + + + +////////////////////////////// +// +// optionQ -- returns true if the string is an option +// "--" is not an option, also '-' is not an option. +// aString is assumed to not be NULL. +// + +int Options::optionQ(const char* aString, int& argp) { + if (aString[0] == getFlag()) { + if (aString[1] == '\0') { + argp++; + return 0; + } else if (aString[1] == getFlag()) { + if (aString[2] == '\0') { + argp++; + return 0; + } else { + return 1; + } + } else { + return 1; + } + } else { + return 0; + } +} + + + + +////////////////////////////// +// +// sortOptionNames -- +// + +void Options::sortOptionNames(void) { + qsort(optionList.getBase(), optionList.getSize(), + sizeof(option_list*), optionListCompare); + sortedQ = 1; +} + + + +////////////////////////////// +// +// storeOption -- +// + +#define OPTION_FORM_SHORT 0 +#define OPTION_FORM_LONG 1 +#define OPTION_FORM_CONTINUE 2 + +int Options::storeOption(int gargp, int& position, int& running) { + int optionForm; + char tempname[1024]; + char optionType = '\0'; + + if (running) { + optionForm = OPTION_FORM_CONTINUE; + } else if (gargv[gargp][1] == getFlag()) { + optionForm = OPTION_FORM_LONG; + } else { + optionForm = OPTION_FORM_SHORT; + } + + switch (optionForm) { + case OPTION_FORM_CONTINUE: + position++; + tempname[0] = gargv[gargp][position]; + tempname[1] = '\0'; + optionType = getType(tempname); + if (optionType != OPTION_BOOLEAN_TYPE) { + running = 0; + position++; + } + break; + case OPTION_FORM_SHORT: + position = 1; + tempname[0] = gargv[gargp][position]; + tempname[1] = '\0'; + optionType = getType(tempname); + if (optionType != OPTION_BOOLEAN_TYPE) { + position++; + } + break; + case OPTION_FORM_LONG: + position = 2; + while (gargv[gargp][position] != '=' && + gargv[gargp][position] != '\0') { + tempname[position-2] = gargv[gargp][position]; + position++; + } + tempname[position-2] = '\0'; + optionType = getType(tempname); + if (optionType == -1) { // suppressed --options option + optionsArgument = 1; + break; + } + if (gargv[gargp][position] == '=') { + if (optionType == OPTION_BOOLEAN_TYPE) { + std::cout << "Error: boolean variable cannot have any options: " + << tempname << std::endl; + exit(1); + } + position++; + } + break; + } + + if (optionType == -1) { // suppressed --options option + optionsArgument = 1; + gargp++; + position = 0; + return gargp; + } + + if (gargv[gargp][position] == '\0' && + optionType != OPTION_BOOLEAN_TYPE) { + gargp++; + position = 0; + } + + if (optionForm != OPTION_FORM_LONG && optionType == OPTION_BOOLEAN_TYPE && + gargv[gargp][position+1] != '\0') { + running = 1; + } else if (optionType == OPTION_BOOLEAN_TYPE && + gargv[gargp][position+1] == '\0') { + running = 0; + } + + if (gargp >= gargc) { + std::cout << "Error: last option requires a parameter" << std::endl; + exit(1); + } + setModified(tempname, &gargv[gargp][position]); + + if (!running) { + gargp++; + } + return gargp; +} + + +/////////////////////////////////////////////////////////////////////////// +// +// helping function +// + +////////////////////////////// +// +// optionListCompare -- for sorting the option list +// + +int optionListCompare(const void* a, const void* b) { +//cerr << " comparing: " << (*((option_list**)a))->getName() +// << " i=" << (*((option_list**)a))->getIndex() +// << " :to: " +// << (*((option_list**)b))->getName() +// << " i=" << (*((option_list**)b))->getIndex() << std::endl; + return strcmp((*((option_list**)a))->getName(), + (*((option_list**)b))->getName()); +} + + + +// md5sum: 63584ffabc92170fdb9ef5caedb5a3f6 - Options.cpp =css= 20030102 diff --git a/src/midiio/src/Options_private.cpp b/src/midiio/src/Options_private.cpp new file mode 100644 index 0000000..5a875a8 --- /dev/null +++ b/src/midiio/src/Options_private.cpp @@ -0,0 +1,358 @@ +// +// Copyright 1998-1999 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Apr 5 13:07:18 PDT 1998 +// Last Modified: Sun Jan 10 05:43:24 PST 1999 +// Filename: ...sig/maint/code/sigBase/Options_private.cpp +// Web Address: http://sig.sapp.org/src/sigBase/Options_private.cpp +// Syntax: C++ +// +// Description: A private set of functions for use in the Options class. +// + +#include "Options_private.h" +#include <iostream> +#include <stdlib.h> +#include <string.h> + + +////////////////////////////// +// +// option_register::option_register -- +// + +option_register::option_register(void) { + definition = NULL; + defaultOption = NULL; + modifiedOption = NULL; + type = 's'; +} + + +option_register::option_register(const char* aDefinition, char aType, + const char* aDefaultOption, const char* aModifiedOption) { + definition = NULL; + defaultOption = NULL; + modifiedOption = NULL; + + setType(aType); + setDefinition(aDefinition); + setDefault(aDefaultOption); + setModified(aModifiedOption); +} + + + +////////////////////////////// +// +// option_register::~option_register -- +// + +option_register::~option_register() { + if (definition != NULL) { + delete [] definition; + } + definition = NULL; + + if (defaultOption != NULL) { + delete [] defaultOption; + } + defaultOption = NULL; + + if (modifiedOption != NULL) { + delete [] modifiedOption; + } + modifiedOption = NULL; +} + + + +////////////////////////////// +// +// option_register::clearModified -- sets the modified string to +// NULL. +// + +void option_register::clearModified(void) { + if (modifiedOption != NULL) { + delete [] modifiedOption; + } + modifiedOption = NULL; +} + + + +////////////////////////////// +// +// option_register::getDefinition -- returns the initial definition +// string used to define this entry. +// + +const char* option_register::getDefinition(void) { + return definition; +} + + + +////////////////////////////// +// +// option_register::getDefault -- returns the default string +// to be returned. Will never return a NULL; +// + +const char* option_register::getDefault(void) { + return defaultOption; +} + + + +////////////////////////////// +// +// option_register::getModified -- return the modified +// option string +// + +const char* option_register::getModified(void) { + return modifiedOption; +} + + + +////////////////////////////// +// +// option_register::getModifiedQ -- returns true if +// modified string is not null, false otherwise. +// + +int option_register::getModifiedQ(void) { + if (modifiedOption == NULL) { + return 0; + } else { + return 1; + } +} + + + +////////////////////////////// +// +// option_register::getType -- +// + +char option_register::getType(void) { + return type; +} + + + +////////////////////////////// +// +// option_register::getOption -- return the modified option +// or the default option if no modified option. +// + +const char* option_register::getOption(void) { + if (getModifiedQ()) { + return getModified(); + } else { + return getDefault(); + } +} + + + +////////////////////////////// +// +// option_register::reset -- deallocate space for all +// strings in object. (but default string is set to "") +// + +void option_register::reset(void) { + if (definition != NULL) { + delete [] definition; + } + definition = NULL; + + if (defaultOption != NULL) { + delete [] defaultOption; + } + defaultOption = NULL; + defaultOption = new char[1]; + defaultOption[0] = '\0'; + + if (modifiedOption != NULL) { + delete [] modifiedOption; + } + modifiedOption = NULL; +} + + + +////////////////////////////// +// +// option_register::setDefault -- +// + +void option_register::setDefault(const char* aString) { + if (aString == NULL) { + std::cout << "Error: default string cannot be null" << std::endl; + exit(1); + } + + if (defaultOption != NULL) { + delete [] defaultOption; + } + if (aString == NULL) { + defaultOption = NULL; + } else { + defaultOption = new char[strlen(aString) + 1]; + strcpy(defaultOption, aString); + } +} + + + +////////////////////////////// +// +// option_register::setDefinition -- +// + +void option_register::setDefinition(const char* aString) { + + if (definition != NULL) { + delete [] definition; + } + if (aString == NULL) { + definition = NULL; + } else { + definition = new char[strlen(aString) + 1]; + strcpy(definition, aString); + } + +} + + + +////////////////////////////// +// +// option_register::setModified -- +// + +void option_register::setModified(const char* aString) { + if (modifiedOption != NULL) { + delete [] modifiedOption; + } + if (aString == NULL) { + modifiedOption = NULL; + } else { + modifiedOption = new char[strlen(aString) + 1]; + strcpy(modifiedOption, aString); + } +} + + + +////////////////////////////// +// +// option_register::setType -- +// + +void option_register::setType(char aType) { + type = aType; +} + + + +///////////////////////////////////////////////////////////////////////////// +/// option_list class definitions /////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + + +////////////////////////////// +// +// option_list::option_list -- +// + +option_list::option_list(void) { + name = NULL; + index = -1; +} + + + +////////////////////////////// +// +// option_list::option_list -- +// + +option_list::option_list(const char* optionName, int anIndex) { + name = NULL; + setIndex(anIndex); + setName(optionName); +} + + + +////////////////////////////// +// +// option_list::~option_list -- +// + +option_list::~option_list() { + if (name != NULL) { + delete [] name; + } + name = NULL; +} + + + +////////////////////////////// +// +// option_list::getIndex -- +// + +int option_list::getIndex(void) { + return index; +} + + + +////////////////////////////// +// +// option_list::getName -- +// + +const char* option_list::getName(void) { + return name; +} + + + +////////////////////////////// +// +// option_list::setName -- +// + +void option_list::setName(const char* aString) { + if (name != NULL) { + delete [] name; + } + name = new char[strlen(aString) + 1]; + strcpy(name, aString); +} + + + +////////////////////////////// +// +// option_list::setIndex -- +// + +void option_list::setIndex(int anIndex) { + index = anIndex; +} + + + +// md5sum: be3cc8ad0380820a9ea96739dc989657 - Options_private.cpp =css= 20030102 diff --git a/src/midiio/src/Sequencer_alsa.cpp b/src/midiio/src/Sequencer_alsa.cpp new file mode 100644 index 0000000..4c80e22 --- /dev/null +++ b/src/midiio/src/Sequencer_alsa.cpp @@ -0,0 +1,643 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Thu May 11 21:10:02 PDT 2000 +// Last Modified: Sat Oct 13 14:51:43 PDT 2001 (updated for ALSA 0.9 interface) +// Filename: ...sig/maint/code/control/Sequencer_alsa.cpp +// Web Address: http://sig.sapp.org/src/sig/Sequencer_alsa.cpp +// Syntax: C++ +// +// Description: Basic MIDI input/output functionality for the +// Linux ALSA raw midi devices. This class +// is inherited by the classes MidiInPort_alsa and +// MidiOutPort_alsa. +// + +#if defined(LINUX) && defined(ALSA) + +#include "Collection.h" +#include <alsa/asoundlib.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <string.h> +#include <iostream> +#include <stdio.h> +#include <dirent.h> /* for reading filename for MIDI info */ +#include "Sequencer_alsa.h" + +typedef unsigned char uchar; + +// define static variables: +int Sequencer_alsa::class_count = 0; +int Sequencer_alsa::initialized = 0; + +// static variables for MIDI I/O information database +int Sequencer_alsa::indevcount = 0; +int Sequencer_alsa::outdevcount = 0; + +Collection<snd_rawmidi_t*> Sequencer_alsa::rawmidi_in; +Collection<snd_rawmidi_t*> Sequencer_alsa::rawmidi_out; +Collection<int> Sequencer_alsa::midiincard; +Collection<int> Sequencer_alsa::midioutcard; +Collection<int> Sequencer_alsa::midiindevice; +Collection<int> Sequencer_alsa::midioutdevice; +Collection<char*> Sequencer_alsa::midiinname; +Collection<char*> Sequencer_alsa::midioutname; + + + +/////////////////////////////// +// +// Sequencer_alsa::Sequencer_alsa -- +// default value: autoOpen = 1; +// + +Sequencer_alsa::Sequencer_alsa(int autoOpen) { + if (class_count < 0) { + std::cerr << "Unusual class instantiation count: " << class_count << std::endl; + exit(1); + } else if (class_count == 0) { + buildInfoDatabase(); + } + + // will not autoOpen + + class_count++; +} + + + +////////////////////////////// +// +// Sequencer_alsa::~Sequencer_alsa -- +// + +Sequencer_alsa::~Sequencer_alsa() { + + if (class_count == 1) { + close(); + removeInfoDatabase(); + } else if (class_count <= 0) { + std::cerr << "Unusual class instantiation count: " << class_count << std::endl; + exit(1); + } + + class_count--; +} + + + +////////////////////////////// +// +// Sequencer_alsa::close -- close the sequencer device. The device +// automatically closes once the program ends. +// + +void Sequencer_alsa::close(void) { + int i; + + for (i=0; i<getNumInputs(); i++) { + if (rawmidi_in[i] != NULL) { + snd_rawmidi_close(rawmidi_in[i]); + rawmidi_in[i] = NULL; + } + } + + for (i=0; i<getNumOutputs(); i++) { + if (rawmidi_out[i] != NULL) { + snd_rawmidi_close(rawmidi_out[i]); + rawmidi_out[i] = NULL; + } + } + +} + + +void Sequencer_alsa::closeInput(int index) { + if (index < 0 || index >= rawmidi_in.getSize()) { + return; + } + + if (rawmidi_in[index] != NULL) { + snd_rawmidi_close(rawmidi_in[index]); + rawmidi_in[index] = NULL; + } +} + + +void Sequencer_alsa::closeOutput(int index) { + if (index < 0 || index >= rawmidi_out.getSize()) { + return; + } + + if (rawmidi_out[index] != NULL) { + snd_rawmidi_close(rawmidi_out[index]); + rawmidi_out[index] = NULL; + } +} + + + +////////////////////////////// +// +// Sequencer_alsa::displayInputs -- display a list of the +// available MIDI input devices. +// default values: out = std::cout, initial = "\t" +// + +void Sequencer_alsa::displayInputs(std::ostream& out, char* initial) { + for (int i=0; i<getNumInputs(); i++) { + out << initial << i << ": " << getInputName(i) << '\n'; + } +} + + + +////////////////////////////// +// +// Sequencer_alsa::displayOutputs -- display a list of the +// available MIDI output devices. +// default values: out = std::cout, initial = "\t" +// + +void Sequencer_alsa::displayOutputs(std::ostream& out, char* initial) { + for (int i=0; i<getNumOutputs(); i++) { + out << initial << i << ": " << getOutputName(i) << '\n'; + } +} + + + +////////////////////////////// +// +// Sequencer_alsa::getInputName -- returns a string to the name of +// the specified input device. The string will remain valid as +// long as there are any sequencer devices in existence. +// + +const char* Sequencer_alsa::getInputName(int aDevice) { + if (initialized == 0) { + buildInfoDatabase(); + } + return midiinname[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa::getNumInputs -- returns the total number of +// MIDI inputs that can be used. +// + +int Sequencer_alsa::getNumInputs(void) { + if (initialized == 0) { + buildInfoDatabase(); + } + return indevcount; +} + + + +////////////////////////////// +// +// Sequencer_alsa::getNumOutputs -- returns the total number of +// MIDI inputs that can be used. +// + +int Sequencer_alsa::getNumOutputs(void) { + if (initialized == 0) { + buildInfoDatabase(); + } + return outdevcount; +} + + + +////////////////////////////// +// +// Sequencer_alsa::getOutputName -- returns a string to the name of +// the specified output device. The string will remain valid as +// long as there are any sequencer devices in existence. +// + +const char* Sequencer_alsa::getOutputName(int aDevice) { + if (initialized == 0) { + buildInfoDatabase(); + } + return midioutname[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa::is_open -- returns true if the +// sequencer device is open, false otherwise. +// + +int Sequencer_alsa::is_open(int mode, int index) { + if (mode == 0) { + // midi output + if (rawmidi_out[index] != NULL) { + return 1; + } else { + return 0; + } + } else { + if (rawmidi_in[index] != NULL) { + return 1; + } else { + return 0; + } + } +} + + +int Sequencer_alsa::is_open_in(int index) { + return is_open(1, index); +} + + +int Sequencer_alsa::is_open_out(int index) { + return is_open(0, index); +} + + + +///////////////////////////// +// +// Sequencer_alsa::open -- returns true if the device +// was successfully opended (or already opened) +// + +int Sequencer_alsa::open(int direction, int index) { + if (direction == 0) { + return openOutput(index); + } else { + return openInput(index); + } +} + + +int Sequencer_alsa::openInput(int index) { + if (rawmidi_in[index] != NULL) { + return 1; + } + int status; + char devname[128] = {0}; + sprintf(devname, "hw:%d,%d", midiincard[index], midiindevice[index]); + status = snd_rawmidi_open(&rawmidi_in[index], NULL, devname, 0); + if (status == 0) { + return 1; + } else { + return 0; + } +} + + +int Sequencer_alsa::openOutput(int index) { + if (rawmidi_out[index] != NULL) { + return 1; + } + int status; + char devname[128] = {0}; + sprintf(devname, "hw:%d,%d", midioutcard[index], midioutdevice[index]); + status = snd_rawmidi_open(NULL, &rawmidi_out[index], devname, 0); + if (status == 0) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// Sequencer_alsa::read -- reads MIDI bytes and also stores the +// device from which the byte was read from. Timing is not +// saved from the device. If needed, then it would have to +// be saved in this function, or just return the raw packet +// data (use rawread function). +// + +void Sequencer_alsa::read(int dev, uchar* buf, int count) { + if (is_open_in(dev)) { + snd_rawmidi_read(rawmidi_in[dev], buf, count); + } else { + std::cout << "Warning: MIDI input " << dev << " is not open for reading" + << std::endl; + } +} + + + +////////////////////////////// +// +// Sequencer_alsa::rebuildInfoDatabase -- rebuild the internal +// database that keeps track of the MIDI input and output devices. +// + +void Sequencer_alsa::rebuildInfoDatabase(void) { + removeInfoDatabase(); + buildInfoDatabase(); +} + + + +/////////////////////////////// +// +// Sequencer_alsa::write -- Send a byte out the specified MIDI +// port which can be either an internal or an external synthesizer. +// + +int Sequencer_alsa::write(int aDevice, int aByte) { + uchar byte[1]; + byte[0] = (uchar)aByte; + return write(aDevice, byte, 1); +} + + +int Sequencer_alsa::write(int aDevice, uchar* bytes, int count) { + if (is_open_out(aDevice)) { + int status = snd_rawmidi_write(rawmidi_out[aDevice], bytes, count); + return status == count ? 1 : 0; + } else { + std::cout << "Warning: MIDI output " << aDevice << " is not open for writing" + << std::endl; + return 0; + } + + return 0; +} + + +int Sequencer_alsa::write(int aDevice, char* bytes, int count) { + return write(aDevice, (uchar*)bytes, count); +} + + +int Sequencer_alsa::write(int aDevice, int* bytes, int count) { + uchar *newBytes; + newBytes = new uchar[count]; + for (int i=0; i<count; i++) { + newBytes[i] = (uchar)bytes[i]; + } + int status = write(aDevice, newBytes, count); + delete [] newBytes; + return status; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + +////////////////////////////// +// +// Sequencer_alsa::buildInfoDatabase -- determines the number +// of MIDI input and output devices available from +// /dev/snd/midiC%dD%d, and determines their names. +// + +void Sequencer_alsa::buildInfoDatabase(void) { + if (initialized) { + return; + } + + initialized = 1; + + if (indevcount != 0 || outdevcount != 0) { + std::cout << "Error: Sequencer_alsa is already running" << std::endl; + std::cout << "Indevcout = " << indevcount << " and " + << " outdevcount = " << outdevcount << std::endl; + exit(1); + } + + indevcount = 0; + outdevcount = 0; + + midiincard.setSize(0); + midiincard.allowGrowth(); + midioutcard.setSize(0); + midioutcard.allowGrowth(); + + midiindevice.setSize(0); + midiindevice.allowGrowth(); + midioutdevice.setSize(0); + midioutdevice.allowGrowth(); + + midiinname.setSize(0); + midiinname.allowGrowth(); + midioutname.setSize(0); + midioutname.allowGrowth(); + + rawmidi_in.setSize(256); + rawmidi_out.setSize(256); + + // read number of MIDI inputs/output available + Collection<int> cards; + Collection<int> devices; + getPossibleMidiStreams(cards, devices); + char devname[128] = {0}; + + // check for MIDI input streams + int i; + for (i=0; i<cards.getSize(); i++) { + sprintf(devname, "hw:%d,%d", cards[i], devices[i]); + if (snd_rawmidi_open(&rawmidi_in[indevcount], NULL, devname, 0) == 0){ + midiincard.append(cards[i]); + midiindevice.append(devices[i]); + snd_rawmidi_close(rawmidi_in[indevcount]); + rawmidi_in[indevcount] = NULL; + indevcount++; + } + } + for (i=0; i<rawmidi_in.getSize(); i++) { + rawmidi_in[i] = NULL; + } + + // check for MIDI output streams + for (i=0; i<cards.getSize(); i++) { + sprintf(devname, "hw:%d,%d", cards[i], devices[i]); + if (snd_rawmidi_open(NULL, &rawmidi_out[outdevcount], devname, 0) == 0) { + midioutcard.append(cards[i]); + midioutdevice.append(devices[i]); + snd_rawmidi_close(rawmidi_out[outdevcount]); + rawmidi_out[indevcount] = NULL; + outdevcount++; + } + } + for (i=0; i<rawmidi_out.getSize(); i++) { + rawmidi_out[i] = NULL; + } + + char buffer[256] = {0}; + char* temp; + for (i=0; i<indevcount; i++) { + sprintf(buffer, "MIDI input %d: card %d, device %d", i, + midiincard[i], midiindevice[i]); + temp = new char[strlen(buffer) + 1]; + strcpy(temp, buffer); + midiinname.append(temp); + } + + for (i=0; i<outdevcount; i++) { + sprintf(buffer, "MIDI output %d: card %d, device %d", i, + midioutcard[i], midioutdevice[i]); + temp = new char[strlen(buffer) + 1]; + strcpy(temp, buffer); + midioutname.append(temp); + } + + midiincard.allowGrowth(0); + midioutcard.allowGrowth(0); + midiindevice.allowGrowth(0); + midioutdevice.allowGrowth(0); + midiinname.allowGrowth(0); + midioutname.allowGrowth(0); + rawmidi_in.allowGrowth(0); + rawmidi_out.allowGrowth(0); + +} + + + +////////////////////////////// +// +// Sequencer_alsa::getInDeviceValue -- +// + +int Sequencer_alsa::getInDeviceValue(int aDevice) const { + return midiindevice[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa::getInCardValue -- +// + +int Sequencer_alsa::getInCardValue(int aDevice) const { + return midiincard[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa::getOutDeviceValue -- +// + +int Sequencer_alsa::getOutDeviceValue(int aDevice) const { + return midioutdevice[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa::getOutCardValue -- +// + +int Sequencer_alsa::getOutCardValue(int aDevice) const { + return midioutcard[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa::removeInfoDatabase -- +// + +void Sequencer_alsa::removeInfoDatabase(void) { + if (rawmidi_in.getSize() != 0) { + close(); + } + + if (rawmidi_out.getSize() != 0) { + close(); + } + + rawmidi_in.setSize(0); + rawmidi_out.setSize(0); + midiincard.setSize(0); + midioutcard.setSize(0); + midiindevice.setSize(0); + midioutdevice.setSize(0); + + int i; + for (i=0; i<midiinname.getSize(); i++) { + if (midiinname[i] != NULL) { + delete [] midiinname[i]; + } + } + + for (i=0; i<midioutname.getSize(); i++) { + if (midioutname[i] != NULL) { + delete [] midioutname[i]; + } + } + + indevcount = 0; + outdevcount = 0; + initialized = 0; +} + + + +////////////////////////////// +// +// getPossibleMidiStreams -- read the directory /dev/snd for files +// that match the pattern midiC%dD%d, and extract the card/device +// numbers from these filenames. +// + +void Sequencer_alsa::getPossibleMidiStreams(Collection<int>& cards, + Collection<int>& devices) { + + cards.setSize(0); + devices.setSize(0); + cards.allowGrowth(1); + devices.allowGrowth(1); + + DIR* dir = opendir("/dev/snd"); + if (dir == NULL) { +// std::cout << "Error determining ALSA MIDI info: no directory called /dev/snd" +// << std::endl; +// exit(1); + } + + // read each file in the directory and store information if it is a MIDI dev + else { + int card; + int device; + struct dirent *dinfo; + dinfo = readdir(dir); + int count; + while (dinfo != NULL) { + if (strncmp(dinfo->d_name, "midi", 4) == 0) { + count = sscanf(dinfo->d_name, "midiC%dD%d", &card, &device); + if (count == 2) { + cards.append(card); + devices.append(device); + } + } + dinfo = readdir(dir); + } + + closedir(dir); + cards.allowGrowth(0); + devices.allowGrowth(0); + } +} + + +#endif /* LINUX and ALSA */ + +// md5sum: 8ccf0e750be06aeea90cdc8a7cc4499c - Sequencer_alsa.cpp =css= 20030102 diff --git a/src/midiio/src/Sequencer_alsa05.cpp b/src/midiio/src/Sequencer_alsa05.cpp new file mode 100644 index 0000000..ad4ef2d --- /dev/null +++ b/src/midiio/src/Sequencer_alsa05.cpp @@ -0,0 +1,518 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Thu May 11 21:10:02 PDT 2000 +// Last Modified: Wed Oct 3 22:18:27 PDT 2001 (frozen to ALSA 0.5) +// Filename: ...sig/maint/code/control/Sequencer_alsa05.cpp +// Web Address: http://sig.sapp.org/src/sig/Sequencer_alsa05.cpp +// Syntax: C++ +// +// Description: Basic MIDI input/output functionality for the +// Linux ALSA raw midi devices. This class +// is inherited by the classes MidiInPort_alsa05 and +// MidiOutPort_alsa05. +// + +#if defined(LINUX) && defined(ALSA05) + +#include "Collection.h" +#include <sys/asoundlib.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <string.h> +#include <iostream.h> +#include <stdio.h> +#include "Sequencer_alsa05.h" + +typedef unsigned char uchar; + +// define static variables: +int Sequencer_alsa05::class_count = 0; +int Sequencer_alsa05::initialized = 0; + +// static variables for MIDI I/O information database +int Sequencer_alsa05::indevcount = 0; +int Sequencer_alsa05::outdevcount = 0; + +Collection<snd_rawmidi_t*> Sequencer_alsa05::rawmidi_in; +Collection<snd_rawmidi_t*> Sequencer_alsa05::rawmidi_out; +Collection<int> Sequencer_alsa05::midiincard; +Collection<int> Sequencer_alsa05::midioutcard; +Collection<int> Sequencer_alsa05::midiindevice; +Collection<int> Sequencer_alsa05::midioutdevice; +Collection<char*> Sequencer_alsa05::midiinname; +Collection<char*> Sequencer_alsa05::midioutname; + + + +/////////////////////////////// +// +// Sequencer_alsa05::Sequencer_alsa05 -- +// default value: autoOpen = 1; +// + +Sequencer_alsa05::Sequencer_alsa05(int autoOpen) { + if (class_count < 0) { + cerr << "Unusual class instatiation count: " << class_count << endl; + exit(1); + } else if (class_count == 0) { + buildInfoDatabase(); + } + + if (autoOpen) { + open(); + } + + class_count++; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::~Sequencer_alsa05 -- +// + +Sequencer_alsa05::~Sequencer_alsa05() { + + if (class_count == 1) { + close(); + removeInfoDatabase(); + } else if (class_count <= 0) { + cerr << "Unusual class instatiation count: " << class_count << endl; + exit(1); + } + + class_count--; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::close -- close the sequencer device. The device +// automatically closes once the program ends. +// + +void Sequencer_alsa05::close(void) { + int i; + + for (i=0; i<getNumInputs(); i++) { + if (rawmidi_in[i] != NULL) { + snd_rawmidi_close(rawmidi_in[i]); + rawmidi_in[i] = NULL; + } + } + + for (i=0; i<getNumOutputs(); i++) { + if (rawmidi_out[i] != NULL) { + snd_rawmidi_close(rawmidi_out[i]); + rawmidi_out[i] = NULL; + } + } + +} + + + +////////////////////////////// +// +// Sequencer_alsa05::displayInputs -- display a list of the +// available MIDI input devices. +// default values: out = cout, initial = "\t" +// + +void Sequencer_alsa05::displayInputs(ostream& out, char* initial) { + for (int i=0; i<getNumInputs(); i++) { + out << initial << i << ": " << getInputName(i) << '\n'; + } +} + + + +////////////////////////////// +// +// Sequencer_alsa05::displayOutputs -- display a list of the +// available MIDI output devices. +// default values: out = cout, initial = "\t" +// + +void Sequencer_alsa05::displayOutputs(ostream& out, char* initial) { + for (int i=0; i<getNumOutputs(); i++) { + out << initial << i << ": " << getOutputName(i) << '\n'; + } +} + + + +////////////////////////////// +// +// Sequencer_alsa05::getInputName -- returns a string to the name of +// the specified input device. The string will remain valid as +// long as there are any sequencer devices in existence. +// + +const char* Sequencer_alsa05::getInputName(int aDevice) { + if (initialized == 0) { + buildInfoDatabase(); + } + return midiinname[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::getNumInputs -- returns the total number of +// MIDI inputs that can be used. +// + +int Sequencer_alsa05::getNumInputs(void) { + if (initialized == 0) { + buildInfoDatabase(); + } + return indevcount; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::getNumOutputs -- returns the total number of +// MIDI inputs that can be used. +// + +int Sequencer_alsa05::getNumOutputs(void) { + if (initialized == 0) { + buildInfoDatabase(); + } + return outdevcount; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::getOutputName -- returns a string to the name of +// the specified output device. The string will remain valid as +// long as there are any sequencer devices in existence. +// + +const char* Sequencer_alsa05::getOutputName(int aDevice) { + if (initialized == 0) { + buildInfoDatabase(); + } + return midioutname[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::is_open -- returns true if the +// sequencer device is open, false otherwise. +// + +int Sequencer_alsa05::is_open(int mode, int index) { + if (mode == 0) { + // midi output + if (rawmidi_out[index] != NULL) { + return 1; + } else { + return 0; + } + } else { + if (rawmidi_in[index] != NULL) { + return 1; + } else { + return 0; + } + } +} + + +int Sequencer_alsa05::is_open_in(int index) { + return is_open(1, index); +} + + +int Sequencer_alsa05::is_open_out(int index) { + return is_open(0, index); +} + + + +///////////////////////////// +// +// Sequencer_alsa05::open -- returns true if the device +// was successfully opended (or already opened) +// + +int Sequencer_alsa05::open(void) { + if (rawmidi_out.getSize() != 0 || rawmidi_in.getSize() != 0) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// Sequencer_alsa05::read -- reads MIDI bytes and also stores the +// device from which the byte was read from. Timing is not +// saved from the device. If needed, then it would have to +// be saved in this function, or just return the raw packet +// data (use rawread function). +// + +void Sequencer_alsa05::read(int dev, uchar* buf, int count) { + snd_rawmidi_read(rawmidi_in[dev], buf, count); +} + + + +////////////////////////////// +// +// Sequencer_alsa05::rebuildInfoDatabase -- rebuild the internal +// database that keeps track of the MIDI input and output devices. +// + +void Sequencer_alsa05::rebuildInfoDatabase(void) { + removeInfoDatabase(); + buildInfoDatabase(); +} + + + +/////////////////////////////// +// +// Sequencer_alsa05::write -- Send a byte out the specified MIDI +// port which can be either an internal or an external synthesizer. +// + +int Sequencer_alsa05::write(int aDevice, int aByte) { + uchar byte[1]; + byte[0] = (uchar)aByte; + return write(aDevice, byte, 1); +} + + +int Sequencer_alsa05::write(int aDevice, uchar* bytes, int count) { + int status = snd_rawmidi_write(rawmidi_out[aDevice], bytes, count); + return status == count ? 1 : 0; +} + + +int Sequencer_alsa05::write(int aDevice, char* bytes, int count) { + return write(aDevice, (uchar*)bytes, count); +} + + +int Sequencer_alsa05::write(int aDevice, int* bytes, int count) { + uchar *newBytes; + newBytes = new uchar[count]; + for (int i=0; i<count; i++) { + newBytes[i] = (uchar)bytes[i]; + } + int status = write(aDevice, newBytes, count); + delete [] newBytes; + return status; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + +////////////////////////////// +// +// Sequencer_alsa05::buildInfoDatabase -- determines the number +// of MIDI input and output devices available from +// /dev/snd/midiXX, and determines their names. +// + +void Sequencer_alsa05::buildInfoDatabase(void) { + if (initialized) { + return; + } + + initialized = 1; + + if (indevcount != 0 || outdevcount != 0) { + cout << "Error: Sequencer_alsa05 is already running" << endl; + cout << "Indevcout = " << indevcount << " and " + << " outdevcount = " << outdevcount << endl; + exit(1); + } + + indevcount = 0; + outdevcount = 0; + + midiincard.setSize(0); + midiincard.allowGrowth(); + midioutcard.setSize(0); + midioutcard.allowGrowth(); + + midiindevice.setSize(0); + midiindevice.allowGrowth(); + midioutdevice.setSize(0); + midioutdevice.allowGrowth(); + + midiinname.setSize(0); + midiinname.allowGrowth(); + midioutname.setSize(0); + midioutname.allowGrowth(); + + rawmidi_in.setSize(256); + rawmidi_out.setSize(256); + + // read number of MIDI inputs/output available + int card; + int device; + + for (card=0; card<16; card++) { + for (device=0; device<16; device++) { + if (snd_rawmidi_open(&rawmidi_in[indevcount], card, device, + O_RDONLY | O_APPEND | O_NONBLOCK) == 0){ + midiincard.append(card); + midiindevice.append(device); + indevcount++; + } + } + } + rawmidi_in.setSize(indevcount); + + for (card=0; card<16; card++) { + for (device=0; device<16; device++) { + if (snd_rawmidi_open(&rawmidi_out[outdevcount], card, + device, O_WRONLY | O_APPEND | O_NONBLOCK) == 0) { + midioutcard.append(card); + midioutdevice.append(device); + outdevcount++; + } + } + } + rawmidi_out.setSize(indevcount); + + int i; + char buffer[256] = {0}; + char* temp; + for (i=0; i<indevcount; i++) { + sprintf(buffer, "MIDI input %d", i); + temp = new char[strlen(buffer) + 1]; + strcpy(temp, buffer); + midiinname.append(temp); + } + + for (i=0; i<outdevcount; i++) { + sprintf(buffer, "MIDI output %d", i); + temp = new char[strlen(buffer) + 1]; + strcpy(temp, buffer); + midioutname.append(temp); + } + + midiincard.allowGrowth(0); + midioutcard.allowGrowth(0); + midiindevice.allowGrowth(0); + midioutdevice.allowGrowth(0); + midiinname.allowGrowth(0); + midioutname.allowGrowth(0); + rawmidi_in.allowGrowth(0); + rawmidi_out.allowGrowth(0); + +} + + + +////////////////////////////// +// +// Sequencer_alsa05::getInDeviceValue -- +// + +int Sequencer_alsa05::getInDeviceValue(int aDevice) const { + return midiindevice[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::getInCardValue -- +// + +int Sequencer_alsa05::getInCardValue(int aDevice) const { + return midiincard[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::getOutDeviceValue -- +// + +int Sequencer_alsa05::getOutDeviceValue(int aDevice) const { + return midioutdevice[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::getOutCardValue -- +// + +int Sequencer_alsa05::getOutCardValue(int aDevice) const { + return midioutcard[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::removeInfoDatabase -- +// + +void Sequencer_alsa05::removeInfoDatabase(void) { + if (rawmidi_in.getSize() != 0) { + close(); + } + + if (rawmidi_out.getSize() != 0) { + close(); + } + + rawmidi_in.setSize(0); + rawmidi_out.setSize(0); + midiincard.setSize(0); + midioutcard.setSize(0); + midiindevice.setSize(0); + midioutdevice.setSize(0); + + int i; + for (i=0; i<midiinname.getSize(); i++) { + if (midiinname[i] != NULL) { + delete [] midiinname[i]; + } + } + + for (i=0; i<midioutname.getSize(); i++) { + if (midioutname[i] != NULL) { + delete [] midioutname[i]; + } + } + + indevcount = 0; + outdevcount = 0; + initialized = 0; +} + + +#endif /* LINUX and ALSA05 */ + + +// md5sum: b47021f0b71b2bc1555755584777c9a8 - Sequencer_alsa05.cpp =css= 20030102 diff --git a/src/midiio/src/Sequencer_oss.cpp b/src/midiio/src/Sequencer_oss.cpp new file mode 100644 index 0000000..db9258e --- /dev/null +++ b/src/midiio/src/Sequencer_oss.cpp @@ -0,0 +1,809 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Jan 3 21:02:02 PST 1999 +// Last Modified: Fri Jan 8 04:50:05 PST 1999 +// Last Modified: Wed May 10 17:00:11 PDT 2000 (name change from _linux to _oss) +// Filename: ...sig/maint/code/control/MidiOutPort/Sequencer_oss.cpp +// Web Address: http://sig.sapp.org/src/sig/Sequencer_oss.cpp +// Syntax: C++ +// +// Description: Basic MIDI input/output functionality for the +// Linux OSS midi device /dev/sequencer. This class +// is inherited by the classes MidiInPort_oss and +// MidiOutPort_oss. +// + +#ifdef LINUX + +#include <stdlib.h> + + +#include <linux/soundcard.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <string.h> +#include <iostream> +#include "Sequencer_oss.h" + + +// define static variables: +const char* Sequencer_oss::sequencer = "/dev/sequencer"; +int Sequencer_oss::sequencer_fd = -1; +int Sequencer_oss::class_count = 0; +int Sequencer_oss::initialized = 0; +uchar Sequencer_oss::midi_write_packet[4] = {SEQ_MIDIPUTC, 0, 0, 0}; +uchar Sequencer_oss::midi_read_packet[4]; + + +// static variables for MIDI I/O information database +int Sequencer_oss::indevcount = 0; +int Sequencer_oss::outdevcount = 0; + +int* Sequencer_oss::indevnum = NULL; +int* Sequencer_oss::outdevnum = NULL; + +int* Sequencer_oss::indevtype = NULL; +int* Sequencer_oss::outdevtype = NULL; + +char** Sequencer_oss::indevnames = NULL; +char** Sequencer_oss::outdevnames = NULL; + + + +/////////////////////////////// +// +// Sequencer_oss::Sequencer_oss -- +// default value: autoOpen = 1; +// + +Sequencer_oss::Sequencer_oss(int autoOpen) { + if (autoOpen) { + open(); + } + + if (class_count < 0) { + std::cerr << "Unusual class instatiation count: " << class_count << std::endl; + exit(1); + } else if (class_count == 0) { + buildInfoDatabase(); + } + + class_count++; +} + + + +////////////////////////////// +// +// Sequencer_oss::~Sequencer_oss -- +// + +Sequencer_oss::~Sequencer_oss() { + class_count--; + + if (class_count == 0) { + close(); + removeInfoDatabase(); + } else if (class_count < 0) { + std::cerr << "Unusual class instatiation count: " << class_count << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// Sequencer_oss::close -- close the sequencer device. The device +// automatically closes once the program ends, but you can close it +// so that other programs can use it. +// + +void Sequencer_oss::close(void) { + ::close(getFd()); +} + + + +////////////////////////////// +// +// Sequencer_oss::displayInputs -- display a list of the +// available MIDI input devices. +// default values: out = cout, initial = "\t" +// + +void Sequencer_oss::displayInputs(std::ostream& out, char* initial) { + for (int i=0; i<getNumInputs(); i++) { + out << initial << i << ": " << getInputName(i) << '\n'; + } +} + + + +////////////////////////////// +// +// Sequencer_oss::displayOutputs -- display a list of the +// available MIDI output devices. +// default values: out = cout, initial = "\t" +// + +void Sequencer_oss::displayOutputs(std::ostream& out, char* initial) { + for (int i=0; i<getNumOutputs(); i++) { + out << initial << i << ": " << getOutputName(i) << '\n'; + } +} + + + +////////////////////////////// +// +// Sequencer_oss::getInputName -- returns a string to the name of +// the specified input device. The string will remain valid as +// long as there are any sequencer devices in existence. +// + +const char* Sequencer_oss::getInputName(int aDevice) { + if (initialized == 0) { + buildInfoDatabase(); + } + if (aDevice >= getNumInputs()) { + std::cerr << "Error: " << aDevice << " is greater than max in (" + << getNumInputs() << ")" << std::endl; + exit(1); + } + + return indevnames[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::getNumInputs -- returns the total number of +// MIDI inputs that can be used. +// + +int Sequencer_oss::getNumInputs(void) { + if (initialized == 0) { + buildInfoDatabase(); + } + return indevcount; +} + + + +////////////////////////////// +// +// Sequencer_oss::getNumOutputs -- returns the total number of +// MIDI inputs that can be used. +// + +int Sequencer_oss::getNumOutputs(void) { + if (initialized == 0) { + buildInfoDatabase(); + } + return outdevcount; +} + + + +////////////////////////////// +// +// Sequencer_oss::getOutputName -- returns a string to the name of +// the specified output device. The string will remain valid as +// long as there are any sequencer devices in existence. +// + +const char* Sequencer_oss::getOutputName(int aDevice) { + if (initialized == 0) { + buildInfoDatabase(); + } + if (aDevice >= getNumOutputs()) { + std::cerr << "Error: " << aDevice << " is greater than max out (" + << getNumOutputs() << ")" << std::endl; + exit(1); + } + + return outdevnames[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::is_open -- returns true if the +// sequencer device is open, false otherwise. +// + +int Sequencer_oss::is_open(void) { + if (getFd() > 0) { + return 1; + } else { + return 0; + } +} + + + +///////////////////////////// +// +// Sequencer_oss::open -- returns true if the device +// was successfully opended (or already opened) +// + +int Sequencer_oss::open(void) { + if (getFd() <= 0) { + setFd(::open(sequencer, O_RDWR, 0)); + } + + return is_open(); +} + + + +////////////////////////////// +// +// Sequencer_oss::read -- reads MIDI bytes and also stores the +// device from which the byte was read from. Timing is not +// saved from the device. If needed, then it would have to +// be saved in this function, or just return the raw packet +// data (use rawread function). +// + +void Sequencer_oss::read(uchar* buf, uchar* dev, int count) { + int i = 0; + while (i < count) { + ::read(getFd(), midi_read_packet, sizeof(midi_read_packet)); + if (midi_read_packet[1] == SEQ_MIDIPUTC) { + buf[i] = midi_read_packet[1]; + dev[i] = midi_read_packet[2]; + i++; + } + } +} + + + +////////////////////////////// +// +// Sequencer_oss::rawread -- read Input MIDI packets. +// each packet contains 4 bytes. +// + +void Sequencer_oss::rawread(uchar* buf, int packetCount) { + ::read(getFd(), buf, packetCount * 4); +} + + + +////////////////////////////// +// +// Sequencer_oss::rebuildInfoDatabase -- rebuild the internal +// database that keeps track of the MIDI input and output devices. +// + +void Sequencer_oss::rebuildInfoDatabase(void) { + removeInfoDatabase(); + buildInfoDatabase(); +} + + + +/////////////////////////////// +// +// Sequencer_oss::write -- Send a byte out the specified MIDI +// port which can be either an internal or an external synthesizer. +// + +int Sequencer_oss::write(int device, int aByte) { + int status = 0; + + switch (getOutputType(device)) { + case MIDI_EXTERNAL: + midi_write_packet[1] = (uchar) (0xff & aByte); + midi_write_packet[2] = getOutDeviceValue(device); + status = ::write(getFd(), midi_write_packet,sizeof(midi_write_packet)); + break; + case MIDI_INTERNAL: + status = writeInternal(getOutDeviceValue(device), aByte); + break; + } + + if (status > 0) { + return 1; + } else { + return 0; + } + +} + + +int Sequencer_oss::write(int device, uchar* bytes, int count) { + int status = 1; + for (int i=0; i<count; i++) { + status &= write(device, bytes[i]); + } + return status; +} + + +int Sequencer_oss::write(int device, char* bytes, int count) { + return write(device, (uchar*)bytes, count); +} + + +int Sequencer_oss::write(int device, int* bytes, int count) { + int status = 1; + for (int i=0; i<count; i++) { + status &= write(device, bytes[i]); + } + return status; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + +////////////////////////////// +// +// Sequencer_oss::buildInfoDatabase -- determines the number +// of MIDI input and output devices available from +// /dev/sequencer, and determines their names. +// + +void Sequencer_oss::buildInfoDatabase(void) { + int status; + initialized = 1; + + int startup = sequencer_fd == -1 ? 0 : 1; + if (startup == 0) { + // setup the file descriptor for /dev/sequencer + sequencer_fd = ::open(sequencer, O_RDWR); + if (sequencer_fd < 0) { +// std::cout << "Error: cannot open " << sequencer << std::endl; +// exit(1); + } + else { + // read number of inputs available (external MIDI devices only) + status = ioctl(getFd(), SNDCTL_SEQ_NRMIDIS, &indevcount); + if (status!= 0) { + std::cerr << "Error determining the number of MIDI inputs" << std::endl; + exit(1); + } + + // read number of output available + int extmidi = indevcount; + int intmidi; + status = ioctl(getFd(), SNDCTL_SEQ_NRSYNTHS, &intmidi); + if (status!= 0) { + std::cerr << "Error determining the number of MIDI inputs" << std::endl; + exit(1); + } + outdevcount = extmidi + intmidi; + + // allocate space for names and device number arrays + if (indevnum != NULL || outdevnum != NULL || indevnames != NULL || + outdevnames != NULL || indevtype != NULL || outdevtype != NULL) { + std::cerr << "Error: buildInfoDatabase called twice." << std::endl; + exit(1); + } + + indevnum = new int[indevcount]; + outdevnum = new int[outdevcount]; + + indevtype = new int[indevcount]; + outdevtype = new int[outdevcount]; + + indevnames = new char*[indevcount]; + outdevnames = new char*[outdevcount]; + + + // fill in the device translation table and fill in the device names + int i; + struct midi_info midiinfo; + for (i=0; i<indevcount; i++) { + midiinfo.device = i; + status = ioctl(getFd(), SNDCTL_MIDI_INFO, &midiinfo); + if (status != 0) { + std::cerr << "Error while reading MIDI device " << i << std::endl; + exit(1); + } + + indevnum[i] = midiinfo.device; + outdevnum[i] = midiinfo.device; + indevtype[i] = MIDI_EXTERNAL; + outdevtype[i] = MIDI_EXTERNAL; + indevnames[i] = new char[strlen(midiinfo.name) + 1 + 10]; + outdevnames[i] = new char[strlen(midiinfo.name) + 1 + 11]; + strcpy(indevnames[i], midiinfo.name); + strcpy(outdevnames[i], midiinfo.name); + strcat(indevnames[i], " (MIDI In)"); + strcat(outdevnames[i], " (MIDI Out)"); + } + + char tempstring[1024] = {0}; + struct synth_info synthinfo; + for (i=0; i<intmidi; i++) { + synthinfo.device = i; + status = ioctl(getFd(), SNDCTL_SYNTH_INFO, &synthinfo); + if (status != 0) { + std::cerr << "Error while reading MIDI device " << i << std::endl; + exit(1); + } + outdevnum[extmidi+i] = i; + outdevtype[extmidi + i] = MIDI_INTERNAL; + + strcpy(tempstring, synthinfo.name); + switch (synthinfo.synth_type) { + case SYNTH_TYPE_FM: // 0 + strcat(tempstring, " (FM"); + switch (synthinfo.synth_subtype) { + case FM_TYPE_ADLIB: // 0 + strcat(tempstring, " Adlib"); + break; + case FM_TYPE_OPL3: // 1 + strcat(tempstring, " OPL3"); + break; + } + strcat(tempstring, ")"); + break; + case SYNTH_TYPE_SAMPLE: // 1 + strcat(tempstring, " (Wavetable)"); + break; + case SYNTH_TYPE_MIDI: // 2 + strcat(tempstring, " (MIDI Interface"); + switch (synthinfo.synth_subtype) { + case SYNTH_TYPE_MIDI: // 0x401 + strcat(tempstring, " MPU401"); + break; + } + strcat(tempstring, ")"); + break; + } + outdevnames[i+extmidi] = new char[strlen(tempstring) + 1]; + strcpy(outdevnames[i+extmidi], tempstring); + } + + + if (startup == 0) { + ::close(sequencer_fd); + } + } + } +} + + +////////////////////////////// +// +// Sequencer_oss::getFd -- returns the file descriptor of the +// sequencer device. +// + +int Sequencer_oss::getFd(void) { + return sequencer_fd; +} + + + +////////////////////////////// +// +// Sequencer_oss::getInDeviceValue -- +// + +int Sequencer_oss::getInDeviceValue(int aDevice) const { + if (aDevice >= getNumInputs()) { + std::cerr << "Error: " << aDevice << " is greater than max in (" + << getNumInputs() << ")" << std::endl; + exit(1); + } + + return indevnum[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::getInputType -- returns 1 = external MIDI, +// 2 = internal MIDI +// + +int Sequencer_oss::getInputType(int aDevice) const { + if (aDevice >= getNumInputs()) { + std::cerr << "Error: " << aDevice << " is greater than max in (" + << getNumInputs() << ")" << std::endl; + exit(1); + } + + return indevtype[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::getOutDeviceValue -- +// + +int Sequencer_oss::getOutDeviceValue(int aDevice) const { + if (aDevice >= getNumOutputs()) { + std::cerr << "Error: " << aDevice << " is greater than max out (" + << getNumOutputs() << ")" << std::endl; + exit(1); + } + + return outdevnum[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::getOutputType -- returns 1 = external MIDI, +// 2 = internal MIDI +// + +int Sequencer_oss::getOutputType(int aDevice) const { + if (aDevice >= getNumOutputs()) { + std::cerr << "Error: " << aDevice << " is greater than max out (" + << getNumOutputs() << ")" << std::endl; + exit(1); + } + + return outdevtype[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::removeInfoDatabase -- +// + +void Sequencer_oss::removeInfoDatabase(void) { + initialized = 0; + + if (indevnum != NULL) delete [] indevnum; + if (outdevnum != NULL) delete [] outdevnum; + if (indevtype != NULL) delete [] indevtype; + if (outdevtype != NULL) delete [] outdevtype; + + int i; + if (indevnames != NULL) { + for (i=0; i<indevcount; i++) { + if (indevnames[i] != NULL) delete [] indevnames[i]; + } + delete [] indevnames; + } + + if (outdevnames != NULL) { + for (i=0; i<outdevcount; i++) { + if (outdevnames[i] != NULL) delete [] outdevnames[i]; + } + delete [] outdevnames; + } + + indevnum = NULL; + outdevnum = NULL; + indevtype = NULL; + outdevtype = NULL; + indevnames = NULL; + outdevnames = NULL; + + indevcount = 0; + outdevcount = 0; +} + + + +////////////////////////////// +// +// Sequencer_oss::setFd -- +// + +void Sequencer_oss::setFd(int anFd) { + sequencer_fd = anFd; +} + + + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions dealing with the stupid internal sythesizer messages +// which have to be processed as complete messages as opposed to +// external MIDI devices which are processed on the driver level as +// discrete bytes. +// + +// static variables related to the processing of message for internal MIDI: +uchar Sequencer_oss::synth_write_message[8]; +uchar Sequencer_oss::synth_message_buffer[1024] = {0}; +int Sequencer_oss::synth_message_buffer_count = 0; +int Sequencer_oss::synth_message_bytes_expected = 0; +int Sequencer_oss::synth_message_curr_device = -1; + + +////////////////////////////// +// +// Sequencer_oss::writeInternal -- the device number is the +// driver's device number *NOT* this class's device numbering +// system. MIDI bytes are stored in a buffer until a complete +// message is received, then a synth message is generated. +// While a complete message is being received, the device number +// cannot change. The first byte of a message must be a MIDI +// command (i.e., no running status). +// + +int Sequencer_oss::writeInternal(int aDevice, int aByte) { + int status = 0; + + if (synth_message_bytes_expected == 0) { + // a new message is coming in. + synth_message_curr_device = aDevice; + if (aByte < 128) { + std::cerr << "Error: MIDI output byte: " << aByte + << " is not a command byte." << std::endl; + exit(1); + } else { + synth_message_buffer[0] = aByte; + synth_message_buffer_count = 1; + } + + switch (aByte & 0xf0) { + case 0x80: synth_message_bytes_expected = 3; break; + case 0x90: synth_message_bytes_expected = 3; break; + case 0xA0: synth_message_bytes_expected = 3; break; + case 0xB0: synth_message_bytes_expected = 3; break; + case 0xC0: synth_message_bytes_expected = 2; break; + case 0xD0: synth_message_bytes_expected = 2; break; + case 0xE0: synth_message_bytes_expected = 3; break; + case 0xF0: std::cerr << "Can't handle 0xE0 yet" << std::endl; exit(1); + default: std::cerr << "Unknown error" << std::endl; exit(1); + } + } + + // otherwise expecting at least one more byte for the MIDI message + else { + if (synth_message_curr_device != aDevice) { + std::cerr << "Error: device number changed during message" << std::endl; + exit(1); + } + if (aByte > 127) { + std::cerr << "Error: expecting MIDI data but got MIDI command: " + << aByte << std::endl; + exit(1); + } + + synth_message_buffer[synth_message_buffer_count++] = aByte; + } + + // check to see if the message is complete: + if (synth_message_bytes_expected == synth_message_buffer_count) { + status = transmitMessageToInternalSynth(); + synth_message_bytes_expected = 0; + synth_message_buffer_count = 0; + } + + return status; +} + + + +////////////////////////////// +// +// Sequencer_oss::transmitMessageToInternalSynth -- send the stored +// MIDI message to the internal synthesizer. +// + +int Sequencer_oss::transmitMessageToInternalSynth(void) { + int status; + switch (synth_message_buffer[0] & 0xf0) { + case 0x80: // Note-off + case 0x90: // Note-on + case 0xA0: // Aftertouch + status = transmitVoiceMessage(); + break; + case 0xB0: // Control change + case 0xC0: // Patch change + case 0xD0: // Channel pressure + case 0xE0: // Pitch wheel + status = transmitCommonMessage(); + break; + case 0xF0: + std::cerr << "Cannot handle 0xf0 commands yet" << std::endl; + exit(1); + break; + default: + std::cerr << "Error: unknown MIDI command" << std::endl; + exit(1); + } + + return status; +} + + + +////////////////////////////// +// +// Sequencer_oss::transmitVoiceMessage -- send a voice-type MIDI +// message to an internal synthesizer. +// + +int Sequencer_oss::transmitVoiceMessage(void) { + synth_write_message[0] = EV_CHN_VOICE; + synth_write_message[1] = synth_message_curr_device; + synth_write_message[2] = synth_message_buffer[0] & 0xf0; + synth_write_message[3] = synth_message_buffer[0] & 0x0f; + synth_write_message[4] = synth_message_buffer[1]; + synth_write_message[5] = synth_message_buffer[2]; + synth_write_message[6] = 0; + synth_write_message[7] = 0; + + int status; + status = ::write(getFd(), synth_write_message, sizeof(synth_write_message)); + + if (status > 0) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// Sequencer_oss::transmitCommonMessage -- send a common-type MIDI +// message to an internal synthesizer. +// + +int Sequencer_oss::transmitCommonMessage(void) { + synth_write_message[0] = EV_CHN_COMMON; + synth_write_message[1] = synth_message_curr_device; + synth_write_message[2] = synth_message_buffer[0] & 0xf0; + synth_write_message[3] = synth_message_buffer[0] & 0x0f; + + switch (synth_write_message[2]) { + case 0xB0: // Control change + synth_write_message[4] = synth_message_buffer[1]; + synth_write_message[5] = 0; + synth_write_message[6] = synth_message_buffer[2]; + synth_write_message[7] = 0; + break; + case 0xC0: // Patch change + case 0xD0: // Channel pressure + synth_write_message[4] = synth_message_buffer[1]; + synth_write_message[5] = 0; + synth_write_message[6] = 0; + synth_write_message[7] = 0; + break; + case 0xE0: // Pitch wheel + synth_write_message[4] = 0; + synth_write_message[5] = 0; + synth_write_message[6] = synth_message_buffer[1]; + synth_write_message[7] = synth_message_buffer[2]; + break; + default: + std::cerr << "Unknown Common MIDI message" << std::endl; + exit(1); + } + + int status; + status = ::write(getFd(), synth_write_message, sizeof(synth_write_message)); + + if (status > 0) { + return 1; + } else { + return 0; + } +} + + + +#endif // LINUX +// md5sum: bc7b96041137b22f3d3c35376b5912c6 - Sequencer_oss.cpp =css= 20030102 diff --git a/src/midiio/src/SigTimer.cpp b/src/midiio/src/SigTimer.cpp new file mode 100644 index 0000000..5786098 --- /dev/null +++ b/src/midiio/src/SigTimer.cpp @@ -0,0 +1,498 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Thanks to: Erik Neuenschwander <erikn@leland.stanford.edu> +// for Windows 95 assembly code for Pentium clock cycles. +// Ozgur Izmirli <ozgur@ccrma.stanford.edu> +// for concept of periodic timer. +// Creation Date: Mon Oct 13 11:34:57 GMT-0800 1997 +// Last Modified: Tue Feb 10 21:05:19 GMT-0800 1998 +// Last Modified: Sat Sep 19 15:56:48 PDT 1998 +// Last Modified: Mon Feb 22 04:44:25 PST 1999 +// Last Modified: Sun Nov 28 12:39:39 PST 1999 (added adjustPeriod()) +// Filename: .../sig/code/control/SigTimer/SigTimer.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/SigTimer.cpp +// Syntax: C++ +// +// Description: This class can only be used on Motorola Pentinum 75 Mhz +// chips or better because the timing information is +// extracted from the clock cycle count from a register +// on the CPU itself. This class will estimate the +// speed of the computer, but it would be better if there +// was a way of finding out the speed from some function. +// This class is used primarily for timing of MIDI input +// and output at a millisecond resolution. +// + + +#include "SigTimer.h" +#include <iostream> +#include <stdlib.h> + + +// get Sleep or usleep function definition for measureCpu function: +#ifdef VISUAL + #define WIN32_LEAN_AND_MEAN + #include <windows.h> + #undef WIN32_LEAN_AND_MEAN +#else + #include <unistd.h> +#endif + + +// declare static variables +int64bits SigTimer::globalOffset = 0; +int SigTimer::cpuSpeed = 0; // in cycles per second + + + +////////////////////////////// +// +// SigTimer::SigTimer +// + +SigTimer::SigTimer(void) { + if (globalOffset == 0) { // coordinate offset between timers + globalOffset = clockCycles(); + } + if (cpuSpeed <= 0) { // initialize CPU speed value + cpuSpeed = measureCpuSpeed(1); + if (cpuSpeed <= 0) { + cpuSpeed = 100000000; + } + } + + offset = globalOffset; // initialize the start time of timer + ticksPerSecond = 1000; // default of 1000 ticks per second + period = 1000.0; // default period of once per second +} + + +SigTimer::SigTimer(int aSpeed) { + if (globalOffset == 0) { + globalOffset = clockCycles(); + } + cpuSpeed = aSpeed; + + offset = globalOffset; + ticksPerSecond = 1000; + period = 1000.0; // default period of once per second +} + + +SigTimer::SigTimer(SigTimer& aTimer) { + offset = aTimer.offset; + ticksPerSecond = aTimer.ticksPerSecond; + period = aTimer.period; +} + + + +////////////////////////////// +// +// SigTimer::~SigTimer +// + +SigTimer::~SigTimer() { + // do nothing +} + + + +////////////////////////////// +// +// SigTimer::adjustPeriod -- adjust the period of the timer. +// + +void SigTimer::adjustPeriod(double periodDelta) { + offset -= (int64bits)(getCpuSpeed() * getPeriod() * periodDelta / + getTicksPerSecond()); +} + + + +////////////////////////////// +// +// SigTimer::clockCycles -- returns the number of clock cycles since last reboot +// HARDWARE DEPENDENT -- currently for Pentiums only. +// static function. +// + + +int64bits SigTimer::clockCycles() { +#ifndef VISUAL + int64bits output; + + // For Pentiums, you can get the number of clock cycles elapsed + // since the last reboot with the following assembler code: + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (output)); + +#else + int64bits output; + unsigned long high_end, low_end; + __asm { + __asm _emit 0x0f __asm _emit 0x31 + mov high_end, edx + mov low_end, eax + } + output = high_end; + output = output << 32; + output += low_end; +#endif + + return output; +} + + + +////////////////////////////// +// +// SigTimer::expired -- returns the integral number of periods +// That have passed since the last update or reset. +// See getPeriodCount which returns a floating point +// count of the period position. +// + + +int SigTimer::expired(void) const { + return (int)(getTime()/period); +} + + + +////////////////////////////// +// +// SigTimer::getCpuSpeed -- returns the CPU speed of the computer. +// (static function) +// + +int SigTimer::getCpuSpeed(void) { + return cpuSpeed; +} + + + +////////////////////////////// +// +// SigTimer::getPeriod -- returns the timing period of the timer, +// if the timer is being used as a periodic timer. +// + +double SigTimer::getPeriod(void) const { + return period; +} + + + +////////////////////////////// +// +// SigTimer::getPeriodCount -- returns the current period count +// of the timer as a double. Similar in behavior to expired +// function but lists the current fraction of a period. +// + +double SigTimer::getPeriodCount(void) const { + return (double)getTime()/period; +} + + + +////////////////////////////// +// +// SigTimer::getTempo -- returns the current tempo in terms +// of beats (ticks) per minute. +// + +double SigTimer::getTempo(void) const { + return getTicksPerSecond() * 60.0 / getPeriod(); +} + + + +////////////////////////////// +// +// SigTimer::getTicksPerSecond -- return the number of ticks per +// second. +// + +int SigTimer::getTicksPerSecond(void) const { + return ticksPerSecond; +} + + + +////////////////////////////// +// +// SigTimer::getTime -- returns time in milliseconds by default. +// time can be altered to be in some other unit of time +// by using the setTicksPerSecond function. +// (Default is 1000 ticks per second.) +// + +int SigTimer::getTime(void) const { + return (int)((clockCycles()-offset)/getFactor()); +} + + + +////////////////////////////// +// +// SigTimer::getTimeInSeconds +// + +double SigTimer::getTimeInSeconds(void) const { + return ((clockCycles()-offset)/(double)cpuSpeed); +} + + + +////////////////////////////// +// +// SigTimer::getTimeInTicks +// + +int SigTimer::getTimeInTicks(void) const { + return (int)((clockCycles()-offset)/getFactor()); +} + + + +////////////////////////////// +// +// SigTimer::measureCpuSpeed -- returns the number of clock cycles in +// one second. Accuracy to about +/- 5%. +// default value: quantize = 0. +// + +int SigTimer::measureCpuSpeed(int quantize) { + int64bits a, b; + a = clockCycles(); + #ifdef VISUAL + Sleep(1000/4); + #else + usleep(1000000/4); + #endif + b = clockCycles(); + + int output = (int)(4*(b-a-140100-450000)); + + if (quantize) { + // quantize to a known computer CPU speed + if (output < 78000000) { + output = 75000000; + } else if (output < 95000000) { + output = 90000000; + } else if (output < 110000000) { + output = 100000000; + } else if (output < 140000000) { + output = 133000000; + } else if (output < 155000000) { + output = 150000000; + } else if (output < 180000000) { + output = 166000000; + } else if (output < 215000000) { + output = 200000000; + } else if (output < 250000000) { + output = 233000000; + } else if (output < 280000000) { + output = 266000000; + } else if (output < 325000000) { + output = 300000000; + } else if (output < 375000000) { + output = 350000000; + } else if (output < 425000000) { + output = 400000000; + } else { + output = output; + } + } // end if quantize + + return output; +} + + + +////////////////////////////// +// +// SigTimer::reset -- set the timer to 0. +// + +void SigTimer::reset(void) { + offset = clockCycles(); +} + + + +////////////////////////////// +// +// SigTimer::setCpuSpeed -- You can also vary the CPU speed here to cause the +// getTime function to output different units of time, but the +// setTicksPerSecond is a more appropriate place to do such a thing. +// + +void SigTimer::setCpuSpeed(int aSpeed) { + if (aSpeed <= 0) { + std::cerr << "Error: Cannot set the cpu speed to be negative: " + << aSpeed << std::endl; + exit(1); + } + cpuSpeed = aSpeed; +} + + + +////////////////////////////// +// +// SigTimer::setPeriod -- sets the period length of the timer. +// input value cannot be less than 1.0. +// + +void SigTimer::setPeriod(double aPeriod) { + if (aPeriod < 1.0) { + std::cerr << "Error: period too small: " << aPeriod << std::endl; + exit(1); + } + period = aPeriod; +} + + + +////////////////////////////// +// +// SigTimer::setPeriodCount -- adjusts the offset time according +// to the current period to match the specified period count. +// + +void SigTimer::setPeriodCount(double aCount) { + offset = (int64bits)(clockCycles() - aCount * getPeriod() * + getCpuSpeed() / getTicksPerSecond()); +} + + + +////////////////////////////// +// +// SigTimer::setTempo -- sets the period length in terms of +// beats per minute. +// + +void SigTimer::setTempo(double beatsPerMinute) { + if (beatsPerMinute < 1.0) { + std::cerr << "Error: tempo is too slow: " << beatsPerMinute << std::endl; + exit(1); + } + double count = getPeriodCount(); + period = getTicksPerSecond() * 60.0 / beatsPerMinute; + setPeriodCount(count); +} + + + +////////////////////////////// +// +// SigTimer::setTicksPerSecond +// + +void SigTimer::setTicksPerSecond(int aTickRate) { + if (aTickRate <= 0) { + std::cerr << "Error: Cannot set the tick rate to be negative: " + << aTickRate << std::endl; + exit(1); + } + ticksPerSecond = aTickRate; +} + + + +////////////////////////////// +// +// SigTimer::start +// + +void SigTimer::start(void) { + reset(); +} + + + +////////////////////////////// +// +// SigTimer::sync +// + +void SigTimer::sync(SigTimer& aTimer) { + offset = aTimer.offset; +} + + + +////////////////////////////// +// +// SigTimer::update -- set the timer start to the next period. +// + +void SigTimer::update(void) { + if (getTime() >= getPeriod()) { + offset += (int64bits)(getPeriod() * getFactor()); + } +} + + +// update(int) will do nothing if the periodCount is greater than +// than the expired period count + +void SigTimer::update(int periodCount) { + if (periodCount > expired()) { + return; + } else { + offset += (int64bits)(getPeriod() * getFactor() * periodCount); + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// protected functions: +// + + +////////////////////////////// +// +// SigTimer::getFactor -- +// + +double SigTimer::getFactor(void) const { + return (double)((double)getCpuSpeed()/(double)getTicksPerSecond()); +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Miscellaneous timing functions are located here untill a better +// place can be found: +// + +void millisleep(int milliseconds) { + #ifdef VISUAL + Sleep(milliseconds); + #else + usleep( milliseconds * 1000); + #endif +} + + +void millisleep(float milliseconds) { + #ifdef VISUAL + // cannot convert to microseconds in Visual C++ yet. + // Tell me how and I'll fix the following line + Sleep((unsigned long)milliseconds); + #else + usleep((int)(milliseconds * 1000.0)); + #endif +} + + + + +// md5sum: b35e9e6a8d6fd16636d7fca5d565f284 - SigTimer.cpp =css= 20030102 diff --git a/src/midiio/src/Voice.cpp b/src/midiio/src/Voice.cpp new file mode 100644 index 0000000..ed05bce --- /dev/null +++ b/src/midiio/src/Voice.cpp @@ -0,0 +1,334 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Oct 11 18:39:14 PDT 1998 +// Last Modified: Sun Oct 11 18:39:18 PDT 1998 +// Filename: ...sig/maint/code/control/Voice/Voice.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/Voice.cpp +// Syntax: C++ +// +// Description: The Voice class is a MIDI output class which keeps +// track of the last note played in to it. If the last +// note was not turned off when a new note is played, +// then the old note will be turned off before the +// new note is played. +// + +#include "Voice.h" + + +// declare static variables: +SigTimer Voice::timer; + +////////////////////////////// +// +// Voice::Voice +// + +Voice::Voice(int aChannel) { + chan = oldChan = aChannel; + vel = oldVel = key = oldKey = 0; +} + + +Voice::Voice(const Voice& aVoice) { + chan = aVoice.chan; + vel = aVoice.vel; + key = aVoice.key; + oldChan = 0; + oldVel = 0; + oldKey = 0; +} + + +Voice::Voice(void) { + chan = oldChan = key = oldKey = vel = oldVel = 0; +} + + +////////////////////////////// +// +// Voice::~Voice +// + +Voice::~Voice() { + off(); +} + + + +////////////////////////////// +// +// Voice::cont -- use default channel if none specified for +// the continuous controller message. +// + +void Voice::cont(int controller, int data) { + MidiOutput::cont(getChannel(), controller, data); +} + + + +////////////////////////////// +// +// Voice::getChan -- returns the channel of the voice. +// Synonym for getChannel. +// + +int Voice::getChan(void) const { + return chan; +} + + + +////////////////////////////// +// +// Voice::getChannel -- returs the channel of the voice. +// + +int Voice::getChannel(void) const { + return chan; +} + + + +////////////////////////////// +// +// Voice::getKey -- returns the current MIDI key number of the voice. +// Synonym for getKeynum. +// + +int Voice::getKey(void) const { + return key; +} + + + +////////////////////////////// +// +// Voice::getKeynum -- returns the current MIDI key number of the voice. +// + +int Voice::getKeynum(void) const { + return key; +} + + +////////////////////////////// +// +// Voice::getOffTime -- returns the last note off message sent +// out of the voice object +// + +int Voice::getOffTime(void) const { + return offTime; +} + + + +////////////////////////////// +// +// Voice::getOnTime -- returns the last note on message sent +// out of the voice object. +// + +int Voice::getOnTime(void) const { + return onTime; +} + + + +////////////////////////////// +// +// Voice::getVel -- returns the current velocity of the MIDI key. +// Synonym for getVelocity. +// + +int Voice::getVel(void) const { + return vel; +} + + + +////////////////////////////// +// +// Voice::getVelocity -- returns the current velocity of the MIDI key. +// + +int Voice::getVelocity(void) const { + return vel; +} + + + +////////////////////////////// +// +// Voice::off +// + +void Voice::off(void) { + if (status() != 0) { + offTime = timer.getTime(); + MidiOutput::play(oldChan, oldKey, 0); + oldVel = 0; + } +} + + + +////////////////////////////// +// +// Voice::pc -- use default channel if none is specified +// + +void Voice::pc(int aTimbre) { + MidiOutput::pc(getChannel(), aTimbre); +} + + + +////////////////////////////// +// +// Voice::play +// + +void Voice::play(int aChannel, int aKeyno, int aVelocity) { + off(); + MidiOutput::play(aChannel, aKeyno, aVelocity); + oldChan = aChannel; + oldKey = aKeyno; + oldVel = aVelocity; + setChannel(aChannel); + setKeynum(aKeyno); + setVelocity(aVelocity); + + if (aVelocity != 0) { + onTime = timer.getTime(); + } else { + offTime = timer.getTime(); + } +} + + +void Voice::play(int aKeyno, int aVelocity) { + off(); + MidiOutput::play(getChannel(), aKeyno, aVelocity); + oldChan = getChannel(); + oldKey = aKeyno; + oldVel = aVelocity; + setKeynum(aKeyno); + setVelocity(aVelocity); + + if (aVelocity != 0) { + onTime = timer.getTime(); + } else { + offTime = timer.getTime(); + } +} + + +void Voice::play(void) { + off(); + MidiOutput::play(getChannel(), getKey(), getVel()); + oldChan = getChannel(); + oldKey = getKey(); + oldVel = getVel(); + + if (getVel() != 0) { + onTime = timer.getTime(); + } else { + offTime = timer.getTime(); + } +} + + + +////////////////////////////// +// +// Voice::setChan -- set the MIDI channel. Synonym for setChannel. +// + +void Voice::setChan(int aChannel) { + chan = aChannel; +} + + + +////////////////////////////// +// +// Voice::setChannel -- set the MIDI channel of the voice. +// + +void Voice::setChannel(int aChannel) { + chan = aChannel; +} + + + +////////////////////////////// +// +// Voice::setKey -- set the keynumber of the voice +// Synonym for setKeyno. +// + +void Voice::setKey(int aKeynum) { + key = aKeynum; +} + + + +////////////////////////////// +// +// Voice::setKeynum -- set the keynumber of the voice +// + +void Voice::setKeynum(int aKeynum) { + key = aKeynum; +} + + + +////////////////////////////// +// +// Voice::setVel -- set the MIDI velocity of the voice. +// Synonym for setVelocity. +// + +void Voice::setVel(int aVelocity) { + vel = aVelocity; +} + + + +////////////////////////////// +// +// Voice::setVelocity +// + +void Voice::setVelocity(int aVelocity) { + vel = aVelocity; +} + + + +////////////////////////////// +// +// Voice::status -- returns zero if off or positive if on. +// + +int Voice::status(void) const { + return oldVel; +} + + + +////////////////////////////// +// +// Voice::sustain -- uses default channel if none specified. +// + +void Voice::sustain(int aStatus) { + MidiOutput::sustain(getChannel(), aStatus); +} + + +// md5sum: d02ca41ae3b4e07efe7fedc720e52573 - Voice.cpp =css= 20030102 |