changeset 562:ecce042cc374

* Wire up MIDI input port (as far as printing a message when an event comes in, anyway)
author Chris Cannam
date Mon, 23 Feb 2009 17:50:17 +0000
parents 863ad4b1f841
children a5e0d1068cae
files data/data.pro data/midi/MIDIInput.cpp data/midi/MIDIInput.h data/midi/rtmidi/RtMidi.cpp data/midi/rtmidi/RtMidi.h
diffstat 5 files changed, 126 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/data/data.pro	Mon Feb 23 14:40:17 2009 +0000
+++ b/data/data.pro	Mon Feb 23 17:50:17 2009 +0000
@@ -14,6 +14,11 @@
 OBJECTS_DIR = tmp_obj
 MOC_DIR = tmp_moc
 
+# Set up suitable platform defines for RtMidi
+linux*: DEFINES += __LINUX_ALSASEQ__
+macx*:  DEFINES += __MACOSX_CORE__
+win*:   DEFINES += __WINDOWS_MM__
+
 # Input
 HEADERS += fft/FFTapi.h \
            fft/FFTCacheReader.h \
@@ -48,6 +53,8 @@
            fileio/WavFileWriter.h \
            midi/MIDIEvent.h \
            midi/MIDIInput.h \
+           midi/rtmidi/RtError.h \
+           midi/rtmidi/RtMidi.h \
            model/AggregateWaveModel.h \
            model/AlignmentModel.h \
            model/Dense3DModelPeakCache.h \
@@ -104,6 +111,7 @@
            fileio/WavFileReader.cpp \
            fileio/WavFileWriter.cpp \
            midi/MIDIInput.cpp \
+           midi/rtmidi/RtMidi.cpp \
            model/AggregateWaveModel.cpp \
            model/AlignmentModel.cpp \
            model/Dense3DModelPeakCache.cpp \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/midi/MIDIInput.cpp	Mon Feb 23 17:50:17 2009 +0000
@@ -0,0 +1,86 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2006-2009 Chris Cannam and QMUL.
+    
+    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.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "MIDIInput.h"
+
+#include "rtmidi/RtMidi.h"
+
+MIDIInput::MIDIInput(QString name) :
+    m_rtmidi(),
+    m_buffer(1023)
+{
+    try {
+        m_rtmidi = new RtMidiIn(name.toStdString());
+        m_rtmidi->setCallback(staticCallback, this);
+        m_rtmidi->openPort();
+    } catch (RtError e) {
+        e.printMessage();
+        delete m_rtmidi;
+        m_rtmidi = 0;
+    }
+}
+
+MIDIInput::~MIDIInput()
+{
+    delete m_rtmidi;
+}
+
+void
+MIDIInput::staticCallback(double timestamp, std::vector<unsigned char> *message,
+                          void *userData)
+{
+    ((MIDIInput *)userData)->callback(timestamp, message);
+}
+
+void
+MIDIInput::callback(double timestamp, std::vector<unsigned char> *message)
+{
+    std::cerr << "MIDIInput::callback(" << timestamp << ")" << std::endl;
+
+}
+
+MIDIEvent
+MIDIInput::readEvent()
+{
+    MIDIEvent *event = m_buffer.readOne();
+    MIDIEvent revent = *event;
+    delete event;
+    return revent;
+}
+
+void
+MIDIInput::postEvent(MIDIEvent e)
+{
+    int count = 0, max = 5;
+    while (m_buffer.getWriteSpace() == 0) {
+        if (count == max) {
+            std::cerr << "ERROR: MIDIInput::postEvent: MIDI event queue is full and not clearing -- abandoning incoming event" << std::endl;
+            return;
+        }
+        std::cerr << "WARNING: MIDIInput::postEvent: MIDI event queue (capacity " << m_buffer.getSize() << " is full!" << std::endl;
+        std::cerr << "Waiting for something to be processed" << std::endl;
+#ifdef _WIN32
+        Sleep(1);
+#else
+        sleep(1);
+#endif
+        count++;
+    }
+
+    MIDIEvent *me = new MIDIEvent(e);
+    m_buffer.write(&me, 1);
+    emit eventsAvailable();
+}
+
--- a/data/midi/MIDIInput.h	Mon Feb 23 14:40:17 2009 +0000
+++ b/data/midi/MIDIInput.h	Mon Feb 23 17:50:17 2009 +0000
@@ -29,7 +29,7 @@
     Q_OBJECT
 
 public:
