Use stereo input and stereo audio buffer
This commit is contained in:
parent
6e8687592b
commit
59b146f052
11 changed files with 107 additions and 53 deletions
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include "audiobuffer.hxx"
|
||||
#include "config.hxx"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -31,7 +32,8 @@ AudioBuffer::AudioBuffer(unsigned long size)
|
|||
// FIXME recorded buffers don't get an ID, using garbage IDs
|
||||
/// no ID assigned: it *takes* the one from the previous buffer!
|
||||
init();
|
||||
buffer.resize(size);
|
||||
bufferL.resize(size);
|
||||
bufferR.resize(size);
|
||||
}
|
||||
|
||||
void AudioBuffer::init()
|
||||
|
@ -98,18 +100,32 @@ long AudioBuffer::getAudioFrames()
|
|||
return audioFrames;
|
||||
}
|
||||
|
||||
std::vector<float>& AudioBuffer::getData()
|
||||
long AudioBuffer::getSize()
|
||||
{
|
||||
return buffer;
|
||||
if(bufferL.size() != bufferR.size()) {
|
||||
LUPPP_WARN("left and right channels of audio buffer have different size: %i vs %i", bufferL.size(), bufferR.size() );
|
||||
}
|
||||
return std::min(bufferL.size(), bufferR.size());
|
||||
}
|
||||
|
||||
void AudioBuffer::nonRtSetSample(std::vector<float>& sample)
|
||||
std::vector<float>& AudioBuffer::getDataL()
|
||||
{
|
||||
buffer.swap(sample);
|
||||
return bufferL;
|
||||
}
|
||||
std::vector<float>& AudioBuffer::getDataR()
|
||||
{
|
||||
return bufferR;
|
||||
}
|
||||
|
||||
void AudioBuffer::nonRtSetSample(std::vector<float>& sampleL, std::vector<float>& sampleR)
|
||||
{
|
||||
bufferL.swap(sampleL);
|
||||
bufferR.swap(sampleR);
|
||||
}
|
||||
void AudioBuffer::nonRtResize(unsigned long size)
|
||||
{
|
||||
buffer.resize(size);
|
||||
bufferL.resize(size);
|
||||
bufferR.resize(size);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -52,9 +52,12 @@ public:
|
|||
|
||||
long getAudioFrames();
|
||||
|
||||
std::vector<float>& getData();
|
||||
long getSize();
|
||||
|
||||
void nonRtSetSample(std::vector<float>& sample);
|
||||
std::vector<float>& getDataL();
|
||||
std::vector<float>& getDataR();
|
||||
|
||||
void nonRtSetSample(std::vector<float>& sampleL, std::vector<float>& sampleR);
|
||||
|
||||
void nonRtResize(unsigned long size);
|
||||
|
||||
|
@ -72,7 +75,8 @@ protected:
|
|||
|
||||
char name[20];
|
||||
|
||||
std::vector<float> buffer;
|
||||
std::vector<float> bufferL;
|
||||
std::vector<float> bufferR;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,7 +28,8 @@ public:
|
|||
|
||||
enum BUFFER {
|
||||
// AUDIO
|
||||
MASTER_INPUT = 0,
|
||||
MASTER_INPUT_L = 0,
|
||||
MASTER_INPUT_R,
|
||||
|
||||
MASTER_OUT_L,
|
||||
MASTER_OUT_R,
|
||||
|
|
|
@ -237,7 +237,8 @@ int DiskReader::loadSample( int track, int scene, string path )
|
|||
/// create buffer, and set the data
|
||||
AudioBuffer* ab = new AudioBuffer();
|
||||
ab->setAudioFrames( buf.size() );
|
||||
ab->nonRtSetSample( buf );
|
||||
// TODO right (stereo)
|
||||
ab->nonRtSetSample( buf, buf );
|
||||
|
||||
//cout << "DiskReader::loadSample() " << path << endl;
|
||||
|
||||
|
|
|
@ -321,7 +321,8 @@ int DiskWriter::writeAudioBuffer(int track, int scene, AudioBuffer* ab,
|
|||
// FIXME: the size of the buffer is bigger than the audio contained in it:
|
||||
// calculate the length that needs saving using getBeats() * framesPerBeat
|
||||
if ( ab->getAudioFrames() > 0 )
|
||||
outfile.write( &ab->getData()[0], ab->getAudioFrames() );
|
||||
// TODO right (stereo)
|
||||
outfile.write( &ab->getDataL()[0], ab->getAudioFrames() );
|
||||
else {
|
||||
LUPPP_WARN("%s","Sample has zero samples");
|
||||
}
|
||||
|
|
|
@ -102,7 +102,8 @@ void AudioEditor::show( AudioBuffer* buf, bool modal )
|
|||
if ( !ab ) {
|
||||
LUPPP_WARN("called with ab == 0");
|
||||
} else {
|
||||
std::vector<float>& tmp = ab->getData();
|
||||
// TODO right (stereo)
|
||||
std::vector<float>& tmp = ab->getDataL();
|
||||
int size = tmp.size();
|
||||
waveform->setData( &tmp[0], size );
|
||||
|
||||
|
|
43
src/jack.cxx
43
src/jack.cxx
|
@ -109,11 +109,17 @@ Jack::Jack( std::string name ) :
|
|||
uiUpdateCounter = buffers.samplerate / 30;
|
||||
uiUpdateConstant = buffers.samplerate / 30;
|
||||
|
||||
masterInput = jack_port_register( client,
|
||||
"master_in",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsInput,
|
||||
0 );
|
||||
masterInputL = jack_port_register( client,
|
||||
"master_in_left",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsInput,
|
||||
0 );
|
||||
|
||||
masterInputR = jack_port_register( client,
|
||||
"master_in_right",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsInput,
|
||||
0 );
|
||||
|
||||
masterReturnL = jack_port_register( client,
|
||||
"master_return_left",
|
||||
|
@ -367,7 +373,8 @@ void Jack::unregisterMidiIO( MidiIO* mo )
|
|||
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_INPUT_L] = (float*)jack_port_get_buffer( masterInputL , nframes );
|
||||
buffers.audio[Buffers::MASTER_INPUT_R] = (float*)jack_port_get_buffer( masterInputR , nframes );
|
||||
buffers.audio[Buffers::MASTER_RETURN_L] = (float*)jack_port_get_buffer( masterReturnL , nframes );
|
||||
buffers.audio[Buffers::MASTER_RETURN_R] = (float*)jack_port_get_buffer( masterReturnR , nframes );
|
||||
buffers.audio[Buffers::HEADPHONES_OUT] = (float*)jack_port_get_buffer( headphonesPort , nframes );
|
||||
|
@ -469,7 +476,8 @@ void Jack::processFrames(int nframes)
|
|||
|
||||
/// mix input, reverb & post-sidechain in
|
||||
for(unsigned int i = 0; i < nframes; i++) {
|
||||
float input= buffers.audio[Buffers::MASTER_INPUT][i] * inputVol;
|
||||
float inputL = buffers.audio[Buffers::MASTER_INPUT_L][i] * inputVol;
|
||||
float inputR = buffers.audio[Buffers::MASTER_INPUT_R][i] * inputVol;
|
||||
|
||||
float L = buffers.audio[Buffers::MASTER_OUT_L][i];
|
||||
float R = buffers.audio[Buffers::MASTER_OUT_R][i];
|
||||
|
@ -478,19 +486,23 @@ void Jack::processFrames(int nframes)
|
|||
|
||||
if ( inputToMixEnable ) {
|
||||
// if sending to mix, scale by volume *and* by XSide send
|
||||
float tmp = input * inputToMixVol * (1-inputToXSideVol);
|
||||
L += tmp;
|
||||
R += tmp;
|
||||
float tmpL = inputL * inputToMixVol * (1-inputToXSideVol);
|
||||
float tmpR = inputR * inputToMixVol * (1-inputToXSideVol);
|
||||
L += tmpL;
|
||||
R += tmpR;
|
||||
}
|
||||
if ( inputToSendEnable ) {
|
||||
// post-mix-send amount: hence * inputToMixVol
|
||||
buffers.audio[Buffers::SEND][i] += input * inputToSendVol * inputToMixVol;
|
||||
// TODO input r (stereo send)
|
||||
buffers.audio[Buffers::SEND][i] += inputL * inputToSendVol * inputToMixVol;
|
||||
}
|
||||
if ( inputToKeyEnable ) {
|
||||
buffers.audio[Buffers::SIDECHAIN_KEY][i] += input;
|
||||
// TODO input r (stereo key)
|
||||
buffers.audio[Buffers::SIDECHAIN_KEY][i] += inputL;
|
||||
}
|
||||
|
||||
buffers.audio[Buffers::SIDECHAIN_SIGNAL][i] += input * inputToXSideVol;
|
||||
// TODO input r (stereo sidechain)
|
||||
buffers.audio[Buffers::SIDECHAIN_SIGNAL][i] += inputL * inputToXSideVol;
|
||||
|
||||
//compute master volume lag;
|
||||
if(fabs(masterVol-masterVolLag)>=fabs(masterVolDiff/10.0))
|
||||
|
@ -507,7 +519,7 @@ void Jack::processFrames(int nframes)
|
|||
|
||||
|
||||
/// db meter on master input & output
|
||||
inputMeter->process( nframes, buffers.audio[Buffers::MASTER_INPUT], buffers.audio[Buffers::MASTER_INPUT]);
|
||||
inputMeter->process( nframes, buffers.audio[Buffers::MASTER_INPUT_L], buffers.audio[Buffers::MASTER_INPUT_R]);
|
||||
masterMeter->process(nframes, buffers.audio[Buffers::JACK_MASTER_OUT_L], buffers.audio[Buffers::JACK_MASTER_OUT_R] );
|
||||
|
||||
if ( uiUpdateCounter > uiUpdateConstant ) {
|
||||
|
@ -541,7 +553,8 @@ void Jack::processFrames(int nframes)
|
|||
/// update buffers by nframes
|
||||
if(lastnframes+nframes<buffers.nframes) {
|
||||
lastnframes=nframes;
|
||||
buffers.audio[Buffers::MASTER_INPUT] = &buffers.audio[Buffers::MASTER_INPUT] [nframes];
|
||||
buffers.audio[Buffers::MASTER_INPUT_L] = &buffers.audio[Buffers::MASTER_INPUT_L][nframes];
|
||||
buffers.audio[Buffers::MASTER_INPUT_R] = &buffers.audio[Buffers::MASTER_INPUT_R][nframes];
|
||||
buffers.audio[Buffers::MASTER_RETURN_L] = &buffers.audio[Buffers::MASTER_RETURN_L][nframes];
|
||||
buffers.audio[Buffers::MASTER_RETURN_R] = &buffers.audio[Buffers::MASTER_RETURN_R][nframes];
|
||||
buffers.audio[Buffers::HEADPHONES_OUT] = &buffers.audio[Buffers::HEADPHONES_OUT] [nframes];
|
||||
|
|
|
@ -173,7 +173,8 @@ private:
|
|||
bool clientActive;
|
||||
int samplerate;
|
||||
|
||||
jack_port_t* masterInput;
|
||||
jack_port_t* masterInputL;
|
||||
jack_port_t* masterInputR;
|
||||
jack_port_t* masterOutputL;
|
||||
jack_port_t* masterOutputR;
|
||||
|
||||
|
|
|
@ -118,8 +118,9 @@ void Looper::process(unsigned int nframes, Buffers* buffers)
|
|||
}
|
||||
|
||||
// copy data from input buffer to recording buffer
|
||||
float* input = buffers->audio[Buffers::MASTER_INPUT];
|
||||
clips[clip]->record( nframes, input, 0 );
|
||||
float* inputL = buffers->audio[Buffers::MASTER_INPUT_L];
|
||||
float* inputR = buffers->audio[Buffers::MASTER_INPUT_R];
|
||||
clips[clip]->record( nframes, inputL, inputR);
|
||||
} else if ( clips[clip]->playing() ) {
|
||||
// copy data into tmpBuffer, then pitch-stretch into track buffer
|
||||
long targetFrames = clips[clip]->getBeats() * fpb;
|
||||
|
@ -130,11 +131,14 @@ void Looper::process(unsigned int nframes, Buffers* buffers)
|
|||
playSpeed = float(actualFrames) / targetFrames;
|
||||
}
|
||||
|
||||
// TODO stereo sends
|
||||
float* out = buffers->audio[Buffers::SEND_TRACK_0 + track];
|
||||
|
||||
for(unsigned int i = 0; i < nframes; i++ ) {
|
||||
// REFACTOR into system that is better than per sample function calls
|
||||
float tmp = clips[clip]->getSample(playSpeed);
|
||||
float tmpL = 0;
|
||||
float tmpR = 0;
|
||||
clips[clip]->getSample(playSpeed, &tmpL, &tmpR);
|
||||
|
||||
float deltaPitch = 12 * log ( playSpeed ) / log (2);
|
||||
semitoneShift = -deltaPitch;
|
||||
|
@ -143,9 +147,13 @@ void Looper::process(unsigned int nframes, Buffers* buffers)
|
|||
//FIXME: pitchShift adds delay even for playSpeed = 1.0!!
|
||||
//we should use something better (e.g librubberband)
|
||||
if(playSpeed!=1.0f)
|
||||
pitchShift( 1, &tmp, &out[i] );
|
||||
pitchShift( 1, &tmpL, &out[i] );
|
||||
// TODO stereo sends
|
||||
//pitchShift( 1, tmpR, &out[i] );
|
||||
else
|
||||
out[i]+=tmp;
|
||||
// TODO stereo sends
|
||||
out[i]+=tmpL;
|
||||
//outR[i]+=tmpR;
|
||||
}
|
||||
|
||||
//printf("Looper %i playing(), speed = %f\n", track, playSpeed );
|
||||
|
|
|
@ -121,7 +121,7 @@ void LooperClip::load( AudioBuffer* ab )
|
|||
jack->getControllerUpdater()->setTrackSceneProgress(track, scene, 0 );
|
||||
|
||||
// set the endpoint to the buffer's size
|
||||
_recordhead = _buffer->getData().size();
|
||||
_recordhead = _buffer->getSize();
|
||||
|
||||
#ifdef DEBUG_BUFFER
|
||||
char buffer [50];
|
||||
|
@ -134,8 +134,9 @@ void LooperClip::load( AudioBuffer* ab )
|
|||
void LooperClip::setRequestedBuffer( AudioBuffer* ab )
|
||||
{
|
||||
if ( _buffer ) {
|
||||
size_t size = _buffer->getData().size();
|
||||
memcpy( &ab->getData().at(0), &_buffer->getData().at(0), sizeof(float)*size);
|
||||
size_t size = _buffer->getSize();
|
||||
memcpy( &ab->getDataL().at(0), &_buffer->getDataL().at(0), sizeof(float)*size);
|
||||
memcpy( &ab->getDataR().at(0), &_buffer->getDataR().at(0), sizeof(float)*size);
|
||||
|
||||
ab->setID ( _buffer->getID() );
|
||||
ab->setBeats( _buffer->getBeats() );
|
||||
|
@ -153,10 +154,13 @@ void LooperClip::setRequestedBuffer( AudioBuffer* ab )
|
|||
|
||||
void LooperClip::recieveSaveBuffer( AudioBuffer* saveBuffer )
|
||||
{
|
||||
if ( saveBuffer->getData().size() >= _buffer->getData().at(0) ) {
|
||||
if ( saveBuffer->getSize() >= _buffer->getDataL().at(0) ||
|
||||
saveBuffer->getSize() >= _buffer->getDataR().at(0) ) {
|
||||
// copy current contents into save buffer,
|
||||
// getData() contains L and R buffer, so twice the size is needed
|
||||
size_t framesBySize = _buffer->getAudioFrames();
|
||||
memcpy( &saveBuffer->getData().at(0), &_buffer->getData().at(0), sizeof(float)*framesBySize);
|
||||
memcpy( &saveBuffer->getDataL().at(0), &_buffer->getDataL().at(0), sizeof(float)*framesBySize);
|
||||
memcpy( &saveBuffer->getDataR().at(0), &_buffer->getDataR().at(0), sizeof(float)*framesBySize);
|
||||
|
||||
saveBuffer->setID ( _buffer->getID() );
|
||||
saveBuffer->setBeats( _buffer->getBeats() );
|
||||
|
@ -189,11 +193,12 @@ void LooperClip::record(int count, float* L, float* R)
|
|||
{
|
||||
// write "count" samples into current buffer.
|
||||
if ( _buffer ) {
|
||||
size_t size = _buffer->getData().size();
|
||||
size_t size = _buffer->getSize();
|
||||
|
||||
for(int i = 0; i < count; i++) {
|
||||
if ( _recordhead < size ) {
|
||||
_buffer->getData().at( _recordhead ) = *L++;
|
||||
_buffer->getDataL().at( _recordhead ) = *L++;
|
||||
_buffer->getDataR().at( _recordhead ) = *R++;
|
||||
_recordhead++;
|
||||
} else {
|
||||
// break: this is *BAD*, audio data is lost but the buffer isn't here
|
||||
|
@ -218,7 +223,8 @@ void LooperClip::record(int count, float* L, float* R)
|
|||
unsigned long LooperClip::recordSpaceAvailable()
|
||||
{
|
||||
if ( _buffer )
|
||||
return _buffer->getData().size() - _recordhead;
|
||||
// getData() contains L and R buffer, so it is twice the size
|
||||
return _buffer->getSize() - _recordhead;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -226,7 +232,7 @@ unsigned long LooperClip::recordSpaceAvailable()
|
|||
size_t LooperClip::audioBufferSize()
|
||||
{
|
||||
if ( _buffer ) {
|
||||
return _buffer->getData().size();
|
||||
return _buffer->getSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -410,11 +416,11 @@ bool LooperClip::newBufferInTransit()
|
|||
return _newBufferInTransit;
|
||||
}
|
||||
|
||||
float LooperClip::getSample(float playSpeed)
|
||||
void LooperClip::getSample(float playSpeed, float* L, float* R)
|
||||
{
|
||||
if ( _buffer && _buffer->getData().size() > 0 ) {
|
||||
if ( _buffer && (_buffer->getSize() > 0)) {
|
||||
if ( _playhead >= _recordhead ||
|
||||
_playhead >= _buffer->getData().size() ||
|
||||
_playhead >= _buffer->getSize() ||
|
||||
_playhead < 0 ) {
|
||||
_playhead = 0;
|
||||
|
||||
|
@ -422,14 +428,16 @@ float LooperClip::getSample(float playSpeed)
|
|||
//writeToGuiRingbuffer( &e );
|
||||
}
|
||||
|
||||
std::vector<float>& v = _buffer->getData();
|
||||
float tmp = v.at(_playhead);
|
||||
std::vector<float>& vL = _buffer->getDataL();
|
||||
std::vector<float>& vR = _buffer->getDataR();
|
||||
*L = vL.at(_playhead);
|
||||
*R = vR.at(_playhead);
|
||||
_playhead +=playSpeed;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return 0.f;
|
||||
else {
|
||||
*L = 0.f;
|
||||
*R = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
float LooperClip::getProgress()
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
void load( AudioBuffer* ab );
|
||||
|
||||
/// audio functionality
|
||||
float getSample(float playSpeed);
|
||||
void getSample(float playSpeed, float* L, float* R);
|
||||
void record(int count, float* L, float* R);
|
||||
|
||||
/// TimeObserver override
|
||||
|
|
Loading…
Reference in a new issue