Support for using jack midi input (#2038)
* Support jack midi input * If jack is used for audio then use the same connection for midi as well * Remove old FreeBSD adjustment for portaudio as multiple version support has been dropped. * Disable jack midi out port until it is functional
This commit is contained in:
committed by
Oskar Wallgren
parent
c9618961d6
commit
05ace7e348
@@ -84,6 +84,7 @@ set(LMMS_SRCS
|
||||
core/midi/MidiAlsaSeq.cpp
|
||||
core/midi/MidiClient.cpp
|
||||
core/midi/MidiController.cpp
|
||||
core/midi/MidiJack.cpp
|
||||
core/midi/MidiOss.cpp
|
||||
core/midi/MidiSndio.cpp
|
||||
core/midi/MidiApple.cpp
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
// platform-specific midi-interface-classes
|
||||
#include "MidiAlsaRaw.h"
|
||||
#include "MidiAlsaSeq.h"
|
||||
#include "MidiJack.h"
|
||||
#include "MidiOss.h"
|
||||
#include "MidiSndio.h"
|
||||
#include "MidiWinMM.h"
|
||||
@@ -975,6 +976,19 @@ MidiClient * Mixer::tryMidiClients()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LMMS_HAVE_JACK
|
||||
if( client_name == MidiJack::name() || client_name == "" )
|
||||
{
|
||||
MidiJack * mjack = new MidiJack;
|
||||
if( mjack->isRunning() )
|
||||
{
|
||||
m_midiClientName = MidiJack::name();
|
||||
return mjack;
|
||||
}
|
||||
delete mjack;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LMMS_HAVE_OSS
|
||||
if( client_name == MidiOss::name() || client_name == "" )
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "AudioPort.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
#include "MidiJack.h"
|
||||
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ AudioJack::AudioJack( bool & _success_ful, Mixer* _mixer ) :
|
||||
_mixer ),
|
||||
m_client( NULL ),
|
||||
m_active( false ),
|
||||
m_midiClient( NULL ),
|
||||
m_tempOutBufs( new jack_default_audio_sample_t *[channels()] ),
|
||||
m_outBuf( new surroundSampleFrame[mixer()->framesPerPeriod()] ),
|
||||
m_framesDoneInCurBuf( 0 ),
|
||||
@@ -123,7 +124,15 @@ void AudioJack::restartAfterZombified()
|
||||
|
||||
|
||||
|
||||
AudioJack* AudioJack::addMidiClient(MidiJack *midiClient)
|
||||
{
|
||||
if( m_client == NULL )
|
||||
return NULL;
|
||||
|
||||
m_midiClient = midiClient;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool AudioJack::initJackClient()
|
||||
{
|
||||
@@ -331,6 +340,14 @@ void AudioJack::renamePort( AudioPort * _port )
|
||||
|
||||
int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata )
|
||||
{
|
||||
// do midi processing first so that midi input can
|
||||
// add to the following sound processing
|
||||
if( m_midiClient && _nframes > 0 )
|
||||
{
|
||||
m_midiClient->JackMidiRead(_nframes);
|
||||
m_midiClient->JackMidiWrite(_nframes);
|
||||
}
|
||||
|
||||
for( int c = 0; c < channels(); ++c )
|
||||
{
|
||||
m_tempOutBufs[c] =
|
||||
|
||||
223
src/core/midi/MidiJack.cpp
Normal file
223
src/core/midi/MidiJack.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* MidiJack.cpp - MIDI client for Jack
|
||||
*
|
||||
* Copyright (c) 2015 Shane Ambler <develop/at/shaneware.biz>
|
||||
*
|
||||
* This file is part of LMMS - http://lmms.io
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "MidiJack.h"
|
||||
|
||||
#ifdef LMMS_HAVE_JACK
|
||||
|
||||
#include <QCompleter>
|
||||
#include <QDirModel>
|
||||
#include <QMessageBox>
|
||||
#include <QTranslator>
|
||||
|
||||
#ifdef LMMS_HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "ConfigManager.h"
|
||||
#include "gui_templates.h"
|
||||
#include "GuiApplication.h"
|
||||
#include "Engine.h"
|
||||
#include "Mixer.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( gui->mainWindow(), mess_short, mess_long );
|
||||
}
|
||||
|
||||
MidiJack::MidiJack() :
|
||||
MidiClientRaw(),
|
||||
m_input_port( NULL ),
|
||||
m_output_port( NULL ),
|
||||
m_quit( false )
|
||||
{
|
||||
// if jack is used for audio then we share the connection
|
||||
// AudioJack creates and maintains the jack connection
|
||||
// and also handles the callback, we pass it our address
|
||||
// so that we can also process during the callback
|
||||
|
||||
if(Engine::mixer()->audioDevName() == AudioJack::name() )
|
||||
{
|
||||
// if a jack connection has been created for audio we use that
|
||||
m_jackAudio = dynamic_cast<AudioJack*>(Engine::mixer()->audioDev())->addMidiClient(this);
|
||||
}else{
|
||||
m_jackAudio = NULL;
|
||||
m_jackClient = jack_client_open(probeDevice().toLatin1().data(),
|
||||
JackNoStartServer, NULL);
|
||||
|
||||
if(m_jackClient)
|
||||
{
|
||||
jack_set_process_callback(m_jackClient,
|
||||
JackMidiProcessCallback, this);
|
||||
jack_on_shutdown(m_jackClient,
|
||||
JackMidiShutdown, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(jackClient())
|
||||
{
|
||||
/* jack midi out not implemented
|
||||
JackMidiWrite and sendByte needs to be functional
|
||||
before enabling this
|
||||
m_output_port = jack_port_register(
|
||||
jackClient(), "MIDI out", JACK_DEFAULT_MIDI_TYPE,
|
||||
JackPortIsOutput, 0);
|
||||
*/
|
||||
|
||||
m_input_port = jack_port_register(
|
||||
jackClient(), "MIDI in", JACK_DEFAULT_MIDI_TYPE,
|
||||
JackPortIsInput, 0);
|
||||
|
||||
if(jack_activate(jackClient()) == 0 )
|
||||
{
|
||||
// only start thread, if we have an active jack client.
|
||||
start( QThread::LowPriority );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MidiJack::~MidiJack()
|
||||
{
|
||||
if(jackClient())
|
||||
{
|
||||
if( jack_port_unregister( jackClient(), m_input_port) != 0){
|
||||
printf("Failed to unregister jack midi input\n");
|
||||
}
|
||||
|
||||
if( jack_port_unregister( jackClient(), m_output_port) != 0){
|
||||
printf("Failed to unregister jack midi output\n");
|
||||
}
|
||||
|
||||
if(m_jackClient)
|
||||
{
|
||||
// an m_jackClient means we are handling the jack connection
|
||||
if( jack_deactivate(m_jackClient) != 0){
|
||||
printf("Failed to deactivate jack midi client\n");
|
||||
}
|
||||
|
||||
if( jack_client_close(m_jackClient) != 0){
|
||||
printf("Failed close jack midi client\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if( isRunning() )
|
||||
{
|
||||
m_quit = true;
|
||||
wait( 1000 );
|
||||
terminate();
|
||||
}
|
||||
}
|
||||
|
||||
jack_client_t* MidiJack::jackClient()
|
||||
{
|
||||
if( m_jackAudio == NULL && m_jackClient == NULL)
|
||||
return NULL;
|
||||
|
||||
if( m_jackAudio == NULL && m_jackClient )
|
||||
return m_jackClient;
|
||||
|
||||
return m_jackAudio->jackClient();
|
||||
}
|
||||
|
||||
QString MidiJack::probeDevice()
|
||||
{
|
||||
QString jid = ConfigManager::inst()->value( "midijack", "lmms" );
|
||||
if( jid.isEmpty() )
|
||||
{
|
||||
return "lmms";
|
||||
}
|
||||
return jid;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* jack midi out is not implemented
|
||||
sending plain bytes to jack midi outputs doesn't work
|
||||
once working the output port needs to be enabled in the constructor
|
||||
*/
|
||||
|
||||
void MidiJack::sendByte( const unsigned char c )
|
||||
{
|
||||
//m_midiDev.putChar( c );
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LMMS_HAVE_JACK
|
||||
@@ -65,6 +65,7 @@
|
||||
// platform-specific midi-interface-classes
|
||||
#include "MidiAlsaRaw.h"
|
||||
#include "MidiAlsaSeq.h"
|
||||
#include "MidiJack.h"
|
||||
#include "MidiOss.h"
|
||||
#include "MidiSndio.h"
|
||||
#include "MidiWinMM.h"
|
||||
@@ -862,6 +863,11 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
|
||||
MidiSetupWidget::create<MidiAlsaRaw>( msw );
|
||||
#endif
|
||||
|
||||
#ifdef LMMS_HAVE_JACK
|
||||
m_midiIfaceSetupWidgets[MidiJack::name()] =
|
||||
MidiSetupWidget::create<MidiJack>( msw );
|
||||
#endif
|
||||
|
||||
#ifdef LMMS_HAVE_OSS
|
||||
m_midiIfaceSetupWidgets[MidiOss::name()] =
|
||||
MidiSetupWidget::create<MidiOss>( msw );
|
||||
|
||||
Reference in New Issue
Block a user