-Added Controller subfolder, working on MIDI mapping / binding and feedback functionality

main
Harry van Haaren 2013-05-18 19:52:12 +01:00
parent 6e861dd4c1
commit 370815e7aa
8 changed files with 123 additions and 20 deletions

View File

@ -12,13 +12,15 @@ class Buffers
{
memset( audio, 0, sizeof(float*)*2);
}
float* audio[2];
char* midi [1];
float* audio[32];
unsigned char* midi [32];
enum BUFFER {
MASTER_OUTPUT = 0,
MASTER_INPUT,
MASTER_MIDI_INPUT,
APC_INPUT,
APC_OUTPUT,
};
// Jack details

0
src/controller/apc.cxx Normal file
View File

22
src/controller/apc.hxx Normal file
View File

@ -0,0 +1,22 @@
#ifndef LUPPP_APC_H
#define LUPPP_APC_H
#include "controller.hxx"
class AkaiAPC : public Controller
{
public:
AkaiAPC();
void mute(int t, bool b);
void clip(int t, bool b);
void record(int t, bool b);
void volume(int t, float f);
};
#endif // LUPPP_APC_H

View File

@ -0,0 +1,21 @@
#ifndef LUPPP_CONTROLLER_H
#define LUPPP_CONTROLLER_H
class Controller
{
public:
Controller();
virtual ~Controller();
virtual void mute(int t, bool b);
virtual void clip(int t, bool b);
virtual void record(int t, bool b);
virtual void volume(int t, float f);
};
#endif // LUPPP_CONTROLLER_H

View File

@ -38,6 +38,18 @@ 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 );
if ( jack_set_process_callback( client,
static_process,
static_cast<void*>(this)) )
@ -79,7 +91,13 @@ int Jack::process (jack_nframes_t nframes)
// get buffers
buffers.audio[Buffers::MASTER_INPUT] = (float*)jack_port_get_buffer( masterInput , nframes);
buffers.audio[Buffers::MASTER_OUTPUT] = (float*)jack_port_get_buffer( masterOutput, nframes);
buffers.midi[Buffers::MASTER_MIDI_INPUT]= (char*) jack_port_get_buffer( masterMidiInput, nframes );
buffers.midi[Buffers::MASTER_MIDI_INPUT]= (unsigned char*) jack_port_get_buffer( masterMidiInput, nframes );
buffers.midi[Buffers::APC_INPUT] = (unsigned char*) jack_port_get_buffer( apcMidiInput , nframes );
buffers.midi[Buffers::APC_OUTPUT] = (unsigned char*) jack_port_get_buffer( apcMidiOutput , nframes );
// pre-zero output buffers
memset( buffers.audio[Buffers::MASTER_OUTPUT], 0, sizeof(float) * nframes );
jack_midi_clear_buffer( buffers.midi[Buffers::APC_OUTPUT] );
// process incoming MIDI
jack_midi_event_t in_event;
@ -95,14 +113,11 @@ int Jack::process (jack_nframes_t nframes)
// check each looper for MIDI match
for(int i = 0; i < loopers.size(); i++)
loopers.at(i)->midi( (char*)in_event.buffer );
loopers.at(i)->midi( (unsigned char*)&in_event.buffer[0] );
masterMidiInputIndex++;
}
// pre-zero output buffers
memset( buffers.audio[Buffers::MASTER_OUTPUT], 0, sizeof(float) * nframes );
for(uint i = 0; i < loopers.size(); i++)
loopers.at(i)->process( nframes, &buffers );
@ -132,6 +147,22 @@ int Jack::getSamplerate()
return jack_get_sample_rate( client );
}
void Jack::writeApcOutput( unsigned char* data )
{
void* apcOutput = buffers.midi[Buffers::APC_OUTPUT];
unsigned char* buf = jack_midi_event_reserve( apcOutput, 0, 3);
if( buf )
{
memcpy( buf, data, sizeof( unsigned char ) * 3);
}
else
{
EventGuiPrint e( "__FILE__ __LINE__ Buffer not valid" );
writeToGuiRingbuffer( &e );
}
}
int Jack::timebase(jack_transport_state_t state,
jack_nframes_t nframes,
jack_position_t* pos,

View File

@ -22,6 +22,8 @@
#include "metronome.hxx"
#include "timemanager.hxx"
#include "controller/apc.hxx"
using namespace std;
class Jack
@ -44,12 +46,16 @@ class Jack
Metronome* getMetronome(){return &metronome;}
TimeManager* getTimeManager(){return &timeManager;}
void writeApcOutput( unsigned char* data );
private:
Buffers buffers;
Metronome metronome;
TimeManager timeManager;
vector<Controller*> controllers;
vector<Looper*> loopers;
int nframes;
@ -61,6 +67,8 @@ class Jack
jack_port_t* masterInput;
jack_port_t* masterOutput;
jack_port_t* apcMidiInput;
jack_port_t* apcMidiOutput;
jack_port_t* masterMidiInput;
// JACK callbacks

View File

@ -37,8 +37,25 @@ Looper::Looper(int t) :
fRec0[i] = 0;
}
void Looper::midi(char* data)
void Looper::midi(unsigned char* data)
{
if ( data[0] - 144 == track )
{
switch ( data[1] )
{
case 48: setState( STATE_RECORD_QUEUED ); break;
case 53: setState( STATE_PLAY_QUEUED ); break;
case 52: setState( STATE_STOPPED ); break;
}
}
else if ( data[0] - 128 == track )
{
switch ( data[1] )
{
case 48: setState( STATE_STOP_QUEUED );
}
}
}
@ -49,15 +66,17 @@ void Looper::setState(State s)
stopRecordOnBar = true;
}
// ensure we're not setting eg PLAY_QUEUED, if we're already PLAYING
if ( static_cast<int>(s) != static_cast<int>(state) + 1)
state = s;
if (state == STATE_RECORD_QUEUED )
{
state = s;
if (state == STATE_RECORDING)
{
numBeats = 0;
}
numBeats = 0;
unsigned char data[3];
data[0] == 144 + track;
data[1] == 48; // record LED
data[2] == 127;
jack->writeApcOutput( &data[0] );
cout << "wrote to APC" << endl;
}
}
@ -146,7 +165,7 @@ void Looper::bar()
playPoint = 0;
endPoint = lastWrittenSampleIndex;
}
if ( state == STATE_RECORD_QUEUED && state != STATE_RECORDING )
if ( state == STATE_RECORD_QUEUED )
{
EventGuiPrint e( "Looper Q->Recording" );
writeToGuiRingbuffer( &e );
@ -156,7 +175,7 @@ void Looper::bar()
endPoint = 0;
lastWrittenSampleIndex = 0;
}
if ( state == STATE_PLAY_QUEUED && state != STATE_STOPPED )
if ( state == STATE_PLAY_QUEUED )
{
EventGuiPrint e( "Looper Q->Stopped" );
writeToGuiRingbuffer( &e );

View File

@ -24,7 +24,7 @@ class Looper : public Observer // for notifications
Looper(int t);
void midi(char* data);
void midi(unsigned char* data);
void bar();
void beat();
@ -37,7 +37,7 @@ class Looper : public Observer // for notifications
void process(int nframes, Buffers* buffers);
private:
int track;
const int track;
State state;
int fpb;