Skip to content

Commit

Permalink
-Initial Audio Recording implemented, using AudioQueue to transport a…
Browse files Browse the repository at this point in the history
…udio to non-RT context, and create buffer & use it.
  • Loading branch information
harryhaaren committed Dec 21, 2011
1 parent cabcff1 commit 07a29e7
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 6 deletions.
90 changes: 90 additions & 0 deletions src/audioqueue.cpp
@@ -0,0 +1,90 @@

#include "audioqueue.hpp"

using namespace std;

AudioQueue::AudioQueue()
{
//std::cout << "AudioQueue()" << std::flush;

// initialize the ringbuffer to 100 elements
buffer = jack_ringbuffer_create( 44100 * 100 * sizeof(float));

if ( buffer == 0 )
{
cout << "Error creating AudioQueue!" << endl;
}

// lock the buffer into memory
int res = jack_ringbuffer_mlock(buffer);
if ( res )
{
std::cout << "AudioQueue() Error locking memory!" << std::endl;
}

tempEvent = new float[100*44100];
}

void AudioQueue::push(int nframes, float* audioPointer)
{
unsigned int availableWrite = jack_ringbuffer_write_space(buffer);

if (availableWrite >= sizeof(float) * nframes )
{
unsigned int written = jack_ringbuffer_write( buffer, (const char*)audioPointer , sizeof(float) * nframes );

if (written != sizeof(float) * nframes )
{
std::cout << "AudioQueue::push() ERROR! didn't write full event!" << std::endl;
}
}
else
{
std::cout << "AudioQueue::push() ERROR! RingBuffer FULL! Skipping event..." <<std::endl;
}
}

int AudioQueue::writeSamplesTo(float *writeBuffer)
{
// check if there's anything to read
int availableRead = jack_ringbuffer_read_space(buffer);

cout << "AudioQueue::pull() availableRead = " << availableRead << " writeLocation " << writeBuffer << endl;

int returnValue = 0;

if ( availableRead >= (long)sizeof(float) )
{
// read from the buffer
int result = jack_ringbuffer_read(buffer, (char*)writeBuffer, sizeof(float) * availableRead);

if ( result != availableRead )
{
std::cout << "AudioQueue::pull() WARNING! didn't read all contents! Result = " << result << std::endl;
returnValue = -1;
}
}

// reset the buffer, so that we start writing @ the start again next time
jack_ringbuffer_reset(buffer);

// nothing available
return returnValue;
}

// this function checks if the GUI thread should push events to the Queue
// so that the JACK thread will always have blank EE*'s available
// it should *not* be used for any other purpose!
int AudioQueue::readSpaceAvailable()
{
int availableReadBytes = (int)jack_ringbuffer_read_space(buffer);
return availableReadBytes;
}


AudioQueue::~AudioQueue()
{
std::cout << "~AudioQueue()" << std::endl;
jack_ringbuffer_free(buffer);
}

29 changes: 29 additions & 0 deletions src/audioqueue.hpp
@@ -0,0 +1,29 @@

#ifndef LUPPP_AUDIOQUEUE
#define LUPPP_AUDIOQUEUE

#include <vector>
#include <string>
#include <iostream>

#include <cstring>
#include <jack/ringbuffer.h>

class AudioQueue
{
public:
AudioQueue();
~AudioQueue();

void push(int,float*);
int writeSamplesTo(float*);

int readSpaceAvailable();

protected:
jack_ringbuffer_t *buffer;
float* tempEvent;
};

#endif

45 changes: 45 additions & 0 deletions src/g_window.cpp
Expand Up @@ -47,6 +47,7 @@ Window::Window(Gtk::Main *k, Top* t)
window->set_title("Luppp 2.0");

refBuilder->get_widget("mainBox", mainBox);
mainBox->add( inputWaveview );
mainBox->add( waveview );
mainBox->show_all();

Expand Down Expand Up @@ -102,10 +103,12 @@ int Window::handleEvent()

top->scopeVectorMutex.lock();
{
inputWaveview.setSample( top->inputScopeVector );
waveview.setSample( top->scopeVector );
}
top->scopeVectorMutex.unlock();
waveview.redraw();
inputWaveview.redraw();


