On 14/06/2013 16:28, Raine M. Ekman wrote:
Quoting Shane Ambler <[email protected]>:
This may be FreeBSD specific but I found that the only way to make
use of usb-midi is through jack_umidi. So I started adding it to
lmms.

I have jack midi input working so far with two issues.

1. soundfont does not receive any midi input

Does your code call instrument->isMidiBased() or something like that?
 The sf2player lies on that point, not that it has mattered much
before...

What I added doesn't call that, but I have tried changing
sf2player::isMidiBased to return both true and false

I got to try 0.4.15 official build and the Q49 usb attached to a windows
7 machine (64bit) and get the same thing - no soundfont response and
zynaddsubfx only responds if the keyboard is on channel one.

Is this something you would add to lmms or are there other plans
to support usb-midi devices?

I think Jack MIDI would be nice. And if it's the most feasible way to
 get USB-MIDI support on some system, it's totally worth including.

Is there a patch to try?


I'll attach the first patch I used to get jack midi running. I haven't
had any luck getting midi out running. Now I'm looking at expanding the
input ports for multiple devices.

At this stage I haven't tested whether it plays nice with jack audio
(jack audio doesn't run very long for me)- not sure if both classes
should call jack_client_open. But I have run lmms for several hours
playing the keyboard through jack midi without problems.


diff --git a/CMakeLists.txt b/CMakeLists.txt
index ba56de4..01f6ea0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -588,6 +588,7 @@ MESSAGE(
 "-------------------------\n"
 "* ALSA                        : ${STATUS_ALSA}\n"
 "* OSS                         : ${STATUS_OSS}\n"
+"* JACK                        : ${STATUS_JACK}\n"
 "* WinMM                       : ${STATUS_WINMM}\n"
 )
 
diff --git a/include/MidiJack.h b/include/MidiJack.h
new file mode 100644
index 0000000..e0b6f7e
--- /dev/null
+++ b/include/MidiJack.h
@@ -0,0 +1,87 @@
+/*
+ * MidiJack.h - Jack MIDI client
+ *
+ * by Shane Ambler
+ *
+ * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
+ *
+ * Based on jack midi code used by hydrogen drum machine
+ * and jack example clients.
+ *
+ */
+
+#ifndef MIDIJACK_H
+#define MIDIJACK_H
+
+#include "lmmsconfig.h"
+
+#ifdef LMMS_HAVE_JACK
+#include <jack/jack.h>
+#include <jack/midiport.h>
+
+#include <QtCore/QThread>
+#include <QMutex>
+#include <QtCore/QFile>
+
+#include "MidiClient.h"
+
+#define        JACK_MIDI_BUFFER_MAX 64 /* events */
+
+class QLineEdit;
+
+class MidiJack : public MidiClientRaw, public QThread
+{
+public:
+    MidiJack();
+    virtual ~MidiJack();
+
+    static QString probeDevice();
+
+    inline static QString name()
+    {
+        return( QT_TRANSLATE_NOOP( "setupWidget",
+            "Jack-MIDI" ) );
+    }
+
+    void JackMidiWrite(jack_nframes_t nframes);
+    void JackMidiRead(jack_nframes_t nframes);
+
+
+    class setupWidget : public MidiClientRaw::setupWidget
+    {
+    public:
+        setupWidget( QWidget * _parent );
+        virtual ~setupWidget();
+
+        virtual void saveSettings();
+
+    private:
+        QLineEdit * m_device;
+
+    } ;
+
+
+protected:
+    virtual void sendByte( const Uint8 _c );
+    virtual void run();
+
+
+private:
+    jack_client_t * m_jack_client;
+    jack_port_t *m_input_port;
+    jack_port_t *m_output_port;
+    uint8_t m_jack_buffer[JACK_MIDI_BUFFER_MAX * 4];
+
+    void JackMidiOutEvent(uint8_t *buf, uint8_t len);
+    void lock();
+    void unlock();
+
+    void getPortInfo( const QString& sPortName, int& nClient, int& nPort );
+
+    volatile bool m_quit;
+
+};
+
+#endif // LMMS_HAVE_JACK
+
+#endif // MIDIJACK_H
diff --git a/src/core/midi/MidiJack.cpp b/src/core/midi/MidiJack.cpp
new file mode 100644
index 0000000..8ef0aeb
--- /dev/null
+++ b/src/core/midi/MidiJack.cpp
@@ -0,0 +1,201 @@
+/*
+ * MidiJack.cpp - Jack MIDI client
+ *
+ * by Shane Ambler
+ *
+ * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
+ *
+ * Based on jack midi code used by hydrogen drum machine
+ * and jack example clients.
+ *
+ */
+
+#include "MidiJack.h"
+
+#ifdef LMMS_HAVE_JACK
+
+#include <QtGui/QCompleter>
+#include <QtGui/QDirModel>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QMessageBox>
+#include <QTranslator>
+
+#ifdef LMMS_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "config_mgr.h"
+#include "gui_templates.h"
+#include "engine.h"
+#include "MainWindow.h"
+
+/* callback functions for jack */
+static int JackMidiProcessCallback(jack_nframes_t nframes, void *arg)
+{
+    MidiJack *jmd = (MidiJack *)arg;
+
+    if (nframes <= 0)
+        return (0);
+
+    jmd->JackMidiRead(nframes);
+    jmd->JackMidiWrite(nframes);
+
+    return (0);
+}
+
+static void JackMidiShutdown(void *arg)
+{
+    // TODO: support translations here
+    const QString mess_short = "JACK server down";
+    const QString mess_long = "The JACK server seems to have been shutdown.";
+    QMessageBox::information( engine::mainWindow(), mess_short, mess_long );
+}
+
+
+MidiJack::MidiJack() :
+    MidiClientRaw(),
+    m_input_port( NULL ),
+    m_output_port( NULL ),
+    m_quit( false )
+{
+    m_jack_client = jack_client_open(probeDevice().toLatin1().data(),
+                                     JackNoStartServer, NULL);
+
+    if(m_jack_client)
+    {
+        jack_set_process_callback(m_jack_client,
+                JackMidiProcessCallback, this);
+
+        jack_on_shutdown(m_jack_client,
+                JackMidiShutdown, 0);
+
+        m_output_port = jack_port_register(
+                m_jack_client, "midi_TX", JACK_DEFAULT_MIDI_TYPE,
+                JackPortIsOutput, 0);
+
+        m_input_port = jack_port_register(
+                m_jack_client, "midi_RX", JACK_DEFAULT_MIDI_TYPE,
+                JackPortIsInput, 0);
+
+        if(jack_activate(m_jack_client) == 0 )
+        {
+            // only start thread, if we are an active jack client.
+            start( QThread::LowPriority );
+        }
+    }
+}
+
+MidiJack::~MidiJack()
+{
+    if(m_jack_client)
+    {
+        if( jack_port_unregister( m_jack_client, m_input_port) != 0){
+            printf("Failed to unregister jack midi input\n");
+        }
+
+        if( jack_port_unregister( m_jack_client, m_output_port) != 0){
+            printf("Failed to unregister jack midi output\n");
+        }
+
+        if( jack_deactivate(m_jack_client) != 0){
+            printf("Failed to deactivate jack midi client\n");
+        }
+
+        if( jack_client_close(m_jack_client) != 0){
+            printf("Failed close jack midi client\n");
+        }
+    }
+    if( isRunning() )
+    {
+        m_quit = true;
+        wait( 1000 );
+        terminate();
+    }
+}
+
+QString MidiJack::probeDevice()
+{
+    QString jid = configManager::inst()->value( "midijack", "lmms" );
+    if( jid.isEmpty() )
+    {
+        return "lmms";
+    }
+    return jid;
+}
+
+void MidiJack::sendByte( const Uint8 _c )
+{
+    //m_midiDev.putChar( _c );
+}
+
+// we read data from jack
+void MidiJack::JackMidiRead(jack_nframes_t nframes)
+{
+    unsigned int i,b;
+    void* port_buf = jack_port_get_buffer(m_input_port, nframes);
+    jack_midi_event_t in_event;
+    jack_nframes_t event_index = 0;
+    jack_nframes_t event_count = jack_midi_get_event_count(port_buf);
+
+    jack_midi_event_get(&in_event, port_buf, 0);
+    for(i=0; i<nframes; i++)
+    {
+        if((in_event.time == i) && (event_index < event_count))
+        {
+            // lmms is setup to parse bytes coming from a device
+            // parse it byte by byte as it expects
+            for(b=0;b<in_event.size;b++)
+                parseData( *(in_event.buffer + b) );
+
+            event_index++;
+            if(event_index < event_count)
+                jack_midi_event_get(&in_event, port_buf, event_index);
+        }
+    }
+}
+
+// we write data to jack
+void MidiJack::JackMidiWrite(jack_nframes_t nframes)
+{
+    // TODO: write midi data to jack port
+}
+
+void MidiJack::run()
+{
+    while( m_quit == false )
+    {
+        // we sleep the thread to keep it alive
+        // midi processing is handled by jack server callbacks
+        sleep(1);
+    }
+}
+
+MidiJack::setupWidget::setupWidget( QWidget * _parent ) :
+    MidiClientRaw::setupWidget( MidiJack::name(), _parent )
+{
+    m_device = new QLineEdit( MidiJack::probeDevice(), this );
+    m_device->setGeometry( 10, 20, 180, 20 );
+    QDirModel * model = new QDirModel( QStringList(),
+            QDir::AllDirs | QDir::System,
+            QDir::Name | QDir::DirsFirst,
+            this );
+    m_device->setCompleter(    new QCompleter( model, this ) );
+
+
+    QLabel * dev_lbl = new QLabel( tr( "CLIENT-NAME" ), this );
+    dev_lbl->setFont( pointSize<6>( dev_lbl->font() ) );
+    dev_lbl->setGeometry( 10, 40, 180, 10 );
+}
+
+MidiJack::setupWidget::~setupWidget()
+{
+}
+
+void MidiJack::setupWidget::saveSettings()
+{
+    configManager::inst()->setValue( "midijack", "lmms",
+                            m_device->text() );
+}
+
+#endif // LMMS_HAVE_JACK
diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp
index bdb955d..77af2e1 100644
--- a/src/core/mixer.cpp
+++ b/src/core/mixer.cpp
@@ -52,6 +52,7 @@
 // platform-specific midi-interface-classes
 #include "MidiAlsaRaw.h"
 #include "MidiAlsaSeq.h"
+#include "MidiJack.h"
 #include "MidiOss.h"
 #include "MidiWinMM.h"
 #include "MidiDummy.h"
@@ -1129,6 +1130,19 @@ MidiClient * mixer::tryMidiClients()
        }
 #endif
 
