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