Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

-Initial Audio Recording implemented, using AudioQueue to transport a…

…udio to non-RT context, and create buffer & use it.
  • Loading branch information...
commit 07a29e709eda5ea4b1fbf2fde8353cead315ec45 1 parent cabcff1
Harry van Haaren authored
90 src/audioqueue.cpp
View
@@ -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 src/audioqueue.hpp
View
@@ -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 src/g_window.cpp
View
@@ -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();
@@ -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
@@ -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;
1  src/g_window.hpp
View
@@ -52,6 +52,7 @@ class Window
void setEffectsBox(int trackID);
GWaveView waveview;
+ GWaveView inputWaveview;
// helper functions
void redrawEffectBox();
17 src/jackclient.cpp
View
@@ -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();
@@ -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;
};
@@ -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 )
2  src/jackclient.hpp
View
@@ -47,6 +47,8 @@ class JackClient
JPort* apcInputPort;
JPort* apcOutputPort;
+ bool recordInput;
+
int trackControlMode;
void apcRead(int);
9 src/mixer.cpp
View
@@ -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 )
{
@@ -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
@@ -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
2  src/mixer.hpp
View
@@ -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;
1  src/top.cpp
View
@@ -22,4 +22,5 @@ Top::Top() :
void Top::initialize()
{
scopeVector.resize(bufferSize);
+ inputScopeVector.resize(bufferSize);
}
4 src/top.hpp
View
@@ -7,6 +7,7 @@
#include <glibmm.h>
#include "rtqueue.hpp"
+#include "audioqueue.hpp"
#include "statestore.hpp"
@@ -31,6 +32,7 @@ class Top
Glib::Mutex scopeVectorMutex;
std::vector<float> scopeVector;
+ std::vector<float> inputScopeVector;
Controller* controller;
OfflineWorker* offlineWorker;
@@ -42,6 +44,8 @@ class Top
RtQueue toEngineQueue;
RtQueue toEngineEmptyEventQueue;
+
+ AudioQueue recordAudioQueue;
};
#endif
1  wscript
View
@@ -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',
Please sign in to comment.
Something went wrong with that request. Please try again.