Donnerstag, 7. Dezember 2017

MIDI Programming for LINUX Chapter-2

############################################
// Syntax:        C++
// $Smake:        cc -g -c %b.cc && rm -f %b.o
//
#ifndef _SIGTIMER_H_INCLUDED
#define _SIGTIMER_H_INCLUDED

#ifdef VISUAL
   #include
   typedef LONGLONG int64bits;
#else
   typedef long long int int64bits;
#endif


class SigTimer {
   public:
                       SigTimer           (void);
                       SigTimer           (int aSpeed);
                       SigTimer           (SigTimer& aTimer);
                      ~SigTimer           ();
      static int64bits clockCycles        (void);
      int              expired            (void) const;
      static int       getCpuSpeed        (void);
      double           getPeriod          (void) const;
      double           getPeriodCount     (void) const;
      int              getTicksPerSecond  (void) const;
      int              getTime            (void) const;
      double           getTimeInSeconds   (void) const;
      int              getTimeInTicks     (void) const;
      int              measureCpuSpeed    (int quantize = 0) const;
      void             reset              (void);
      static void      setCpuSpeed        (int aSpeed);
      void             setPeriod          (double aPeriod);
      void             setTempo           (double beatsPerMinute);
      void             setTicksPerSecond  (int aTickRate);
      void             start              (void);
      void             sync               (SigTimer& aTimer);
      void             update             (void);
      void             update             (int periodCount);
   protected:
      static int64bits globalOffset;
      static int       cpuSpeed;        
      int64bits        offset;         
      int              ticksPerSecond;   
      double           period;
   // protected functions
      double           getFactor          (void) const;
};
  
#endif  _SIGTIMER_H_INCLUDED


##################################
// Syntax:        C++
// $Smake:        g++ -O3 -Wall -o %b %f && strip %b
//
#include
#include
#include
#include
#include

#include "SigTimer.cpp"
// global variables:
const char* dev = "/dev/sequencer";     // name of sequencer file
int status;                             // for error checking

// function declarations:
void randomwalk(int seqfd, int device);

int main(int argc, char** argv) {
   int seqfd = open(dev, O_WRONLY, 0);
   if (seqfd < 0) {
      cout << "Error: cannot open " << dev << endl;
      exit(1);
   }
   int numMidi;                        // number of midi outputs
   status = ioctl(seqfd, SNDCTL_SEQ_NRMIDIS, &numMidi);
   if (status != 0) {
      cout << "Error: cannot access MIDI devices on soundcard" << endl;
      exit(1);
   }
   cout << "\nThere are: " << numMidi << " Midi output devices" << endl;
   int device = 0;                    // MIDI output device to use
   if (argc >= 2) {
      device = argv[1][0] - '0';
   }
   if (device >= numMidi) {
      cout << "Error: specified device is not valid: " << device << endl;
      exit(1);
   } else {
      cout << "Device set to: " << device << endl;
   }
  
   randomwalk(seqfd, device);
   close(seqfd);
   return 0;
}

void randomwalk(int seqfd, int device) {
   unsigned char outpacket[4];
   outpacket[0] = SEQ_MIDIPUTC;
   outpacket[2] = device;
   outpacket[3] = 0;
  
   cout << "What timbre do you want: ";
   int userinput;
   cin  >> userinput;
   outpacket[1] = 0xc0;
   write(seqfd, outpacket, 4);
   outpacket[1] = userinput & 0xff;
   write(seqfd, outpacket, 4);

   SigTimer timer;
   cout << "Enter a tempo for quarter notes per minute: ";
   double tempo = 120.0;
   cin >> tempo;
   timer.setTempo(tempo); 
   timer.reset();
   timer.update(-1);
   int key = 60;
   while (1) {
      if (timer.expired()) {
         timer.update();
         switch (rand() % 2) {
            case 0:   key--;    if (key < 0) key = 0;       break;
            case 1:   key++;    if (key > 127) key = 127;   break;
         }
         outpacket[1] = 0x90;            // note-on MIDI command
         write(seqfd, outpacket, 4);
         outpacket[1] = key;             // note-on key MIDI data
         write(seqfd, outpacket, 4);
         outpacket[1] = 127;             // note-on velocity MIDI data
         write(seqfd, outpacket, 4);
     }
  
   }
   close(seqfd);
}

###################################

for MIDI Input:
// Syntax:        C; pthread
// $Smake:        gcc -O3 -Wall -o %b %f -static -lpthread && strip %b
//
#include
#include
#include
#include

#define  MIDI_DEVICE  "/dev/sequencer"

