Files
lmms/plugins/zynaddsubfx/remote_zynaddsubfx.cpp
Tobias Doerffel 9873b880e2 ZynAddSubFX: made MIDI pitch bend work
Always send MIDI pitch bend events to MIDI channel 0 for the time being.
Makes MIDI pitch wheel work with ZynAddSubFX.
2009-04-18 12:47:02 +02:00

384 lines
7.9 KiB
C++

/*
* remote_zynaddsubfx.cpp - ZynAddSubFX-embedding plugin
*
* Copyright (c) 2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* 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 <lmmsconfig.h>
#include <queue>
#define BUILD_REMOTE_PLUGIN_CLIENT
#include "engine.h"
#include "instrument_play_handle.h"
#include "note_play_handle.h"
#include "remote_plugin.h"
#include "remote_zynaddsubfx.h"
std::string __presets_dir;
#define main unused_main
#ifdef LMMS_BUILD_LINUX
#define ATOM(x) (x)
#endif
#include "src/main.C"
#undef main
#include <FL/x.H>
static pthread_t __gui_thread_handle;
static pthread_mutex_t __gui_mutex;
static std::queue<remotePluginClient::message> __gui_messages;
class remoteZynAddSubFX : public remotePluginClient
{
public:
remoteZynAddSubFX( int _shm_in, int _shm_out ) :
remotePluginClient( _shm_in, _shm_out )
{
for( int i = 0; i < NumKeys; ++i )
{
m_runningNotes[i] = 0;
}
setInputCount( 0 );
sendMessage( IdInitDone );
waitForMessage( IdInitDone );
}
virtual void updateSampleRate( void )
{
SAMPLE_RATE = sampleRate();
}
virtual void updateBufferSize( void )
{
SOUND_BUFFER_SIZE = bufferSize();
}
virtual bool processMessage( const message & _m )
{
bool gui_message = false;
switch( _m.id )
{
case IdQuit:
delete master;
break;
case IdShowUI:
case IdHideUI:
case IdLoadSettingsFromFile:
case IdLoadPresetFromFile:
gui_message = true;
break;
case IdSaveSettingsToFile:
{
char * name = strdup( _m.getString().c_str() );
master->saveXML( name );
free( name );
sendMessage( IdSaveSettingsToFile );
return true;
break;
}
case IdZasfPresetDirectory:
__presets_dir = _m.getString();
for( int i = 0; i < MAX_BANK_ROOT_DIRS; ++i )
{
if( config.cfg.bankRootDirList[i] == NULL )
{
config.cfg.bankRootDirList[i] = new char[MAX_STRING_SIZE];
strcpy(config.cfg.bankRootDirList[i], __presets_dir.c_str() );
break;
}
else if( strcmp( config.cfg.bankRootDirList[i],
__presets_dir.c_str() ) == 0 )
{
break;
}
}
break;
default:
return remotePluginClient::processMessage( _m );
}
if( gui_message )
{
pthread_mutex_lock( &__gui_mutex );
__gui_messages.push( _m );
pthread_mutex_unlock( &__gui_mutex );
}
return true;
}
virtual ~remoteZynAddSubFX()
{
}
// all functions are called while master->mutex is held
virtual void processMidiEvent( const midiEvent & _e,
const f_cnt_t /* _offset */ )
{
switch( _e.m_type )
{
case MidiNoteOn:
if( _e.velocity() > 0 )
{
if( _e.key() <= 0 || _e.key() >= 128 )
{
break;
}
if( m_runningNotes[_e.key()] > 0 )
{
master->NoteOff( 0, _e.key() );
}
++m_runningNotes[_e.key()];
master->NoteOn( 0, _e.key(),
_e.velocity() );
break;
}
case MidiNoteOff:
if( _e.key() <= 0 || _e.key() >= 128 )
{
break;
}
if( --m_runningNotes[_e.key()] <= 0 )
{
master->NoteOff( 0, _e.key() );
}
break;
case MidiPitchBend:
master->SetController( 0,
C_pitchwheel,
_e.m_data.m_param[0] +
_e.m_data.m_param[1]*128-8192 );
break;
default:
break;
}
}
virtual void process( const sampleFrame * _in, sampleFrame * _out )
{
REALTYPE outputl[SOUND_BUFFER_SIZE];
REALTYPE outputr[SOUND_BUFFER_SIZE];
master->AudioOut( outputl, outputr );
for( fpp_t f = 0; f < SOUND_BUFFER_SIZE; ++f )
{
_out[f][0] = outputl[f];
_out[f][1] = outputr[f];
}
}
private:
int m_runningNotes[NumKeys];
} ;
static remoteZynAddSubFX * __remote_zasf = NULL;
static int __exit = 0;
void * guiThread( void * )
{
int e;
ui = NULL;
while( !__exit )
{
if( ui )
{
Fl::wait( 0.1 );
}
else
{
#ifdef LMMS_BUILD_WIN32
Sleep( 100 );
#else
usleep( 100*1000 );
#endif
}
pthread_mutex_lock( &__gui_mutex );
while( __gui_messages.size() )
{
remotePluginClient::message m = __gui_messages.front();
__gui_messages.pop();
switch( m.id )
{
case IdShowUI:
// we only create GUI
if( !ui )
{
Fl::scheme( "plastic" );
ui = new MasterUI( master, &e );
}
ui->showUI();
ui->refresh_master_ui();
break;
case IdHideUI:
if( !ui ) break;
switch( config.cfg.UserInterfaceMode )
{
case 0:
ui->selectuiwindow->hide();
break;
case 1:
ui->masterwindow->hide();
break;
case 2:
ui->simplemasterwindow->hide();
break;
}
break;
case IdLoadSettingsFromFile:
{
char * f = strdup( m.getString().
c_str() );
pthread_mutex_lock( &master->mutex );
master->defaults();
master->loadXML( f );
pthread_mutex_unlock( &master->mutex );
master->applyparameters();
if( ui ) ui->refresh_master_ui();
unlink( f );
free( f );
pthread_mutex_lock( &master->mutex );
__remote_zasf->sendMessage(
IdLoadSettingsFromFile );
pthread_mutex_unlock( &master->mutex );
break;
}
case IdLoadPresetFromFile:
{
char * f = strdup( m.getString().
c_str() );
pthread_mutex_lock( &master->mutex );
const int npart = ui ?
ui->npartcounter->value()-1 : 0;
master->part[npart]->defaultsinstrument();
master->part[npart]->loadXMLinstrument( f );
pthread_mutex_unlock( &master->mutex );
master->applyparameters();
if( ui )
{
ui->npartcounter->do_callback();
ui->updatepanel();
ui->refresh_master_ui();
}
free( f );
pthread_mutex_lock( &master->mutex );
__remote_zasf->sendMessage(
IdLoadPresetFromFile );
pthread_mutex_unlock( &master->mutex );
break;
}
default:
break;
}
}
pthread_mutex_unlock( &__gui_mutex );
}
Fl::flush();
return NULL;
}
int main( int _argc, char * * _argv )
{
if( _argc < 3 )
{
fprintf( stderr, "not enough arguments\n" );
return( -1 );
}
#ifdef LMMS_BUILD_WIN32
// (non-portable) initialization of statically linked pthread library
pthread_win32_process_attach_np();
pthread_win32_thread_attach_np();
#endif
__remote_zasf = new remoteZynAddSubFX( atoi( _argv[1] ),
atoi( _argv[2] ) );
config.init();
OSCIL_SIZE = config.cfg.OscilSize;
config.cfg.GzipCompression = 0;
srand( time( NULL ) );
denormalkillbuf = new REALTYPE[SOUND_BUFFER_SIZE];
for( int i = 0; i < SOUND_BUFFER_SIZE; ++i )
{
denormalkillbuf[i] = (RND-0.5)*1e-16;
}
OscilGen::tmpsmps = new REALTYPE[OSCIL_SIZE];
newFFTFREQS( &OscilGen::outoscilFFTfreqs, OSCIL_SIZE/2 );
pthread_mutex_init( &__gui_mutex, NULL );
master = new Master();
master->swaplr = 0;
pthread_create( &__gui_thread_handle, NULL, guiThread, NULL );
remotePluginClient::message m;
while( ( m = __remote_zasf->receiveMessage() ).id != IdQuit )
{
pthread_mutex_lock( &master->mutex );
__remote_zasf->processMessage( m );
pthread_mutex_unlock( &master->mutex );
}
__exit = 1;
delete denormalkillbuf;
delete OscilGen::tmpsmps;
deleteFFTFREQS( &OscilGen::outoscilFFTfreqs );
pthread_mutex_destroy( &__gui_mutex );
#ifdef LMMS_BUILD_WIN32
pthread_win32_thread_detach_np();
pthread_win32_process_detach_np();
#endif
return 0;
}