-    MIDIInput();
+    MIDIInput(QString name);
     virtual ~MIDIInput();
 
     bool isOK() const { return m_rtmidi != 0; }
--- a/data/midi/rtmidi/RtMidi.cpp	Mon Feb 23 14:40:17 2009 +0000
+++ b/data/midi/rtmidi/RtMidi.cpp	Mon Feb 23 17:50:17 2009 +0000
@@ -69,9 +69,9 @@
 //  Common RtMidiIn Definitions
 //*********************************************************************//
 
-RtMidiIn :: RtMidiIn() : RtMidi()
+RtMidiIn :: RtMidiIn(std::string name) : RtMidi()
 {
-  this->initialize();
+  this->initialize(name);
 }
 
 void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData )
@@ -144,9 +144,9 @@
 //  Common RtMidiOut Definitions
 //*********************************************************************//
 
-RtMidiOut :: RtMidiOut() : RtMidi()
+RtMidiOut :: RtMidiOut(std::string name) : RtMidi()
 {
-  this->initialize();
+  this->initialize(name);
 }
 
 
@@ -311,11 +311,11 @@
   }
 }
 
-void RtMidiIn :: initialize( void )
+void RtMidiIn :: initialize(std::string name)
 {
   // Set up our client.
   MIDIClientRef client;
-  OSStatus result = MIDIClientCreate( CFSTR("RtMidi Input Client"), NULL, NULL, &client );
+  OSStatus result = MIDIClientCreate( CFSTR(name.c_str()), NULL, NULL, &client );
   if ( result != noErr ) {
     errorString_ = "RtMidiIn::initialize: error creating OS-X MIDI client object.";
     error( RtError::DRIVER_ERROR );
@@ -479,11 +479,11 @@
   return stringName;
 }
 
-void RtMidiOut :: initialize( void )
+void RtMidiOut :: initialize(std::string name)
 {
   // Set up our client.
   MIDIClientRef client;
-  OSStatus result = MIDIClientCreate( CFSTR("RtMidi Output Client"), NULL, NULL, &client );
+  OSStatus result = MIDIClientCreate( CFSTR(name.c_str()), NULL, NULL, &client );
   if ( result != noErr ) {
     errorString_ = "RtMidiOut::initialize: error creating OS-X MIDI client object.";
     error( RtError::DRIVER_ERROR );
@@ -813,7 +813,7 @@
   return 0;
 }
 
-void RtMidiIn :: initialize( void )
+void RtMidiIn :: initialize(std::string name)
 {
   // Set up the ALSA sequencer client.
 	snd_seq_t *seq;
@@ -824,7 +824,7 @@
 	}
 
   // Set client name.
-  snd_seq_set_client_name(seq, "RtMidi Input Client");
+  snd_seq_set_client_name(seq, name.c_str());
 
   // Save our api-specific connection information.
   AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
@@ -885,8 +885,8 @@
     error( RtError::NO_DEVICES_FOUND );
   }
 
-	snd_seq_port_info_t *pinfo;
-	snd_seq_port_info_alloca( &pinfo );
+  snd_seq_port_info_t *pinfo;
+  snd_seq_port_info_alloca( &pinfo );
   std::ostringstream ost;
   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
   if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) == 0 ) {
@@ -895,6 +895,8 @@
     error( RtError::INVALID_PARAMETER );
   }
 
+  char name[20];
+  sprintf(name, "Input %d", portNumber + 1);
 
   snd_seq_addr_t sender, receiver;
   sender.client = snd_seq_port_info_get_client( pinfo );
@@ -913,7 +915,7 @@
     snd_seq_port_info_set_timestamping(pinfo, 1);
     snd_seq_port_info_set_timestamp_real(pinfo, 1);    
     snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