int main(void) {
   unsigned char inpacket[4];
   // first open the sequencer device for reading.
   int seqfd = open(MIDI_DEVICE, O_RDONLY);
   if (seqfd == -1) {
      printf("Error: cannot open %s\n", MIDI_DEVICE);
      exit(1);
   }
   // now just wait around for MIDI bytes to arrive and print them to screen.
   while (1) {
      read(seqfd, &inpacket, sizeof(inpacket));

      // print the MIDI byte if this input packet contains one
      if (inpacket[0] == SEQ_MIDIPUTC) {
         printf("received MIDI byte: %d\n", inpacket[1]);
      }
   }
     
   return 0;
}
##########################################
// Filename:      insimple.c
// Syntax:        C; pthread
// $Smake:        gcc -O3 -Wall -o %b %f -lpthread && strip %b
//
#include
#include
#include
#include

#include          /* for MIDI input interpreter thread */
#define  MIDI_DEVICE  "/dev/sequencer"
// global variables:
int                         seqfd;          // sequencer file descriptor
pthread_t                   midiInThread;   // thread blocker for midi input

// function declarations
void* threadFunction(void*);    // thread function for MIDI input interpreter

///////////////////////////////////////////////////////////////////////////
  
int main(void) {
   int status;            // for error checking
   // (1) first open the sequencer device for reading.
   //     some examples also have a nonblocking options in 2nd param
   seqfd = open(MIDI_DEVICE, O_RDONLY);
   if (seqfd == -1) {
      printf("Error: cannot open %s\n", MIDI_DEVICE);
      exit(1);
   }

   // (2) now start the thread that interpreting incoming MIDI bytes:
   status = pthread_create(&midiInThread, NULL, threadFunction, NULL);
   if (status == -1) {
      printf("Error: unable to create MIDI input thread.\n");
      exit(1);
   }

   // (3) finally, just wait around for MIDI messages to appear in the
   // input buffer and print them to the screen.
   while (1) {
      // do nothing, just wait around for thread function.
   }
   return 0;
}

///////////////////////////////////////////////////////////////////////////

//////////////////////////////
//
// threadFunction -- this function is sent to the pthread library
//    functions for running as a separate thread.
//
void* threadFunction(void* x) {
   unsigned char inbytes[4];         // bytes from sequencer driver
   int status;               // for error checking
   while (1) {
      status = read(seqfd, &inbytes, sizeof(inbytes));
      if (status < 0) {
         printf("Error reading %s\n", MIDI_DEVICE);
         exit(1);
      }

      if (inbytes[0] == SEQ_MIDIPUTC) {
         printf("received MIDI byte: %d\n", inbytes[1]);
      }
   }
}


#####################################

for MIDI I/O Interface
// Syntax:        C++
//
#ifndef _SEQUENCER_H_INCLUDED
#define _SEQUENCER_H_INCLUDED

#include

#define MIDI_EXTERNAL  (1)
#define MIDI_INTERNAL  (2)

typedef unsigned char uchar;

class Sequencer {
   public:
                    Sequencer      (int autoOpen = 1);
                   ~Sequencer      ();
      void          close                (void);
      void          displayInputs        (ostream& out = cout,
                                            char* initial = "\t") const;
      void          displayOutputs       (ostream& out = cout,
                                            char* initial = "\t") const;
      int           getNumInputs         (void) const;
      int           getNumOutputs        (void) const;
      const char*   getInputName         (int aDevice) const;
      const char*   getOutputName        (int aDevice) const;
      int           is_open              (void) const;
      int           open                 (void);
      void          read                 (uchar* buf, uchar* dev, int count);
      void          rawread              (uchar* buf, int packetCount);
      void          rebuildInfoDatabase  (void);
      void          write                (int aDevice, int aByte);
      void          write                (int aDevice, uchar* bytes, int count);
      void          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
   private:
      void          buildInfoDatabase     (void);
      int           getFd                 (void) const;  
      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);  
      void          writeInternal(int aDevice, int aByte);
      void          transmitMessageToInternalSynth(void);
      void          transmitVoiceMessage(void);
      void          transmitCommonMessage(void);
};


#endif  // _SEQUENCER_H_INCLUDED
####################################################
// Syntax:        C++
// $Smake:        g++ -Wall -g -c %f && rm -f %b.o
//

#include
#include
#include
#include
#include
#include
#include "Sequencer.h"


