Loopp/src/jack.cxx

370 lines
11 KiB
C++
Raw Normal View History

2013-04-20 12:37:36 +02:00
#include "jack.hxx"
#include <sstream>
#include <cstring>
#include <iostream>
#include "audiobuffer.hxx"
2013-04-20 12:54:16 +02:00
#include "eventhandler.hxx"
2013-08-22 05:32:51 +02:00
#include "controller/guicontroller.hxx"
2013-04-20 12:37:36 +02:00
using namespace std;
int AudioBuffer::privateID = 0;
// static pointer from main.
extern Jack* jack;
2013-04-20 12:37:36 +02:00
extern int jackSamplerate;
2013-07-31 18:19:15 +02:00
Jack::Jack() :
2013-08-13 17:35:27 +02:00
client( jack_client_open ( "Luppp", JackNullOption , 0 , 0 ) ),
timeManager(),
2013-08-13 17:35:27 +02:00
controllerUpdater( new ControllerUpdater() ),
save( new Save() ),
2013-08-13 17:35:27 +02:00
clientActive(false)
2013-04-20 12:37:36 +02:00
{
jack = this;
// construct Observer classes here, not in the initializer list as the Jack*
// will be 0x0 until then.
metronome = new Metronome();
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 );
2013-04-20 12:37:36 +02:00
uiUpdateCounter = buffers.samplerate / 30;
uiUpdateConstant = buffers.samplerate / 30;
masterInput = jack_port_register( client,
"master_in",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput,
0 );
2013-07-31 12:34:28 +02:00
masterOutputL = jack_port_register( client,
"master_left",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput,
0 );
2013-07-31 12:34:28 +02:00
masterOutputR = jack_port_register( client,
"master_right",
2013-04-20 12:37:36 +02:00
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput,
0 );
masterMidiInput = jack_port_register( client,
"midi_in",
JACK_DEFAULT_MIDI_TYPE,
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 );
2013-08-16 13:50:31 +02:00
masterVol = 0.77;
/// prepare internal buffers
2013-08-16 00:03:14 +02:00
buffers.audio[Buffers::REVERB] = new float[ buffers.nframes ];
buffers.audio[Buffers::SIDECHAIN] = new float[ buffers.nframes ];
buffers.audio[Buffers::POST_SIDECHAIN] = new float[ buffers.nframes ];
buffers.audio[Buffers::MASTER_OUT_L] = new float[ buffers.nframes ];
buffers.audio[Buffers::MASTER_OUT_R] = new float[ buffers.nframes ];
2013-07-31 02:05:14 +02:00
for(int i = 0; i < NTRACKS; i++)
{
loopers.push_back( new Looper(i) );
2013-07-31 02:05:14 +02:00
trackOutputs.push_back( new TrackOutput(i, loopers.back() ) );
buffers.audio[Buffers::TRACK_0 + i] = new float[ buffers.nframes ];
timeManager.registerObserver( loopers.back() );
}
/// setup FX
reverb = new Reverb( buffers.samplerate );
reverb->dryWet( 1 );
sidechainGain = new SidechainGain( buffers.samplerate );
2013-08-15 18:18:03 +02:00
reverbMeter = new DBMeter( buffers.samplerate );
2013-07-31 02:43:24 +02:00
masterMeter = new DBMeter( buffers.samplerate );
/// setup JACK callbacks
2013-04-20 12:37:36 +02:00
if ( jack_set_process_callback( client,
static_process,
static_cast<void*>(this)) )
2013-04-20 12:37:36 +02:00
{
cerr << "Jack() error setting process callback" << endl;
}
if ( jack_set_timebase_callback(client,
0,
(JackTimebaseCallback)static_timebase,
static_cast<void*>(this)) )
{
cerr << "Jack() error setting timebase callback" << endl;
}
2013-04-20 12:37:36 +02:00
}
void Jack::activate()
{
/*
// move to "settings" class or so
Controller* c = new AkaiAPC();
controllerUpdater->registerController( c );
Controller* g = new LupppGUI();
controllerUpdater->registerController( g );
*/
// move to time class, get instantiate order right
//jack->getTimeManager()->registerObserver( metronome );
//jack->getTimeManager()->registerObserver( gridLogic );
2013-04-20 12:37:36 +02:00
jack_activate( client );
jack_transport_start(client);
2013-04-20 12:37:36 +02:00
}
TrackOutput* Jack::getTrackOutput(int t)
{
if ( t >= 0 && t < NTRACKS )
return trackOutputs.at(t);
#ifdef DEBUG_TRACKS
else
{
printf( "Jack::getTrackOutput() returning 0x0: invalid track requested!\n" );
}
#endif
return 0;
}
Looper* Jack::getLooper(int t)
{
if ( t >= 0 && t < NTRACKS )
return loopers.at(t);
#ifdef DEBUG_TRACKS
else
{
printf( "Jack::getLooper() returning 0x0: invalid track requested!\n" );
}
#endif
return 0;
}
void Jack::registerMidiObserver( MidiObserver* mo )
{
midiObservers.push_back( mo );
}
2013-04-20 12:37:36 +02:00
int Jack::process (jack_nframes_t nframes)
{
/// get buffers
2013-07-31 02:05:14 +02:00
buffers.audio[Buffers::MASTER_INPUT] = (float*)jack_port_get_buffer( masterInput , nframes );
2013-07-31 12:34:28 +02:00
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 );
2013-07-31 02:05:14 +02:00
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 );
memset( buffers.audio[Buffers::MASTER_OUT_L] , 0, sizeof(float) * nframes );
memset( buffers.audio[Buffers::MASTER_OUT_R] , 0, sizeof(float) * nframes );
2013-07-31 02:05:14 +02:00
memset( buffers.audio[Buffers::REVERB] , 0, sizeof(float) * nframes );
memset( buffers.audio[Buffers::SIDECHAIN] , 0, sizeof(float) * nframes );
memset( buffers.audio[Buffers::POST_SIDECHAIN] , 0, sizeof(float) * nframes );
2013-08-12 20:01:47 +02:00
jack_midi_clear_buffer( buffers.midi[Buffers::APC_OUTPUT] );
2013-05-18 21:33:13 +02:00
/// do events from the ringbuffer
handleDspEvents();
/// process incoming MIDI
jack_midi_event_t in_event;
int masterMidiInputIndex = 0;
int event_count = (int) jack_midi_get_event_count( buffers.midi[Buffers::MASTER_MIDI_INPUT] );
while ( masterMidiInputIndex < event_count )
{
jack_midi_event_get(&in_event, buffers.midi[Buffers::MASTER_MIDI_INPUT], masterMidiInputIndex);
char buffer [50];
sprintf (buffer, "MIDI %i %i %i", int(in_event.buffer[0]), int(in_event.buffer[1]), int(in_event.buffer[2]) );
EventGuiPrint e( buffer );
writeToGuiRingbuffer( &e );
// run each event trought the midiObservers vector
2013-08-13 17:35:27 +02:00
for(unsigned int i = 0; i < midiObservers.size(); i++ )
{
midiObservers.at(i)->midi( (unsigned char*) &in_event.buffer[0] );
}
masterMidiInputIndex++;
}
2013-04-20 12:37:36 +02:00
/// process each track, starting at output and working up signal path
2013-08-13 17:35:27 +02:00
for(unsigned int i = 0; i < NTRACKS; i++)
2013-07-31 02:05:14 +02:00
{
2013-07-31 02:43:24 +02:00
trackOutputs.at(i)->process( nframes, &buffers );
2013-07-31 02:05:14 +02:00
}
/// process reverb
float* buf[] = {
buffers.audio[Buffers::REVERB],
buffers.audio[Buffers::REVERB]
};
//if ( reverb->getActive() )
2013-07-31 12:34:28 +02:00
{
reverbMeter->process(nframes, buffers.audio[Buffers::REVERB], buffers.audio[Buffers::REVERB] );
reverb->process( nframes, &buf[0], &buf[0] );
2013-07-31 12:34:28 +02:00
}
2013-08-13 01:41:17 +02:00
/// process sidechain gaining
float* sidechainBuf[] = {
// input
buffers.audio[Buffers::MASTER_OUT_L],
buffers.audio[Buffers::MASTER_OUT_R],
buffers.audio[Buffers::SIDECHAIN],
// output
buffers.audio[Buffers::MASTER_OUT_L],
buffers.audio[Buffers::MASTER_OUT_R]
};
2013-08-13 01:41:17 +02:00
sidechainGain->process( nframes, &sidechainBuf[0], &sidechainBuf[3] );
/// metro signal after sidechain-gain, so its loud on the beats
metronome->process( nframes, &buffers );
/// mix reverb & post-sidechain in
for(unsigned int i = 0; i < buffers.nframes; i++)
{
2013-08-16 13:50:31 +02:00
float L = buffers.audio[Buffers::MASTER_OUT_L][i];
float R = buffers.audio[Buffers::MASTER_OUT_R][i];
float rev = buffers.audio[Buffers::REVERB][i];
float post = buffers.audio[Buffers::POST_SIDECHAIN][i];
2013-08-16 13:50:31 +02:00
buffers.audio[Buffers::MASTER_OUT_L][i] = (L + rev + post) * masterVol;
buffers.audio[Buffers::MASTER_OUT_R][i] = (R + rev + post) * masterVol;
}
/// db meter on master
masterMeter->process(nframes, buffers.audio[Buffers::MASTER_OUT_L], buffers.audio[Buffers::MASTER_OUT_R] );
if ( uiUpdateCounter > uiUpdateConstant )
{
EventTrackSignalLevel e(-1, masterMeter->getLeftDB(), masterMeter->getRightDB() );
writeToGuiRingbuffer( &e );
2013-08-13 01:41:17 +02:00
uiUpdateCounter = 0;
}
uiUpdateCounter += nframes;
// memcpy the internal MASTER_OUTPUT buffer to the JACK_MASTER_OUTPUT
2013-07-31 12:34:28 +02:00
memcpy( buffers.audio[Buffers::JACK_MASTER_OUT_L],
buffers.audio[Buffers::MASTER_OUT_L],
//buffers.audio[Buffers::TRACK_7],
2013-07-31 12:34:28 +02:00
sizeof(float)*nframes);
memcpy( buffers.audio[Buffers::JACK_MASTER_OUT_R],
buffers.audio[Buffers::MASTER_OUT_R],
//buffers.audio[Buffers::POST_SIDECHAIN],
//buffers.audio[Buffers::REVERB], // uncomment to listen to reverb send only
sizeof(float)*nframes);
2013-04-20 12:37:36 +02:00
return false;
}
2013-07-31 12:34:28 +02:00
void Jack::setReverb( bool a, float d, float s )
{
2013-08-15 18:18:03 +02:00
//reverb->setActive( a );
2013-07-31 12:34:28 +02:00
reverb->damping( d );
reverb->rt60( d );
}
2013-04-20 12:37:36 +02:00
int Jack::getBuffersize()
{
return jack_get_buffer_size( client );
}
int Jack::getSamplerate()
{
return jack_get_sample_rate( client );
}
void Jack::writeApcOutput( unsigned char* data )
{
2013-09-06 00:45:06 +02:00
// 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];
unsigned char* buf = jack_midi_event_reserve( apcOutput, 0, 3);
2013-05-18 21:33:13 +02:00
if( buf != 0 )
{
memcpy( buf, data, sizeof( unsigned char ) * 3);
2013-07-25 15:37:55 +02:00
//cout << "writeApcOutput " << int(buf[0]) << ", " << int(buf[1]) << ", " << int(buf[2]) << endl;
}
else
{
EventGuiPrint e( "Jack::writeApcOutput(): Buffer full!" );
writeToGuiRingbuffer( &e );
}
}
int Jack::timebase(jack_transport_state_t state,
jack_nframes_t nframes,
jack_position_t* pos,
int newPos)
2013-04-20 12:37:36 +02:00
{
// fill buffers with data, then pass to timeManager
buffers.transportFrame = jack_get_current_transport_frame(client);
2013-05-15 03:04:39 +02:00
buffers.transportPosition = pos;
buffers.transportState =&state;
// update "time" from JACK master, or write master?
timeManager.process( &buffers );
2013-04-20 12:37:36 +02:00
return 0;
}
int Jack::static_process(jack_nframes_t nframes, void *instance)
{
return static_cast<Jack*>(instance)->process(nframes);
}
int Jack::static_timebase(jack_transport_state_t state,
jack_nframes_t nframes,
jack_position_t* pos,
int newPos,
void* instance)
{
return static_cast<Jack*>(instance)->timebase(state,nframes, pos, newPos );
}