-MidiObserver MIDI handling update, now registers custom MIDI port and interacts just with that. Scales to multiple controllers

This commit is contained in:
Harry van Haaren 2013-09-06 14:05:57 +01:00
parent 9fbca5146a
commit c9bbc9bb48
6 changed files with 109 additions and 40 deletions

View file

@ -16,15 +16,17 @@ AkaiAPC::AkaiAPC() :
footpedalTrack(0),
footpedalScene(0)
{
_port = port();
}
void AkaiAPC::recordArm(int t, bool enabled)
{
unsigned char data[3];
data[0] = 144 + t;
data[1] = 48; // record enable LED
data[2] = enabled ? 127 : 0;
jack->writeApcOutput( &data[0] );
jack->midiObserverWriteMIDI( _port, &data[0] );
}
void AkaiAPC::progress(int t, int s, float f)
@ -34,7 +36,7 @@ void AkaiAPC::progress(int t, int s, float f)
data[0] = 176;
data[1] = 48; // record enable LED
data[2] = 127 * f;
jack->writeApcOutput( &data[0] );
jack->midiObserverWriteMIDI( _port, &data[0] );
*/
}
@ -67,7 +69,7 @@ void AkaiAPC::trackSend(int t, int send, float v)
data[2] = 127 * v;
}
jack->writeApcOutput( &data[0] );
jack->midiObserverWriteMIDI( _port, &data[0] );
}
void AkaiAPC::setSceneState(int t, int clip, GridLogic::State s)
@ -87,7 +89,7 @@ void AkaiAPC::setSceneState(int t, int clip, GridLogic::State s)
case GridLogic::STATE_STOP_QUEUED: data[2] = 6; break;
}
jack->writeApcOutput( &data[0] );
jack->midiObserverWriteMIDI( _port, &data[0] );
}
void AkaiAPC::launchScene( int s )
@ -99,13 +101,13 @@ void AkaiAPC::launchScene( int s )
data[0] = 128;
data[1] = 82 + i; // scene play
data[2] = 0;
jack->writeApcOutput( &data[0] );
jack->midiObserverWriteMIDI( _port, &data[0] );
}
data[0] = 144;
data[1] = 82 + s;
data[2] = 127;
jack->writeApcOutput( &data[0] );
jack->midiObserverWriteMIDI( _port, &data[0] );
}
void AkaiAPC::mute(int t, bool b)
@ -225,6 +227,10 @@ void AkaiAPC::ccChange( int track, int cc, float value )
jack->getLogic()->trackVolume( -1, value );
break; }
/// X-Fader
case 15: {
jack->getTimeManager()->setBpm( 60 + value * 180 );
break; }
/// Device Control
case 16: {
@ -237,6 +243,7 @@ void AkaiAPC::ccChange( int track, int cc, float value )
jack->getLogic()->trackSend( track, SEND_REV, value );
break; }
case 64: { // FootSwitch 1
if ( value > 0.5 )
{
@ -294,6 +301,6 @@ void AkaiAPC::reset()
data[0] = 176 + i;
data[1] = 0x19;
data[2] = 2;
jack->writeApcOutput( &data[0] );
jack->midiObserverWriteMIDI( _port, &data[0] );
}
}

View file

@ -30,6 +30,8 @@ class AkaiAPC : public Controller, public MidiObserver
void midi(unsigned char* data);
private:
int _port;
bool shiftPressed;
int footpedalTrack;

View file