// define static variables:
const char* Sequencer::sequencer       = "/dev/sequencer";
int    Sequencer::sequencer_fd         = -1;
int    Sequencer::class_count          =  0;
uchar  Sequencer::midi_write_packet[4] = {SEQ_MIDIPUTC, 0, 0, 0};
uchar  Sequencer::midi_read_packet[4];

// static variables for MIDI I/O information database
int    Sequencer::indevcount      = 0;
int    Sequencer::outdevcount     = 0;
int*   Sequencer::indevnum        = NULL;
int*   Sequencer::outdevnum       = NULL;
int*   Sequencer::indevtype       = NULL;
int*   Sequencer::outdevtype      = NULL;
char** Sequencer::indevnames      = NULL;
char** Sequencer::outdevnames     = NULL;

///////////////////////////////
//
// Sequencer::Sequencer --
// default value: autoOpen = 1;
//
Sequencer::Sequencer(int autoOpen) {
   if (autoOpen) {
      open();
   }
   if (class_count < 0) {
      cerr << "Unusual class instatiation count: " << class_count << endl;
      exit(1);
   } else if (class_count == 0) {
      buildInfoDatabase();
   }
   class_count++;
}

//////////////////////////////
//
// Sequencer::~Sequencer --
//
Sequencer::~Sequencer() {
   class_count--;
   if (class_count == 0) {
      close();
      removeInfoDatabase();
   } else if (class_count < 0) {
      cerr << "Unusual class instatiation count: " << class_count << endl;
      exit(1);
   }
}

//////////////////////////////
//
// Sequencer::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::close(void) {
   ::close(getFd());
}

//////////////////////////////
//
// Sequencer::displayInputs -- display a list of the
//     available MIDI input devices.
// default values: out = cout, initial = "\t"
//

void Sequencer::displayInputs(ostream& out, char* initial) const {
   for (int i=0; i      out << initial << i << ": " << getInputName(i) << '\n';
   }
}


//////////////////////////////
//
// Sequencer::displayOutputs -- display a list of the
//     available MIDI output devices.
// default values: out = cout, initial = "\t"
//

void Sequencer::displayOutputs(ostream& out, char* initial) const {
   for (int i=0; i      out << initial << i << ": " << getOutputName(i) << '\n';
   }
}


//////////////////////////////
//
// Sequencer::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::getInputName(int aDevice) const {
   if (aDevice >= getNumInputs()) {
      cerr << "Error: " << aDevice << " is greater than max in ("
           << getNumInputs() << ")" << endl;
      exit(1);
   }
   return indevnames[aDevice];
}

//////////////////////////////
//
// Sequencer::getNumInputs -- returns the total number of
//     MIDI inputs that can be used.
//
int Sequencer::getNumInputs(void) const {
   return indevcount;
}

//////////////////////////////
//
// Sequencer::getNumOutputs -- returns the total number of
//     MIDI inputs that can be used.
//
int Sequencer::getNumOutputs(void) const {
   return outdevcount;
}

//////////////////////////////
//
// Sequencer::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::getOutputName(int aDevice) const {
   if (aDevice >= getNumOutputs()) {
      cerr << "Error: " << aDevice << " is greater than max out ("
           << getNumOutputs() << ")" << endl;
      exit(1);
   }
   return outdevnames[aDevice];
}

//////////////////////////////
//
// Sequencer::is_open -- returns true if the
//     sequencer device is open, false otherwise.
//
int Sequencer::is_open(void) const {
   if (getFd() > 0) {
      return 1;
   } else {
      return 0;
   }
}

/////////////////////////////
//
// Sequencer::open -- returns true if the device
// was successfully opended (or already opened)
//
int Sequencer::open(void) {
   if (getFd() <= 0) {
      setFd(::open(sequencer, O_RDWR, 0));
   }
  
   return is_open();
}
  

//////////////////////////////
//
// Sequencer::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::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::rawread -- read Input MIDI packets.
//    each packet contains 4 bytes.
//
void Sequencer::rawread(uchar* buf, int packetCount) {
   ::read(getFd(), buf, packetCount * 4);
}

//////////////////////////////
//
// Sequencer::rebuildInfoDatabase -- rebuild the internal
//   database that keeps track of the MIDI input and output devices.
//
void Sequencer::rebuildInfoDatabase(void) {
   removeInfoDatabase();
   buildInfoDatabase();
}

///////////////////////////////
//
// Sequencer::write -- Send a byte out the specified MIDI
//    port which can be either an internal or an external synthesizer.
//
void Sequencer::write(int device, int aByte) {
   switch (getOutputType(device)) {
      case MIDI_EXTERNAL:
         midi_write_packet[1] = (uchar) (0xff & aByte);
         midi_write_packet[2] = getOutDeviceValue(device);
         ::write(getFd(), midi_write_packet, sizeof(midi_write_packet));
         break;
      case MIDI_INTERNAL:
         writeInternal(getOutDeviceValue(device), aByte);
         break;
   }
}

