cleanup and refactor to prepare for "always on" listen loop
authorAlex Montgomery <apmontgo@users.sourceforge.net>
Sun, 8 May 2011 18:14:17 +0000 (8 19:14 +0100)
committerAlex Montgomery <apmontgo@users.sourceforge.net>
Sun, 8 May 2011 18:14:17 +0000 (8 19:14 +0100)
TODO
common.c
common.h
main.c
qt/src/main.cpp
qt/src/mainWindow.cpp
qt/src/mainWindow.h
qt/src/qjackmmc.ui
qt/src/sequencerThread.cpp
qt/src/sequencerThread.h

diff --git a/TODO b/TODO
index 3839a2b..5e64376 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,5 +1,6 @@
 - fix XRun on quit
 - thread-proof / separate the listen loop
+- make listen loop "always on"
 - change verbose to dropdown with output levels: normal, verbose, silent
 - allow 'output level' to be changed while listening
 - use XML for settings
index bc25c51..e7c8695 100644 (file)
--- a/common.c
+++ b/common.c
 
 #include "common.h"
 
-// common globals
+// exported globals
 int g_quit = 0; // a flag which will be set by our signal handler when it's time to exit
+int g_isListening = 0;
+
+// globals used only here in common.c
 snd_seq_t* g_seq_ptr = NULL;
 jack_client_t* g_jack_client = NULL;
-int g_isListening = 0;
+struct pollfd* g_pollDescriptor = NULL;
+int g_numDescriptors = 0;
 
 #if LASH_SUPPORT
 lash_client_t* g_lashc = NULL;
 
 void init_lash(int argc, char* argv[])
 {
-   lash_event_t * lash_event_ptr = NULL;
-
    /* LASH setup */
    g_lashc = lash_init( lash_extract_args(&argc, &argv), "jackctlmmc", 0, LASH_PROTOCOL_VERSION); 
 
@@ -145,8 +147,14 @@ int init_alsa_sequencer(const char* appName)
    if (ret < 0)
       printMMCMessage("Error with alsa sequencer initialization, %s\n", snd_strerror(ret));
    else // all is well, register the sequencer with whatever name was passed in
+   {
       snd_seq_set_client_name(g_seq_ptr, appName);
 
+      g_numDescriptors = snd_seq_poll_descriptors_count(g_seq_ptr, POLLIN);
+      g_pollDescriptor = (struct pollfd *)malloc(g_numDescriptors * sizeof(struct pollfd));
+      snd_seq_poll_descriptors(g_seq_ptr, g_pollDescriptor, g_numDescriptors, POLLIN);
+   }
+
    return ret;
 }
 
@@ -301,39 +309,32 @@ void handle_midi(uint8_t* midiBuff, MidiSettings* settings)
    }
 }
 
-void listen_loop (MidiSettings* settings)
+void poll_midi (MidiSettings* settings)
 {
    snd_seq_event_t * seq_event_ptr = NULL;
 
-   int npfd = snd_seq_poll_descriptors_count(g_seq_ptr, POLLIN);
-   struct pollfd * pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
-   snd_seq_poll_descriptors(g_seq_ptr, pfd, npfd, POLLIN);
-
-   while(!g_quit)
-   {
-      if (poll(pfd, npfd, 250) > 0 && snd_seq_event_input(g_seq_ptr, &seq_event_ptr) >= 0 && seq_event_ptr->type == SND_SEQ_EVENT_SYSEX)
-         handle_midi((uint8_t *)seq_event_ptr->data.ext.ptr, settings);
+   if (poll(g_pollDescriptor, g_numDescriptors, 250) > 0 && snd_seq_event_input(g_seq_ptr, &seq_event_ptr) >= 0 && seq_event_ptr->type == SND_SEQ_EVENT_SYSEX)
+      handle_midi((uint8_t *)seq_event_ptr->data.ext.ptr, settings);
 
 #if LASH_SUPPORT
-      /* Process LASH events */
+   /* Process LASH events */
+   {
+      lash_event_t * lash_event_ptr = NULL;
+      lash_config_t * lash_config_ptr = NULL;
+      while ((lash_event_ptr = lash_get_event(g_lashc)) != NULL)
       {
-         lash_event_t * lash_event_ptr = NULL;
-         lash_config_t * lash_config_ptr = NULL;
-         while ((lash_event_ptr = lash_get_event(g_lashc)) != NULL)
-         {
-            process_lash_event(lash_event_ptr);
-            lash_event_destroy(lash_event_ptr); 
-         }
+         process_lash_event(lash_event_ptr);
+         lash_event_destroy(lash_event_ptr);
+      }
 
-         /* Process LASH configs */
-         while ((lash_config_ptr = lash_get_config(g_lashc)) != NULL)
-         {
-            process_lash_config(lash_config_ptr);
-            lash_config_destroy(lash_config_ptr);  
-         }
+      /* Process LASH configs */
+      while ((lash_config_ptr = lash_get_config(g_lashc)) != NULL)
+      {
+         process_lash_config(lash_config_ptr);
+         lash_config_destroy(lash_config_ptr);
       }
-#endif
    }
+#endif
 }
 
 void cleanup_globals()
@@ -349,8 +350,14 @@ void cleanup_globals()
       }
    }
 