// loop over events queue, return when no events to process
Expand Down Expand Up @@ -155,6 +158,48 @@ int Window::handleEvent()
std::advance(i,e->ia);
(*i)->redraw();
}
else if ( e->type == EE_LOOPER_RECORD ) {
cout << "GUI: Looper Record event! t = " << e->ia << " value = " << e->ib << endl;
// we get a "record off" event, and then read *all* the contents of
// the ringbuffer into a AudioBuffer, load that into engine same as
// a file source, and finally set the BufferAudioSource to play back
// that bufferID trough the bufferAudioSourceState list in *engine* statestore
if ( e->ib == 0 )
{
// create new buffer, get pointer, read space, resize buffer
AudioBuffer* buffer = new AudioBuffer();
vector<float>* pntr = buffer->getPointer();
int readSpace = top->recordAudioQueue.readSpaceAvailable();
pntr->resize(readSpace);

cout << "AudioBuffer size before read: " << pntr->size() << flush;

// read from ringbuffer *directly* into AudioBuffer
top->recordAudioQueue.writeSamplesTo( &pntr->at(0) );

cout << " and after " << pntr->size() << endl;

// send new AudioBuffer event to engine State
EngineEvent* x = new EngineEvent();
x->setStateAudioBuffer( (void*) buffer);
top->toEngineQueue.push(x);

// send LooperLoad event
x = new EngineEvent();
x->looperLoad( e->ia, 0, buffer->getID() );
top->toEngineQueue.push(x);


cout << "read samples available " << readSpace << endl;
}

/*
guiState.trackoutputState.at(e->ia).rec = e->ib;
std::list<TrackOutput*>::iterator i = trackoutputList.begin();
std::advance(i,e->ia);
(*i)->redraw();
*/
}
else if ( e->type == EE_TRACK_SET_PAN ) {
std::cout << "Gui got pan " << e->fa << std::endl;
guiState.trackoutputState.at(e->ia).pan = e->fa;
Expand Down
1 change: 1 addition & 0 deletions src/g_window.hpp
Expand Up @@ -52,6 +52,7 @@ class Window
void setEffectsBox(int trackID);

GWaveView waveview;
GWaveView inputWaveview;

// helper functions
void redrawEffectBox();
Expand Down
17 changes: 13 additions & 4 deletions src/jackclient.cpp
Expand Up @@ -161,7 +161,8 @@ int JackClient::processRtQueue()

int JackClient::process(jack_nframes_t nframes)
{
float* outBuffer = (float*)jack_port_get_buffer (outputPort , nframes);
float* inBuffer = (float*)jack_port_get_buffer ( inputPort, nframes);
float* outBuffer = (float*)jack_port_get_buffer (outputPort, nframes);

processRtQueue();

Expand All @@ -170,7 +171,7 @@ int JackClient::process(jack_nframes_t nframes)
// handle incoming midi
processMidi(nframes);

mixer.process(nframes, outBuffer);
mixer.process(nframes, recordInput, inBuffer, outBuffer);

return true;
};
Expand Down Expand Up @@ -622,13 +623,21 @@ void JackClient::apcRead( int nframes )
{
int trackID = b1 - 144;
std::cout << "APC: REC on track " << trackID << " on!" << std::endl;
//lo_send( //lo_address_new(NULL, "14688") , "/luppp/track/record", "ii", trackID, 1 );
recordInput = true;

EngineEvent* x = top->toEngineEmptyEventQueue.pull();
x->setLooperRecord(trackID, true);
top->toGuiQueue.push(x);
}
else if ( b1 >= 128 && b1 < 128 + 16 ) // rec off
{
int trackID = b1 - 128;
std::cout << "APC: REC on track " << trackID << " off!" << std::endl;
//lo_send( //lo_address_new(NULL, "14688") , "/luppp/track/record", "ii", trackID, 0 );
recordInput = false;

EngineEvent* x = top->toEngineEmptyEventQueue.pull();
x->setLooperRecord(trackID, false);
top->toGuiQueue.push(x);
}
}
if ( b2 == 49 )
Expand Down
2 changes: 2 additions & 0 deletions src/jackclient.hpp
Expand Up @@ -47,6 +47,8 @@ class JackClient
JPort* apcInputPort;
JPort* apcOutputPort;

bool recordInput;

int trackControlMode;
void apcRead(int);

Expand Down
9 changes: 8 additions & 1 deletion src/mixer.cpp
Expand Up @@ -50,7 +50,7 @@ int Mixer::getEffectID(int track, int pos)
return -1;
}

void Mixer::process(int nframes, float* outBuffer)
void Mixer::process(int nframes,bool record, float* inBuffer, float* outBuffer)
{
if ( nframes > 1024 )
{
Expand All @@ -67,6 +67,12 @@ void Mixer::process(int nframes, float* outBuffer)

float* outPointer = &outputW[0];

if ( record ) // we push the audio data to a ringbuffer
{
cout << "writing to recordAudio ringbuffer!" << endl;
top->recordAudioQueue.push(nframes, inBuffer);
}

bool copyToScopeVector = top->scopeVectorMutex.trylock();

// now sum up the master output buffers and write them
Expand All @@ -79,6 +85,7 @@ void Mixer::process(int nframes, float* outBuffer)
{
// write master output value to scopeVector, to be shown in GUI
top->scopeVector.at(i) = *outPointer;
top->inputScopeVector.at(i) = *inBuffer++;
}

// write 0.f to buffer, and increment
Expand Down
2 changes: 1 addition & 1 deletion src/mixer.hpp
Expand Up @@ -25,7 +25,7 @@ class Mixer
// returns the UniqueID of an Effect in an AudioTrack
int getEffectID(int track, int pos);

void process( int nframes, float* outBuffer );
void process( int nframes, bool, float* inBuffer, float* outBuffer );

private:
Top* top;
Expand Down
1 change: 1 addition & 0 deletions src/top.cpp
Expand Up @@ -22,4 +22,5 @@ Top::Top() :
void Top::initialize()
{
scopeVector.resize(bufferSize);
inputScopeVector.resize(bufferSize);
}
4 changes: 4 additions & 0 deletions src/top.hpp
Expand Up @@ -7,6 +7,7 @@
#include <glibmm.h>

#include "rtqueue.hpp"
#include "audioqueue.hpp"

#include "statestore.hpp"

Expand All @@ -31,6 +32,7 @@ class Top

Glib::Mutex scopeVectorMutex;
std::vector<float> scopeVector;
std::vector<float> inputScopeVector;

Controller* controller;
OfflineWorker* offlineWorker;
Expand All @@ -42,6 +44,8 @@ class Top
RtQueue toEngineQueue;

RtQueue toEngineEmptyEventQueue;

AudioQueue recordAudioQueue;
};

#endif
1 change: 1 addition & 0 deletions wscript
Expand Up @@ -38,6 +38,7 @@ def build(ctx):
# ENGINE
engineList=['src/top.cpp',
'src/rtqueue.cpp',
'src/audioqueue.cpp',
'src/audiosource.cpp',
'src/audiobuffer.cpp',
'src/offlineworker.cpp',
Expand Down

0 comments on commit 07a29e7

Please sign in to comment.