+#ifdef LMMS_HAVE_JACK
+    if( client_name == MidiJack::name() || client_name == "" )
+    {
+        MidiJack * moss = new MidiJack;
+        if( moss->isRunning() )
+        {
+            m_midiClientName = MidiJack::name();
+            return moss;
+        }
+        delete moss;
+    }
+#endif
+
 #ifdef LMMS_HAVE_OSS
        if( client_name == MidiOss::name() || client_name == "" )
        {
diff --git a/src/gui/setup_dialog.cpp b/src/gui/setup_dialog.cpp
index b8f38f9..58f639b 100644
--- a/src/gui/setup_dialog.cpp
+++ b/src/gui/setup_dialog.cpp
@@ -60,6 +60,7 @@
 // platform-specific midi-interface-classes
 #include "MidiAlsaRaw.h"
 #include "MidiAlsaSeq.h"
+#include "MidiJack.h"
 #include "MidiOss.h"
 #include "MidiWinMM.h"
 #include "MidiDummy.h"
@@ -647,6 +648,11 @@ setupDialog::setupDialog( ConfigTabs _tab_to_open ) :
                                        new MidiAlsaRaw::setupWidget( msw );
 #endif
 
+#ifdef LMMS_HAVE_JACK
+    m_midiIfaceSetupWidgets[MidiJack::name()] =
+                    new MidiJack::setupWidget( msw );
+#endif
+
 #ifdef LMMS_HAVE_OSS
        m_midiIfaceSetupWidgets[MidiOss::name()] =
                                        new MidiOss::setupWidget( msw );
------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
LMMS-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/lmms-devel

Reply via email to