Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

/home/pete/Work/TSE3.svn/tse3/src/tse3/MidiScheduler.h

Go to the documentation of this file.
00001 /*
00002  * @(#)MidiScheduler.h 3.00 10 November 2001
00003  *
00004  * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org)
00005  *
00006  * This file is part of TSE3 - the Trax Sequencer Engine version 3.00.
00007  *
00008  * This library is modifiable/redistributable under the terms of the GNU
00009  * General Public License.
00010  *
00011  * You should have received a copy of the GNU General Public License along
00012  * with this program; see the file COPYING. If not, write to the Free Software
00013  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00014  *
00015  */
00016 
00017 #ifndef TSE3_SCHEDULER_H
00018 #define TSE3_SCHEDULER_H
00019 
00020 #include "tse3/listen/MidiScheduler.h"
00021 
00022 #include "tse3/Notifier.h"
00023 #include "tse3/Midi.h"
00024 #include "tse3/util/MulDiv.h"
00025 
00026 #include <cstddef>
00027 #include <vector>
00028 
00029 namespace TSE3
00030 {
00043     class MidiSchedulerFactory
00044     {
00045         public:
00046 
00057             MidiSchedulerFactory(bool canReturnNull = false);
00058             virtual ~MidiSchedulerFactory();
00059 
00070             MidiScheduler *createScheduler();
00071 
00072         private:
00073 
00074             MidiSchedulerFactory &operator=(const MidiSchedulerFactory &);
00075             MidiSchedulerFactory(const MidiSchedulerFactory &);
00076 
00077             bool _canReturnNull;
00078     };
00079 
00171     class MidiScheduler : public Notifier<MidiSchedulerListener>
00172     {
00173         public:
00174 
00175             MidiScheduler();
00176 
00180             virtual ~MidiScheduler();
00181 
00188             const char *implementationName() const
00189             {
00190                 return this->impl_implementationName();
00191             }
00192 
00193             /******************************************************************
00194              * Finding out about the MIDI ports
00195              *****************************************************************/
00196 
00210             size_t numPorts() const { return _portNumbers.size(); }
00211 
00218             bool validPort(int port) const;
00219 
00234             int portNumber(size_t index) const
00235             {
00236                 return _portNumbers[index].first;
00237             }
00238 
00249             size_t numberToIndex(int number) const;
00250 
00258             void portNumbers(std::vector<int> &numbers) const;
00259 
00269             const char *portName(int port) const;
00270 
00281             const char *portType(int port) const;
00282 
00295             bool portReadable(int port) const;
00296 
00311             bool portWriteable(int port) const;
00312 
00326             bool portInternal(int port) const;
00327 
00339             int defaultInternalPort() const;
00340 
00352             int defaultExternalPort() const;
00353 
00354             /******************************************************************
00355              * Manipulating the clock
00356              *****************************************************************/
00357 
00363             void start(Clock startTime) { this->impl_start(startTime); }
00364 
00369             void start() { this->impl_start(_restingClock); }
00370 
00378             void stop(Clock stopTime = -1);
00379 
00385             bool running() const { return _running; }
00386 
00398             void moveTo(Clock moveTime, Clock newTime);
00399 
00405             void moveTo(Clock moveTime) { moveTo(clock(), moveTime); }
00406 
00416             Clock clock()
00417             {
00418                 return _running ? this->impl_clock() : _restingClock; }
00419 
00425             int msecs() { return this->impl_msecs(); }
00426 
00433             int tempo() const { return _tempo; }
00434 
00448             void setTempo(int newTempo, Clock changeTime)
00449             {
00450                 if (newTempo >= 0)
00451                 {
00452                     this->impl_setTempo(newTempo, changeTime);
00453                     _tempo = newTempo;
00454                 }
00455             }
00456 
00457             /******************************************************************
00458              * Transmitting and receiving commands
00459              *****************************************************************/
00460 
00469             bool eventWaiting() { return this->impl_eventWaiting(); }
00470 
00486             MidiEvent rx();
00487 
00496             void tx(MidiCommand mc);
00497 
00514             void tx(MidiEvent event);
00515 
00516             /*
00517              * Transmit a MIDI "system exclusive" data section immeditately.
00518              * The data is prepended by a MidiSystem_SysExStart status byte,
00519              * and followed by a MidiSystem_SysExEnd status byte. You don't
00520              * have to include these in your parameters.
00521              *
00522              * Although you use this method to send sysex data, you receive
00523              * it through the normal rx mechanism; you will receive a
00524              * @ref MidiEvent with a @ref MidiSystem_SysExStart status byte,
00525              * and the first data byte (in data1). Subsequent data
00526              * bytes are received as MidiEvents with this same status byte. The
00527              * sysex data end is denoted by a @ref MidiEvent with the
00528              * @ref MidiSystem_SysExEnd status byte.
00529              *
00530              * @param port MIDI port number
00531              * @param data A buffer containing the sysex data to send
00532              * @param size The number of bytes in the @p data buffer
00533              */
00534             void txSysEx(int port, const unsigned char *data, size_t size);
00535 
00536             /******************************************************************
00537              * Remote control
00538              *****************************************************************/
00539 
00546             bool remoteControl() const { return _remote; }
00547 
00554             void setRemoteControl(bool s) { _remote = s; }
00555 
00556             bool consumeRemoveEvents() const { return _consumeRemote; }
00557 
00565             unsigned int startNote() const { return _startNote; }
00566 
00573             void setStartNote(unsigned int n) { _startNote = n; }
00574 
00582             unsigned int stopNote() const { return _stopNote; }
00583 
00590             void setStopNote(unsigned int n) { _stopNote = n; }
00591 
00592         protected:
00593 
00594             MidiScheduler(const MidiScheduler &);
00595             MidiScheduler &operator=(const MidiScheduler &);
00596 
00597             /******************************************************************
00598              * Implementation functions
00599              *
00600              * To implement a MidiScheduler for a particular platform you
00601              * implement the functions below. They are called by the
00602              * public MidiScheduler functions, using the Template Method
00603              * design pattern (GoF book).
00604              *
00605              * You can assume that you will never be called with an invalid
00606              * port number, and a number of other parameters are guaranteed
00607              * to be valid, as documented.
00608              *
00609              * Functions like impl_start and impl_stop are more requests
00610              * than commands. The MidiScheduler will not assume that the
00611              * clock has started until the implementation calls the
00612              * clockStarted function.
00613              *
00614              * You shouldn't need to perform any notifications, however, you
00615              * do need to take care to call the next block of protected APIs to
00616              * inform the MidiScheduler code what's going on. If you
00617              * don't do this, the MidiScheduler class will not behave
00618              * properly.
00619              *
00620              * Note that in your destructor you will also want to put the
00621              * following code first:
00622              *     // if playing, stop first!
00623              *     if (MidiScheduler::running()) stop();
00624              *
00625              * Your implementation of the MidiScheduler will have to deal
00626              * with timing. You will be sent events (via impl_tx) IN TIME
00627              * ORDER, for some time in the not-too distant future (as usually
00628              * specified by the Transport class's look-ahead). You have to
00629              * do the work of sending the event at the exact timer tick.
00630              *****************************************************************/
00631 
00632             virtual const char *impl_implementationName() const = 0;
00633             virtual const char *impl_portName(int port) const = 0;
00634             virtual const char *impl_portType(int port) const = 0;
00635             virtual bool        impl_portReadable(int port) const = 0;
00636             virtual bool        impl_portWriteable(int port) const = 0;
00642             virtual void impl_start(Clock clock) = 0;
00649             virtual void impl_stop(Clock clock) = 0;
00655             virtual void impl_moveTo(Clock moveTime, Clock newTime) = 0;
00659             virtual Clock impl_clock() = 0;
00663             virtual int impl_msecs() = 0;
00670             virtual void impl_setTempo(int tempo, Clock changeTime) = 0;
00671             virtual bool impl_eventWaiting() = 0;
00676             virtual MidiEvent impl_rx() = 0;
00682             virtual void impl_tx(MidiCommand mc) = 0;
00693             virtual void impl_tx(MidiEvent mc) = 0;
00697             virtual void impl_txSysEx(int port,
00698                                       const unsigned char *data,
00699                                       size_t size) = 0;
00700 
00701             /******************************************************************
00702              * Implementations call these functions to let the MidiScheduler
00703              * class know whats going on.
00704              *
00705              * Don't forget to call these at appropriate times from the
00706              * impl_XXX functions above.
00707              *****************************************************************/
00708 
00729             int addPort(int portIndex, bool isInternal, int requestedPort = 0);
00730 
00735             void removePort(int portIndex);
00736             void clockStarted(Clock startTime);
00737             void clockStopped(Clock stopTime);
00738             void clockMoved(const Clock moveTime, Clock newTime);
00739             void tempoChanged(int tempo, Clock changeTime);
00740 
00741             /******************************************************************
00742              * Internal helper functions you can call
00743              *****************************************************************/
00744 
00751             Clock startClock;
00752 
00753             // XXX use muldiv switch?
00754 
00759             int clockToMs(Clock time)
00760             {
00761                 return Util::muldiv(time-startClock, 60000/Clock::PPQN, _tempo);
00762             }
00763 
00768             Clock msToClock(int ms)
00769             {
00770                 return startClock + Util::muldiv(ms, _tempo, 60000/Clock::PPQN);
00771             }
00772 
00773         private:
00774 
00775             /******************************************************************
00776              * Internal private functions
00777              *****************************************************************/
00778 
00786             MidiEvent doRemoteControl(MidiEvent e);
00787 
00795             bool validChannel(int channel) const
00796             {
00797                 return channel >= 0 && channel <= 15;
00798             }
00799             bool validChannel(MidiCommand mc) const
00800             {
00801                 return validChannel(mc.channel);
00802             }
00803 
00809             bool lookUpPortNumber(MidiCommand &mc) const;
00810             bool lookUpPortNumber(int &port) const;
00811 
00817             void setToPortNumber(MidiCommand &mc) const;
00818 
00819             /******************************************************************
00820              * Internal private data
00821              *****************************************************************/
00822 
00828             struct PortInfo
00829             {
00830                 int  index;
00831                 bool isInternal;
00832                 PortInfo(int n, bool i) : index(n), isInternal(i) {}
00833             };
00834             typedef std::vector<std::pair<int,PortInfo> > port_vector;
00835 
00836             port_vector    _portNumbers;
00837 
00838             bool           _running;
00839             int            _tempo;
00840             Clock          _restingClock;
00841             bool           _remote;
00842             bool           _consumeRemote;
00843             unsigned int   _startNote;
00844             unsigned int   _stopNote;
00845             int            _defaultInternal;
00846             int            _defaultExternal;
00847     };
00848 }
00849 
00850 #endif
00851 

Generated on Wed May 25 14:45:07 2005 for TSE3 by doxygen 1.3.2