@ -32,9 +32,6 @@ Jack::Jack() :
logic = new Logic();
gridLogic = new GridLogic();
Controller* c = new AkaiAPC();
Controller* g = new LupppGUI();
buffers.nframes = jack_get_buffer_size( client );
buffers.samplerate = jack_get_sample_rate( client );
@ -66,18 +63,6 @@ Jack::Jack() :
JackPortIsInput,
0 );
apcMidiInput = jack_port_register( client,
"apc_in",
JACK_DEFAULT_MIDI_TYPE,
JackPortIsInput,
0 );
apcMidiOutput = jack_port_register( client,
"apc_out",
JACK_DEFAULT_MIDI_TYPE,
JackPortIsOutput,
0 );
masterVol = 0.77;
/// prepare internal buffers
@ -128,6 +113,9 @@ Jack::Jack() :
void Jack::activate()
{
Controller* c = new AkaiAPC();
Controller* g = new LupppGUI();
/*
// move to "settings" class or so
Controller* c = new AkaiAPC();
@ -175,9 +163,39 @@ Looper* Jack::getLooper(int t)
}
void Jack::registerMidiObserver( MidiObserver* mo )
void Jack::registerMidiObserver( MidiObserver* mo, std::string name )
{
cout << "Jack::registerMidiObserver() " << name << endl;
// register the observer
midiObservers.push_back( mo );
//set the index of the MIDI controller port on the MidiObserver
midiObservers.back()->port( midiObservers.size() - 1 );
// register new MIDI I/O ports for this controller
stringstream s;
s << name << "_in";
jack_port_t* tmp = jack_port_register(client,
s.str().c_str(),
JACK_DEFAULT_MIDI_TYPE,
JackPortIsInput,
0 );
midiObserverInputBuffers.push_back( 0 );
midiObserverInputPorts.push_back( tmp );
stringstream s2;
s2 << name << "_out";
cout << s2.str() << endl;
tmp = jack_port_register( client,
s2.str().c_str(),
JACK_DEFAULT_MIDI_TYPE,
JackPortIsOutput,
0 );
midiObserverOutputBuffers.push_back( 0 );
midiObserverOutputPorts.push_back( tmp );
}
@ -189,8 +207,6 @@ int Jack::process (jack_nframes_t nframes)
buffers.audio[Buffers::JACK_MASTER_OUT_L] = (float*)jack_port_get_buffer( masterOutputL , nframes );
buffers.audio[Buffers::JACK_MASTER_OUT_R] = (float*)jack_port_get_buffer( masterOutputR , nframes );
buffers.midi [Buffers::MASTER_MIDI_INPUT] = (void*) jack_port_get_buffer( masterMidiInput, nframes );
buffers.midi [Buffers::APC_INPUT] = (void*) jack_port_get_buffer( apcMidiInput , nframes );
buffers.midi [Buffers::APC_OUTPUT] = (void*) jack_port_get_buffer( apcMidiOutput , nframes );
memset( buffers.audio[Buffers::JACK_MASTER_OUT_L] , 0, sizeof(float) * nframes );
memset( buffers.audio[Buffers::JACK_MASTER_OUT_R] , 0, sizeof(float) * nframes );
@ -200,8 +216,6 @@ int Jack::process (jack_nframes_t nframes)
memset( buffers.audio[Buffers::SIDECHAIN] , 0, sizeof(float) * nframes );
memset( buffers.audio[Buffers::POST_SIDECHAIN] , 0, sizeof(float) * nframes );
jack_midi_clear_buffer( buffers.midi[Buffers::APC_OUTPUT] );
/// do events from the ringbuffer
handleDspEvents();
@ -218,15 +232,32 @@ int Jack::process (jack_nframes_t nframes)
EventGuiPrint e( buffer );
writeToGuiRingbuffer( &e );
// run each event trought the midiObservers vector
for(unsigned int i = 0; i < midiObservers.size(); i++ )
{
midiObservers.at(i)->midi( (unsigned char*) &in_event.buffer[0] );
}
masterMidiInputIndex++;
}
/// process each MidiObserver registered MIDI port
for(unsigned int i = 0; i < midiObservers.size(); i++ )
{
midiObserverInputBuffers.at( i ) =
(void*) jack_port_get_buffer( midiObserverInputPorts.at(i), nframes );
midiObserverOutputBuffers.at( i ) =
(void*) jack_port_get_buffer( midiObserverOutputPorts.at(i), nframes );
jack_midi_clear_buffer( midiObserverOutputBuffers.at( i ) );
jack_midi_event_t in_event;
int index = 0;
int event_count = (int) jack_midi_get_event_count( midiObserverInputBuffers.at( i ) );
while ( index < event_count )
{
jack_midi_event_get(&in_event, midiObserverInputBuffers.at( i ), index);
midiObservers.at(i)->midi( (unsigned char*) &in_event.buffer[0] );
printf( "APC MIDI %i %i %i\n", int(in_event.buffer[0]), int(in_event.buffer[1]), int(in_event.buffer[2]) );
index++;
}
}
/// process each track, starting at output and working up signal path
for(unsigned int i = 0; i < NTRACKS; i++)
{
@ -320,12 +351,12 @@ int Jack::getSamplerate()
return jack_get_sample_rate( client );
}
void Jack::writeApcOutput( unsigned char* data )
void Jack::midiObserverWriteMIDI( int portIndex, unsigned char* data )
{
// FIXME: MIDI output needs a QUEUE structure, so we can send more data to the APC "at once"
void* apcOutput = buffers.midi[Buffers::APC_OUTPUT];
void* portBuffer = midiObserverOutputBuffers.at(portIndex);
unsigned char* buf = jack_midi_event_reserve( apcOutput, 0, 3);
unsigned char* buf = jack_midi_event_reserve( portBuffer, 0, 3);
if( buf != 0 )
{
memcpy( buf, data, sizeof( unsigned char ) * 3);

View file

@ -52,15 +52,17 @@ class Jack
/// register MIDI observers: they're called when a MIDI message arrives on
/// a port they're watching
void registerMidiObserver( MidiObserver* mo );
void registerMidiObserver( MidiObserver* mo, std::string name );
/// writes MIDI messages to a MidiObserver's port
void midiObserverWriteMIDI( int portIndex, unsigned char* data );
void masterVolume( float vol ){masterVol = vol;}
/// sets reverb bus parameters
void setReverb( bool e, float d, float s );
/// writes MIDI messages to APC port
void writeApcOutput( unsigned char* data );
private:
jack_client_t* client;
@ -75,7 +77,13 @@ class Jack
vector<Looper*> loopers;
vector<TrackOutput*> trackOutputs;
// FIXME: refactor MidiObserver ports / buffers into one class, single vector
vector<MidiObserver*> midiObservers;
vector<jack_port_t*> midiObserverInputPorts;
vector<jack_port_t*> midiObserverOutputPorts;
vector<void*> midiObserverInputBuffers;
vector<void*> midiObserverOutputBuffers;
// FX
Reverb* reverb;

View file

@ -7,5 +7,15 @@ extern Jack* jack;
MidiObserver::MidiObserver( std::string portName )
{
jack->registerMidiObserver( this );
jack->registerMidiObserver( this, portName );
}
void MidiObserver::port(int index)
{
portIndex = index;
}
int MidiObserver::port()
{
return portIndex;
}

View file

@ -20,6 +20,17 @@ class MidiObserver
/// gets called with each MIDI message from the controller. Deal with its
/// input here, and route to the appropriate function in Luppp
virtual void midi(unsigned char* data) = 0;
/// sets the port number for this instance. Used when writing MIDI messages
/// to identify the port, using Jack::midiObserverWriteMIDI()
void port(int index);
/// returns the port index to the subclass when needed
int port();
private:
int portIndex;
};
#endif // LUPPP_MIDI_OBSERVER_H