+   if (g_pollDescriptor)
+      free(g_pollDescriptor);
+
    if (g_jack_client)
    {
+#if JACK_MIDI_SUPPORT
+      jack_port_unregister(g_jack_client, g_jackMidiIn);
+#endif
       jack_deactivate(g_jack_client);
       jack_client_close(g_jack_client);
    }
index e8402c5..75ed435 100644 (file)
--- a/common.h
+++ b/common.h
@@ -34,8 +34,6 @@ typedef struct
 
 // globals
 extern int g_quit;
-extern snd_seq_t* g_seq_ptr;
-extern jack_client_t* g_jack_client;
 extern int g_isListening;
 
 // functions implemented differently by cli and qt frontends
@@ -45,7 +43,7 @@ extern void printMMCMessage(const char* message, ...);
 int init_alsa_sequencer(const char* appName);
 int init_jack(const char* appName);
 int activate_jack();
-void listen_loop (MidiSettings* settings);
+void poll_midi (MidiSettings* settings);
 void cleanup_globals();
 void handle_midi(uint8_t* midiBuff, MidiSettings* settings);
 
diff --git a/main.c b/main.c
index 8eb5c1c..8741a64 100644 (file)
--- a/main.c
+++ b/main.c
@@ -98,7 +98,11 @@ int main(int argc, char *argv[])
 
    // start listening for and handling MMC events, stops when g_quit is true (SIGINT)
    g_isListening = true;
-   listen_loop(&settings);
+
+   while (!g_quit)
+   {
+      poll_midi(&settings);
+   }
 
    // so we shall quit, eh? ok, cleanup time. otherwise jack would probably produce an xrun on shutdown
    cleanup();
index 231f77c..2a68382 100644 (file)
@@ -23,7 +23,7 @@
 #include <QString>
 #include "mainWindow.h"
 
-static MainWindow* mainWindow = NULL;
+MainWindow* mainWindow = NULL;
 
 int main(int argc, char *argv[])
 {
index d2658b7..39f7c5f 100644 (file)
@@ -153,7 +153,7 @@ void MainWindow::on_startButton_clicked()
       startButton->setText("&Stop Listening");
             
       // start the MMC listener thread
-      sequencerThread = new SequencerThread(this, &m_settings);
+      sequencerThread = new SequencerThread(this, &m_settings, &m_settingsMutex);
 
 
       
index 77d8f75..71e1105 100644 (file)
@@ -20,7 +20,9 @@
 
 #include "ui_qjackmmc.h"
 #include "../../config.h"
+
 #include <QFile>
+#include <QMutex>
 
 extern "C" {
 #include "../../common.h"
@@ -57,5 +59,6 @@ class MainWindow : public QMainWindow, public Ui::QjackMMC
       void enableRelevantWidgets(bool isRunning);
       
       SequencerThread* sequencerThread;
-      MidiSettings m_settings;
+      MidiSettings m_settings; //< shared between threads, Always lock m_settingsMutex when accessing!
+      QMutex m_settingsMutex; //< guards m_settings
 };
index 2be5751..ac4d3a0 100644 (file)
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>419</width>
-    <height>390</height>
+    <height>362</height>
    </rect>
   </property>
   <property name="sizePolicy">
          <string>Check this to schedule QJackMMC with the highest allowable thread priority.</string>
         </property>
         <property name="text">
-         <string>Use &amp;Realtime thread</string>
+         <string>Use &amp;high priority thread</string>
         </property>
        </widget>
       </item>
index 75b3838..52d7e5c 100644 (file)
  ***************************************************************************/
 
 #include "sequencerThread.h"
+#include <QMutexLocker>
 
-SequencerThread::SequencerThread(QObject* parent, MidiSettings* settings)
-   : QThread(parent), m_settings(settings)
+SequencerThread::SequencerThread(QObject* parent, MidiSettings* settings, QMutex* settingsMutex)
+   : QThread(parent), m_settings(settings), m_settingsMutex(settingsMutex)
 {
 }
 
@@ -37,7 +38,12 @@ void SequencerThread::listen(bool realTime)
 void SequencerThread::run ()
 {
    g_quit = 0;
-   listen_loop(m_settings);
+
+   while(!g_quit)
+   {
+      QMutexLocker settingsLock(m_settingsMutex);
+      poll_midi(m_settings);
+   }
 }
 
 void SequencerThread::die()
index f42ab81..4d7a9ca 100644 (file)
@@ -19,6 +19,7 @@
  ***************************************************************************/
 
 #include <QThread>
+class QMutex;
 
 extern "C" {
 #include "../../common.h"
@@ -29,7 +30,7 @@ class SequencerThread : public QThread
    Q_OBJECT
          
    public: 
-      SequencerThread(QObject* parent, MidiSettings* settings);
+      SequencerThread(QObject* parent, MidiSettings* settings, QMutex* settingsMutex);
       
       void listen(bool realTime);
       void die();
@@ -38,4 +39,5 @@ class SequencerThread : public QThread
       virtual void run ();
       
       MidiSettings* m_settings;
+      QMutex* m_settingsMutex;
 };