-    snd_seq_port_info_set_name(pinfo, "RtMidi Input");
+    snd_seq_port_info_set_name(pinfo, name);
     data->vport = snd_seq_create_port(data->seq, pinfo);
   
     if ( data->vport < 0 ) {
@@ -1095,7 +1097,7 @@
   return 0;
 }
 
-void RtMidiOut :: initialize( void )
+void RtMidiOut :: initialize(std::string name)
 {
   // Set up the ALSA sequencer client.
 	snd_seq_t *seq;
@@ -1106,7 +1108,7 @@
 	}
 
   // Set client name.
-  snd_seq_set_client_name(seq, "RtMidi Output Client");
+  snd_seq_set_client_name(seq, name.c_str());
 
   // Save our api-specific connection information.
   AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
@@ -1145,8 +1147,8 @@
     error( RtError::NO_DEVICES_FOUND );
   }
 
-	snd_seq_port_info_t *pinfo;
-	snd_seq_port_info_alloca( &pinfo );
+  snd_seq_port_info_t *pinfo;
+  snd_seq_port_info_alloca( &pinfo );
   std::ostringstream ost;
   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
   if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) == 0 ) {
@@ -1160,8 +1162,11 @@
   receiver.port = snd_seq_port_info_get_port( pinfo );
   sender.client = snd_seq_client_id( data->seq );
 
+  char name[20];
+  sprintf(name, "Output %d", portNumber + 1);
+
   if ( data->vport < 0 ) {
-    data->vport = snd_seq_create_simple_port( data->seq, "RtMidi Output",
+    data->vport = snd_seq_create_simple_port( data->seq, name,
                                               SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
                                               SND_SEQ_PORT_TYPE_MIDI_GENERIC );
     if ( data->vport < 0 ) {
@@ -1423,7 +1428,7 @@
   return 0;
 }
 
-void RtMidiIn :: initialize( void )
+void RtMidiIn :: initialize(std::string name)
 {
   // Initialize the Irix MIDI system.  At the moment, we will not
   // worry about a return value of zero (ports) because there is a
@@ -1564,7 +1569,7 @@
   return stringName;
 }
 
-void RtMidiOut :: initialize( void )
+void RtMidiOut :: initialize(std::string name)
 {
   // Initialize the Irix MIDI system.  At the moment, we will not
   // worry about a return value of zero (ports) because there is a
@@ -1789,7 +1794,7 @@
   apiData->message.bytes.clear();
 }
 
-void RtMidiIn :: initialize( void )
+void RtMidiIn :: initialize(std::string name)
 {
   // We'll issue a warning here if no devices are available but not
   // throw an error since the user can plugin something later.
@@ -1970,7 +1975,7 @@
   return stringName;
 }
 
-void RtMidiOut :: initialize( void )
+void RtMidiOut :: initialize(std::string name)
 {
   // We'll issue a warning here if no devices are available but not
   // throw an error since the user can plug something in later.
--- a/data/midi/rtmidi/RtMidi.h	Mon Feb 23 14:40:17 2009 +0000
+++ b/data/midi/rtmidi/RtMidi.h	Mon Feb 23 17:50:17 2009 +0000
@@ -109,7 +109,7 @@
   /*!
       An exception will be thrown if a MIDI system initialization error occurs.
   */
-  RtMidiIn();
+  RtMidiIn(std::string inputName = std::string("RtMidi Input Client"));
 
   //! If a MIDI connection is still open, it will be closed by the destructor.
   ~RtMidiIn();
@@ -217,7 +217,7 @@
 
  private:
 
-  void initialize( void );
+  void initialize(std::string name);
   RtMidiInData inputData_;
 
 };
@@ -244,7 +244,7 @@
   /*!
       An exception will be thrown if a MIDI system initialization error occurs.
   */
-  RtMidiOut();
+  RtMidiOut(std::string outputName = "RtMidi Output Client");
 
   //! The destructor closes any open MIDI connections.
   ~RtMidiOut();
@@ -290,7 +290,7 @@
 
  private:
 
-  void initialize( void );
+  void initialize(std::string name);
 };
 
 #endif