text: /*
   *  libjdksmidi-2004 C++ Class Library for MIDI
   *
   *  Copyright (C) 2004  J.D. Koftinoff Software, Ltd.
   *  www.jdkoftinoff.com
   *  jeffk@jdkoftinoff.com
   *
   *  *** RELEASED UNDER THE GNU GENERAL PUBLIC LICENSE (GPL) April 27, 2004 ***
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
  
  #include "jdksmidi/world.h"
  #include "jdksmidi/driver.h"
  
  namespace jdksmidi
  {
  
  MIDIDriver::MIDIDriver ( int queue_size )
      :
      in_queue ( queue_size ),
      out_queue ( queue_size ),
      in_proc ( 0 ),
      out_proc ( 0 ),
      thru_proc ( 0 ),
      thru_enable ( false ),
      tick_proc ( 0 )
  {
  }
  
  MIDIDriver::~MIDIDriver()
  {
  }
  
  void MIDIDriver::Reset()
  {
      in_queue.Clear();
      out_queue.Clear();
      out_matrix.Clear();
  }
  
  void MIDIDriver::AllNotesOff ( int chan )
  {
      MIDITimedBigMessage msg;
      // send a note off for every note on in the out_matrix
  
      if ( out_matrix.GetChannelCount ( chan ) > 0 )
      {
          for ( int note = 0; note < 128; ++note )
          {
              while ( out_matrix.GetNoteCount ( chan, note ) > 0 )
              {
                  // make a note off with note on msg, velocity 0
                  msg.SetNoteOn ( ( unsigned char ) chan,
                                  ( unsigned char ) note, 0 );
                  OutputMessage ( msg );
              }
          }
      }
  
      msg.SetControlChange ( chan, C_DAMPER, 0 );
      OutputMessage ( msg );
      msg.SetAllNotesOff ( ( unsigned char ) chan );
      OutputMessage ( msg );
  }
  
  void MIDIDriver::AllNotesOff()
  {
      for ( int i = 0; i < 16; ++i )
      {
          AllNotesOff ( i );
      }
  }
  
  bool MIDIDriver::HardwareMsgIn ( MIDITimedBigMessage &msg )
  {
      // put input midi messages thru the in processor
      if ( in_proc )
      {
          if ( in_proc->Process ( &msg ) == false )
          {
              // message was deleted, so ignore it.
              return true;
          }
      }
  
      // stick input into in queue
  
      if ( in_queue.CanPut() )
      {
          in_queue.Put ( msg );
      }
  
      else
      {
          return false;
      }
  
      // now stick it through the THRU processor
  
      if ( thru_proc )
      {
          if ( thru_proc->Process ( &msg ) == false )
          {
              // message was deleted, so ignore it.
              return true;
          }
      }
  
      if ( thru_enable )
      {
          // stick this message into the out queue so the tick procedure
          // will play it out asap
          if ( out_queue.CanPut() )
          {
              out_queue.Put ( msg );
          }
  
          else
          {
              return false;
          }
      }
  
      return true;
  }
  
  void MIDIDriver::TimeTick ( unsigned long sys_time )
  {
      // run the additional tick procedure if we need to
      if ( tick_proc )
      {
          tick_proc->TimeTick ( sys_time );
      }
  
      // feed as many midi messages from out_queu to the hardware out port
      // as we can
  
      while ( out_queue.CanGet() )
      {
          // use the Peek() function to avoid allocating memory for
          // a duplicate sysex
          if ( HardwareMsgOut ( * ( out_queue.Peek() ) ) == true )
          {
              // ok, got and sent a message - update our out_queue now
              out_queue.Next();
          }
  
          else
          {
              // cant send any more, stop now.
              break;
          }
      }
  }
  
  }
  