void Sequencer::write(int device, uchar* bytes, int count) {
   for (int i=0; i      write(device, bytes[i]);
   }
}


void Sequencer::write(int device, int* bytes, int count) {
   for (int i=0; i      write(device, bytes[i]);
   }
}


///////////////////////////////////////////////////////////////////////////
//
// private functions
//
//////////////////////////////
//
// Sequencer::buildInfoDatabase -- determines the number
//     of MIDI input and output devices available from
//     /dev/sequencer, and determines their names.
//
void Sequencer::buildInfoDatabase(void) {
   int status;
   // read number of inputs available (external MIDI devices only)
   status = ioctl(getFd(), SNDCTL_SEQ_NRMIDIS, &indevcount);
   if (status!= 0) {
      cerr << "Error determining the number of MIDI inputs" << endl;
      exit(1);
   }
   // read number of output available
   int extmidi = indevcount;
   int intmidi;
   status = ioctl(getFd(), SNDCTL_SEQ_NRSYNTHS, &intmidi);
   if (status!= 0) {
      cerr << "Error determining the number of MIDI inputs" << 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) {
      cerr << "Error: buildInfoDatabase called twice." << 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      midiinfo.device = i;
      status = ioctl(getFd(), SNDCTL_MIDI_INFO, &midiinfo);
      if (status != 0) {
         cerr << "Error while reading MIDI device " << i << 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      synthinfo.device = i;
      status = ioctl(getFd(), SNDCTL_SYNTH_INFO, &synthinfo);
      if (status != 0) {
         cerr << "Error while reading MIDI device " << i << 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);
   }
}

//////////////////////////////
//
// Sequencer::getFd -- returns the file descriptor of the
//     sequencer device.
//
int Sequencer::getFd(void) const {
   return sequencer_fd;
}

//////////////////////////////
//
// Sequencer::getInDeviceValue --
//
int Sequencer::getInDeviceValue(int aDevice) const {
   if (aDevice >= getNumInputs()) {
      cerr << "Error: " << aDevice << " is greater than max in ("
           << getNumInputs() << ")" << endl;
      exit(1);
   }
   return indevnum[aDevice];
}

//////////////////////////////
//
// Sequencer::getInputType -- returns 1 = external MIDI,
//     2 = internal MIDI
//
int Sequencer::getInputType(int aDevice) const {
   if (aDevice >= getNumInputs()) {
      cerr << "Error: " << aDevice << " is greater than max in ("
           << getNumInputs() << ")" << endl;
      exit(1);
   }
   return indevtype[aDevice];
}

//////////////////////////////
//
// Sequencer::getOutDeviceValue --
//
int Sequencer::getOutDeviceValue(int aDevice) const {
   if (aDevice >= getNumOutputs()) {
      cerr << "Error: " << aDevice << " is greater than max out ("
           << getNumOutputs() << ")" << endl;
      exit(1);
   }
   return outdevnum[aDevice];
}

//////////////////////////////
//
// Sequencer::getOutputType -- returns 1 = external MIDI,
//     2 = internal MIDI
//
int Sequencer::getOutputType(int aDevice) const {
   if (aDevice >= getNumOutputs()) {
      cerr << "Error: " << aDevice << " is greater than max out ("
           << getNumOutputs() << ")" << endl;
      exit(1);
   }
   return outdevtype[aDevice];
}

//////////////////////////////
//
// Sequencer::removeInfoDatabase --
//
void Sequencer::removeInfoDatabase(void) {
   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         if (indevnames[i] != NULL)    delete [] indevnames[i];
      }
      delete [] indevnames;
   }

   if (outdevnames != NULL) {
      for (i=0; 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::setFd --
//
void Sequencer::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::synth_write_message[8];
uchar  Sequencer::synth_message_buffer[1024]   = {0};
int    Sequencer::synth_message_buffer_count   =  0;
int    Sequencer::synth_message_bytes_expected =  0;
int    Sequencer::synth_message_curr_device    =  -1;

//////////////////////////////
//
// Sequencer::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).
//
void Sequencer::writeInternal(int aDevice, int aByte) {
   if (synth_message_bytes_expected == 0) {
      // a new message is coming in.
      synth_message_curr_device = aDevice;
      if (aByte < 128) {
         cerr << "Error: MIDI output byte: " << aByte
              << " is not a command byte." << 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:   cerr << "Can't handle 0xE0 yet" << endl;   exit(1);
         default:     cerr << "Unknown error" << endl;   exit(1);
      }
   }
   // otherwise expecting at least one more byte for the MIDI message
   else {
      if (synth_message_curr_device != aDevice) {
         cerr << "Error: device number changed during message" << endl;
         exit(1);
      }
      if (aByte > 127) {
         cerr << "Error: expecting MIDI data but got MIDI command: "
              << aByte << 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) {
      transmitMessageToInternalSynth();
      synth_message_bytes_expected = 0;
      synth_message_buffer_count = 0;
   }
}
    
//////////////////////////////
//
// Sequencer::transmitMessageToInternalSynth -- send the stored
//    MIDI message to the internal synthesizer.
//
void Sequencer::transmitMessageToInternalSynth(void) {
   switch (synth_message_buffer[0] & 0xf0) {
      case 0x80:                      // Note-off
      case 0x90:                      // Note-on
      case 0xA0:                      // Aftertouch
         transmitVoiceMessage();
         break;
      case 0xB0:                      // Control change
      case 0xC0:                      // Patch change
      case 0xD0:                      // Channel pressure
      case 0xE0:                      // Pitch wheel
         transmitCommonMessage();
         break;
      case 0xF0:
         cerr << "Cannot handle 0xf0 commands yet" << endl;
         exit(1);
         break;
      default:
         cerr << "Error: unknown MIDI command" << endl;
         exit(1);
   }
}

//////////////////////////////
//
// Sequencer::transmitVoiceMessage -- send a voice-type MIDI
//     message to an internal synthesizer.
//
void Sequencer::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;
   ::write(getFd(), synth_write_message, sizeof(synth_write_message));
}

//////////////////////////////
//
// Sequencer::transmitCommonMessage -- send a common-type MIDI
//     message to an internal synthesizer.
//
void Sequencer::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:
         cerr << "Unknown Common MIDI message" << endl;
         exit(1);
   }
   ::write(getFd(), synth_write_message, sizeof(synth_write_message));
}

##################################
// Filename:      ...linuxmidi/cpp/midiinfo.cpp
// Syntax:        C++
// $Smake:        g++ -DLINUX -O3 -Wall -o %b %f Sequencer.cpp && strip %b
//
// Description:   displays the MIDI input/output devices which can be
//                accessed through /dev/sequencer.
//

#include
#include "Sequencer.h"


int main(void) {
   Sequencer sequencer;
   cout << "\nNumber of MIDI outputs: " << sequencer.getNumOutputs() << '\n';
   sequencer.displayOutputs();
   cout << "\nNumber of MIDI inputs: " << sequencer.getNumInputs() << '\n';
   sequencer.displayInputs();
   cout << endl;
   return 0;
}

##########################################
// Syntax:        C++
// $Smake:        g++ -DLINUX -O3 -Wall -o %b %f Sequencer.cpp && strip %b
//

#include
#include "Sequencer.h"


int main(void) {
   Sequencer sequencer;          // MIDI I/O interface
   int outputDevice = 0;         // MIDI output device number to send to
   int keynumber = 60;           // MIDI keynumber to play
   int velocity;                 // MIDI attack velocity
   int userInput;                // computer keyboard input number
   cout << "There are " << sequencer.getNumOutputs() << " MIDI outputs:.\n";
   sequencer.displayOutputs();
   cout << "\nEnter a device number to send out on (offset zero): ";
   cin  >> outputDevice;
   while (1) {
      cout << "Enter a key number to play (negative=off, >127=quit): ";
      cin  >> userInput;
  
      if (userInput > 127) {
         exit(0);
      } else if (userInput >= 0 && userInput < sequencer.getNumOutputs()) {
         outputDevice = userInput;
         cout << "Changing to device " << outputDevice << ": "
              << sequencer.getOutputName(outputDevice) << endl;
         continue;
      } else {
         keynumber = userInput;
      }
  
      if (keynumber < 0) {
         keynumber = -keynumber;
         velocity = 0;
      } else {
         velocity = 127;
      }
      // send a MIDI note-on message on MIDI channel 1:
      sequencer.write(outputDevice, 0x90);      // MIDI chan 1 note-on command
      sequencer.write(outputDevice, keynumber); // MIDI key number
      sequencer.write(outputDevice, velocity);  // MIDI attack velocity
   }
     
   return 0;
}

#####################################

Keine Kommentare:

Kommentar veröffentlichen

Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.