Browse Source

More rename and fixes; Initial RtAudio MIDI code

tags/1.9.4
falkTX 11 years ago
parent
commit
5b98c24cac
12 changed files with 598 additions and 503 deletions
  1. +5
    -10
      source/backend/CarlaEngine.hpp
  2. +0
    -0
      source/backend/engine/CarlaEngine.pro
  3. +35
    -63
      source/backend/engine/CarlaEngineJack.cpp
  4. +0
    -0
      source/backend/engine/CarlaEnginePlugin.cpp
  5. +547
    -0
      source/backend/engine/CarlaEngineRtAudio.cpp
  6. +3
    -3
      source/backend/engine/Makefile
  7. +0
    -0
      source/backend/engine/distrho/DistrhoPluginInfo.h
  8. +0
    -421
      source/backend/engine/rtaudio.cpp
  9. +1
    -0
      source/backend/plugin/CarlaPluginInternal.hpp
  10. +2
    -1
      source/tests/ANSI.cpp
  11. +2
    -2
      source/tests/Makefile
  12. +3
    -3
      source/utils/CarlaUtils.hpp

+ 5
- 10
source/backend/CarlaEngine.hpp View File

@@ -836,6 +836,9 @@ public:
*/
float getOutputPeak(const unsigned int pluginId, const unsigned short id) const;

// FIXME - remove once IPC audio is implemented
void setPeaks(const unsigned int pluginId, float const inPeaks[MAX_PEAKS], float const outPeaks[MAX_PEAKS]);

// -------------------------------------------------------------------
// Callback

@@ -958,14 +961,6 @@ protected:
*/
void proccessPendingEvents();

/*!
* TODO.
*/
public:
// FIXME - remove once IPC audio is implemented
void setPeaks(const unsigned int pluginId, float const inPeaks[MAX_PEAKS], float const outPeaks[MAX_PEAKS]);

private:
#ifndef BUILD_BRIDGE
// Rack mode data
EngineEvent* getRackEventBuffer(const bool isInput);
@@ -999,8 +994,8 @@ private:
};

static CarlaEngine* newRtAudio(const RtAudioApi api);
static unsigned int getRtAudioApiCount();
static const char* getRtAudioApiName(unsigned int index);
static size_t getRtAudioApiCount();
static const char* getRtAudioApiName(const unsigned int index);
#endif

public:


source/backend/engine/carla_engine.pro → source/backend/engine/CarlaEngine.pro View File


source/backend/engine/jack.cpp → source/backend/engine/CarlaEngineJack.cpp View File

@@ -32,7 +32,7 @@ CARLA_BACKEND_START_NAMESPACE
#endif

// -------------------------------------------------------------------
// Helpers, defined in carla_plugin.cpp
// Helpers, defined in CarlaPlugin.cpp

extern CarlaEngine* CarlaPluginGetEngine(CarlaPlugin* const plugin);
extern CarlaEngineAudioPort* CarlaPluginGetAudioInPort(CarlaPlugin* const plugin, uint32_t index);
@@ -242,7 +242,7 @@ public:
fRetEvent.midi.data[0] = midiStatus;
fRetEvent.midi.data[1] = jackEvent.buffer[1];
fRetEvent.midi.data[2] = jackEvent.buffer[2];
fRetEvent.midi.size = jackEvent.size;
fRetEvent.midi.size = static_cast<uint8_t>(jackEvent.size);
}

return fRetEvent;
@@ -257,7 +257,8 @@ public:
CARLA_ASSERT(fJackBuffer != nullptr);
CARLA_ASSERT(type != kEngineControlEventTypeNull);
CARLA_ASSERT(channel < MAX_MIDI_CHANNELS);
CARLA_ASSERT(value >= 0.0 && value <= 1.0);
CARLA_ASSERT(param < MAX_MIDI_VALUE);
CARLA_SAFE_ASSERT(value >= 0.0 && value <= 1.0);

if (kIsInput)
return;
@@ -267,11 +268,15 @@ public:
return;
if (channel >= MAX_MIDI_CHANNELS)
return;
if (param >= MAX_MIDI_VALUE)
return;
if (type == kEngineControlEventTypeParameter)
{
CARLA_ASSERT(! MIDI_IS_CONTROL_BANK_SELECT(param));
}

const double fixedValue = carla_fixValue<double>(0.0, 1.0, value);

uint8_t data[3] = { 0 };
uint8_t size = 0;

@@ -281,19 +286,19 @@ public:
break;
case kEngineControlEventTypeParameter:
data[0] = MIDI_STATUS_CONTROL_CHANGE + channel;
data[1] = param;
data[2] = value * 127;
data[1] = static_cast<uint8_t>(param);
data[2] = uint8_t(fixedValue * 127.0);
size = 3;
break;
case kEngineControlEventTypeMidiBank:
data[0] = MIDI_STATUS_CONTROL_CHANGE + channel;
data[1] = MIDI_CONTROL_BANK_SELECT;
data[2] = param;
data[2] = static_cast<uint8_t>(param);
size = 3;
break;
case kEngineControlEventTypeMidiProgram:
data[0] = MIDI_STATUS_PROGRAM_CHANGE + channel;
data[1] = param;
data[1] = static_cast<uint8_t>(param);
size = 2;
break;
case kEngineControlEventTypeAllSoundOff:
@@ -467,7 +472,7 @@ public:
return new CarlaEngineJackEventPort(isInput, kProcessMode, kClient, port);
}

qCritical("CarlaEngineJackClient::addPort(%s, \"%s\", %s) - invalid type", EnginePortType2Str(portType), name, bool2str(isInput));
carla_stderr("CarlaEngineJackClient::addPort(%s, \"%s\", %s) - invalid type", EnginePortType2Str(portType), name, bool2str(isInput));
return nullptr;
}

@@ -481,21 +486,6 @@ private:
// -------------------------------------------------------------------------------------------------------------------
// Jack Engine

#if 0
struct EnginePluginData {
CarlaEngine* const engine;
CarlaPlugin* const plugin;

EnginePluginData(CarlaEngine* const engine_, CarlaPlugin* const plugin_)
: engine(engine_),
plugin(plugin_) {}

EnginePluginData() = delete;
EnginePluginData(EnginePlugin&) = delete;
EnginePluginData(const EnginePlugin&) = delete;
};
#endif

class CarlaEngineJack : public CarlaEngine
{
public:
@@ -530,9 +520,7 @@ public:

unsigned int maxClientNameSize()
{
#ifndef BUILD_BRIDGE
if (fOptions.processMode == PROCESS_MODE_SINGLE_CLIENT || fOptions.processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
#endif
return static_cast<unsigned int>(jackbridge_client_name_size());

return CarlaEngine::maxClientNameSize();
@@ -540,9 +528,7 @@ public:

unsigned int maxPortNameSize()
{
#ifndef BUILD_BRIDGE
if (fOptions.processMode == PROCESS_MODE_SINGLE_CLIENT || fOptions.processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
#endif
return static_cast<unsigned int>(jackbridge_port_name_size());

return CarlaEngine::maxPortNameSize();
@@ -563,7 +549,7 @@ public:
#ifndef BUILD_BRIDGE
fClient = jackbridge_client_open(clientName, JackNullOption, nullptr);

if (fClient)
if (fClient != nullptr)
{
fBufferSize = jackbridge_get_buffer_size(fClient);
fSampleRate = jackbridge_get_sample_rate(fClient);
@@ -587,14 +573,14 @@ public:

if (jackbridge_activate(fClient) == 0)
{
const char* const clientName = jackbridge_get_client_name(fClient);
const char* const jackClientName = jackbridge_get_client_name(fClient);

CarlaEngine::init(clientName);
return true;
return CarlaEngine::init(jackClientName);
}
else
{
setLastError("Failed to activate the JACK client");
jackbridge_client_close(fClient);
fClient = nullptr;
}
}
@@ -603,23 +589,19 @@ public:

return false;
#else
// open temp client to get initial buffer-size and sample-rate values
if (fBufferSize == 0 || fSampleRate == 0.0)
{
fClient = jackbridge_client_open(clientName, JackNullOption, nullptr);

if (fClient)
// open temp client to get initial buffer-size and sample-rate values
if (jack_client_t* tmpClient = jackbridge_client_open(clientName, JackNullOption, nullptr))
{
fBufferSize = jackbridge_get_buffer_size(fClient);
fSampleRate = jackbridge_get_sample_rate(fClient);
fBufferSize = jackbridge_get_buffer_size(tmpClient);
fSampleRate = jackbridge_get_sample_rate(tmpClient);

jackbridge_client_close(fClient);
fClient = nullptr;
jackbridge_client_close(tmpClient);
}
}

CarlaEngine::init(clientName);
return true;
return CarlaEngine::init(clientName);
#endif
}

@@ -709,11 +691,7 @@ public:
}
#endif

#ifdef BUILD_BRIDGE
return new CarlaEngineJackClient(kEngineTypeJack, PROCESS_MODE_MULTIPLE_CLIENTS, client);
#else
return new CarlaEngineJackClient(kEngineTypeJack, fOptions.processMode, client);
#endif
}

// -------------------------------------
@@ -746,11 +724,9 @@ protected:

void handleJackProcessCallback(const uint32_t nframes)
{
proccessPendingEvents();

#ifndef BUILD_BRIDGE
if (kData->curPluginCount == 0)
return;
return proccessPendingEvents();
#endif

fTransportPos.unique_1 = fTransportPos.unique_2 + 1; // invalidate
@@ -974,17 +950,15 @@ protected:
}
#endif
}
#endif
#endif // ! BUILD_BRIDGE

proccessPendingEvents();
}

void handleJackLatencyCallback(const jack_latency_callback_mode_t mode)
{
#ifndef BUILD_BRIDGE
if (fOptions.processMode != PROCESS_MODE_SINGLE_CLIENT)
return;
#endif

for (unsigned int i=0; i < kData->curPluginCount; i++)
{
@@ -1136,45 +1110,43 @@ private:

// -------------------------------------

#define handlePtr ((CarlaEngineJack*)arg)

static int carla_jack_srate_callback(jack_nframes_t newSampleRate, void* arg)
{
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackSampleRateCallback(newSampleRate);
handlePtr->handleJackSampleRateCallback(newSampleRate);
return 0;
}

static int carla_jack_bufsize_callback(jack_nframes_t newBufferSize, void* arg)
{
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackBufferSizeCallback(newBufferSize);
handlePtr->handleJackBufferSizeCallback(newBufferSize);
return 0;
}

static void carla_jack_freewheel_callback(int starting, void* arg)
{
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackFreewheelCallback(bool(starting));
handlePtr->handleJackFreewheelCallback(bool(starting));
}

static int carla_jack_process_callback(jack_nframes_t nframes, void* arg)
{
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackProcessCallback(nframes);
handlePtr->handleJackProcessCallback(nframes);
return 0;
}

static void carla_jack_latency_callback(jack_latency_callback_mode_t mode, void* arg)
{
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackLatencyCallback(mode);
handlePtr->handleJackLatencyCallback(mode);
}

static void carla_jack_shutdown_callback(void* arg)
{
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackShutdownCallback();
handlePtr->handleJackShutdownCallback();
}

#undef handlePtr

// -------------------------------------

#ifndef BUILD_BRIDGE

source/backend/engine/plugin.cpp → source/backend/engine/CarlaEnginePlugin.cpp View File


+ 547
- 0
source/backend/engine/CarlaEngineRtAudio.cpp View File

@@ -0,0 +1,547 @@
/*
* Carla RtAudio Engine
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the GPL.txt file
*/

#ifdef WANT_RTAUDIO

#include "CarlaEngineInternal.hpp"
#include "CarlaBackendUtils.hpp"
#include "CarlaMIDI.h"
#include "RtList.hpp"

#include "RtAudio.h"
#include "RtMidi.h"

CARLA_BACKEND_START_NAMESPACE

#if 0
} // Fix editor indentation
#endif

// -------------------------------------------------------------------------------------------------------------------

RtMidi::Api getMatchedAudioMidiAPi(const RtAudio::Api rtApi)
{
switch (rtApi)
{
case RtAudio::UNSPECIFIED:
return RtMidi::UNSPECIFIED;

case RtAudio::LINUX_ALSA:
case RtAudio::LINUX_OSS:
case RtAudio::LINUX_PULSE:
return RtMidi::LINUX_ALSA;

case RtAudio::UNIX_JACK:
return RtMidi::UNIX_JACK;

case RtAudio::MACOSX_CORE:
return RtMidi::MACOSX_CORE;

case RtAudio::WINDOWS_ASIO:
case RtAudio::WINDOWS_DS:
return RtMidi::WINDOWS_MM;

case RtAudio::RTAUDIO_DUMMY:
return RtMidi::RTMIDI_DUMMY;
}

return RtMidi::UNSPECIFIED;
}

// -------------------------------------------------------------------------------------------------------------------
// RtAudio Engine

class CarlaEngineRtAudio : public CarlaEngine
{
public:
CarlaEngineRtAudio(const RtAudio::Api api)
: CarlaEngine(),
fAudio(api),
fAudioIsInterleaved(false),
fAudioIsReady(false),
fAudioInBuf1(nullptr),
fAudioInBuf2(nullptr),
fAudioOutBuf1(nullptr),
fAudioOutBuf2(nullptr),
fMidiIn(getMatchedAudioMidiAPi(api)),
fMidiOut(getMatchedAudioMidiAPi(api))
{
carla_debug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api);

// just to make sure
fOptions.forceStereo = true;
fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK;
}

~CarlaEngineRtAudio()
{
carla_debug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");
CARLA_ASSERT(fAudioInBuf1 == nullptr);
CARLA_ASSERT(fAudioInBuf2 == nullptr);
CARLA_ASSERT(fAudioOutBuf1 == nullptr);
CARLA_ASSERT(fAudioOutBuf2 == nullptr);
}

// -------------------------------------

bool init(const char* const clientName)
{
carla_debug("CarlaEngineRtAudio::init(\"%s\")", clientName);
CARLA_ASSERT(! fAudioIsReady);
CARLA_ASSERT(fAudioInBuf1 == nullptr);
CARLA_ASSERT(fAudioInBuf2 == nullptr);
CARLA_ASSERT(fAudioOutBuf1 == nullptr);
CARLA_ASSERT(fAudioOutBuf2 == nullptr);

if (fAudio.getDeviceCount() == 0)
{
setLastError("No audio devices available for this driver");
return false;
}

fBufferSize = fOptions.preferredBufferSize;

// Audio
{
RtAudio::StreamParameters iParams, oParams;
iParams.deviceId = fAudio.getDefaultInputDevice();
oParams.deviceId = fAudio.getDefaultOutputDevice();
iParams.nChannels = 2;
oParams.nChannels = 2;

RtAudio::StreamOptions rtOptions;
rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME;
rtOptions.numberOfBuffers = 2;
rtOptions.streamName = clientName;
rtOptions.priority = 85;

if (fAudio.getCurrentApi() != RtAudio::LINUX_PULSE)
{
rtOptions.flags |= RTAUDIO_NONINTERLEAVED;
fAudioIsInterleaved = false;

if (fAudio.getCurrentApi() == RtAudio::LINUX_ALSA)
rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT;
}
else
fAudioIsInterleaved = true;

try {
fAudio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, fOptions.preferredSampleRate, &fBufferSize, carla_rtaudio_process_callback, this, &rtOptions);
}
catch (RtError& e)
{
setLastError(e.what());
return false;
}

try {
fAudio.startStream();
}
catch (RtError& e)
{
setLastError(e.what());
return false;
}

fAudioInBuf1 = new float[fBufferSize];
fAudioInBuf2 = new float[fBufferSize];
fAudioOutBuf1 = new float[fBufferSize];
fAudioOutBuf2 = new float[fBufferSize];

fSampleRate = fAudio.getStreamSampleRate();
}

// MIDI
{
fMidiIn.setCallback(carla_rtmidi_callback, this);
fMidiIn.openVirtualPort("events-in");
fMidiOut.openVirtualPort("events-out");
}

fAudioIsReady = true;

return CarlaEngine::init(clientName);
}

bool close()
{
carla_debug("CarlaEngineRtAudio::close()");
CARLA_ASSERT(fAudioIsReady);
CARLA_ASSERT(fAudioInBuf1 != nullptr);
CARLA_ASSERT(fAudioInBuf2 != nullptr);
CARLA_ASSERT(fAudioOutBuf1 != nullptr);
CARLA_ASSERT(fAudioOutBuf2 != nullptr);

CarlaEngine::close();

fAudioIsReady = false;

if (fAudio.isStreamRunning())
fAudio.stopStream();

if (fAudio.isStreamOpen())
fAudio.closeStream();

fMidiIn.cancelCallback();
fMidiIn.closePort();
fMidiOut.closePort();

if (fAudioInBuf1 != nullptr)
{
delete[] fAudioInBuf1;
fAudioInBuf1 = nullptr;
}

if (fAudioInBuf2 != nullptr)
{
delete[] fAudioInBuf2;
fAudioInBuf2 = nullptr;
}

if (fAudioOutBuf1 != nullptr)
{
delete[] fAudioOutBuf1;
fAudioOutBuf1 = nullptr;
}

if (fAudioOutBuf2 != nullptr)
{
delete[] fAudioOutBuf2;
fAudioOutBuf2 = nullptr;
}

fMidiInEvents.clear();
fMidiOutEvents.clear();

return true;
}

bool isRunning() const
{
return fAudio.isStreamRunning();
}

bool isOffline() const
{
return false;
}

EngineType type() const
{
return kEngineTypeRtAudio;
}

// -------------------------------------

protected:
void handleAudioProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status)
{
// get buffers from RtAudio
float* insPtr = (float*)inputBuffer;
float* outsPtr = (float*)outputBuffer;

// assert buffers
CARLA_ASSERT(insPtr != nullptr);
CARLA_ASSERT(outsPtr != nullptr);

if (currentPluginCount() == 0 || ! fAudioIsReady)
{
carla_zeroFloat(outsPtr, sizeof(float)*nframes*2);
return;
}

// initialize audio input
if (fAudioIsInterleaved)
{
for (unsigned int i=0; i < nframes*2; i++)
{
if (i % 2)
fAudioInBuf1[i/2] = insPtr[i];
else
fAudioInBuf2[i/2] = insPtr[i];
}
}
else
{
std::memcpy(fAudioInBuf1, insPtr, sizeof(float)*nframes);
std::memcpy(fAudioInBuf2, insPtr+nframes, sizeof(float)*nframes);

//for (unsigned int i=0; i < nframes; i++)
// fAudioInBuf1[i] = insPtr[i];
//for (unsigned int i=0, j=nframes; i < nframes; i++, j++)
// fAudioInBuf2[i] = insPtr[j];
}

// initialize audio output
carla_zeroFloat(fAudioOutBuf1, fBufferSize);
carla_zeroFloat(fAudioOutBuf2, fBufferSize);

// initialize events input
//memset(rackEventsIn, 0, sizeof(EngineEvent)*MAX_EVENTS);
{
// TODO
}

// create audio buffers
float* inBuf[2] = { fAudioInBuf1, fAudioInBuf2 };
float* outBuf[2] = { fAudioOutBuf1, fAudioOutBuf2 };

processRack(inBuf, outBuf, nframes);

// output audio
if (fAudioIsInterleaved)
{
for (unsigned int i=0; i < nframes*2; i++)
{
if (i % 2)
outsPtr[i] = fAudioOutBuf1[i/2];
else
outsPtr[i] = fAudioOutBuf2[i/2];
}
}
else
{
std::memcpy(outsPtr, fAudioOutBuf1, sizeof(float)*nframes);
std::memcpy(outsPtr+nframes, fAudioOutBuf2, sizeof(float)*nframes);

//for (unsigned int i=0; i < nframes; i++)
// outsPtr[i] = fAudioOutBuf1[i];
//for (unsigned int i=0, j=nframes; i < nframes; i++, j++)
// outsPtr[j] = fAudioOutBuf2[i];
}

// output events
{
// TODO
//fMidiOut.sendMessage();
}

(void)streamTime;
(void)status;
}

void handleMidiCallback(const double timeStamp, std::vector<unsigned char>* const message)
{
const size_t messageSize = message->size();

if (messageSize == 0 || messageSize > 3)
return;

RtMidiEvent midiEvent;
midiEvent.time = timeStamp;

if (messageSize == 1)
{
midiEvent.data[0] = message->at(0);
midiEvent.data[1] = 0;
midiEvent.data[2] = 0;
}
else if (messageSize == 2)
{
midiEvent.data[0] = message->at(0);
midiEvent.data[1] = message->at(1);
midiEvent.data[2] = 0;
}
else
{
midiEvent.data[0] = message->at(0);
midiEvent.data[1] = message->at(1);
midiEvent.data[2] = message->at(2);
}

fMidiInEvents.append(midiEvent);
}

// -------------------------------------

private:
RtAudio fAudio;
bool fAudioIsInterleaved;
bool fAudioIsReady;
float* fAudioInBuf1;
float* fAudioInBuf2;
float* fAudioOutBuf1;
float* fAudioOutBuf2;

RtMidiIn fMidiIn;
RtMidiOut fMidiOut;

struct RtMidiEvent {
double time;
unsigned char data[3];
};

struct RtMidiEvents {
CarlaMutex mutex;
RtList<RtMidiEvent>::Pool dataPool;
RtList<RtMidiEvent> data;
RtList<RtMidiEvent> dataPending;

RtMidiEvents()
: dataPool(512, 512),
data(&dataPool),
dataPending(&dataPool) {}

~RtMidiEvents()
{
clear();
}

void append(const RtMidiEvent& event)
{
mutex.lock();
dataPending.append(event);
mutex.unlock();
}

void clear()
{
mutex.lock();
data.clear();
dataPending.clear();
mutex.unlock();
}

void trySplice()
{
if (mutex.tryLock())
{
dataPending.splice(data, true);
mutex.unlock();
}
}
};

RtMidiEvents fMidiInEvents;
RtMidiEvents fMidiOutEvents;

#define handlePtr ((CarlaEngineRtAudio*)userData)

static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData)
{
handlePtr->handleAudioProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
return 0;
}

static void carla_rtmidi_callback(double timeStamp, std::vector<unsigned char>* message, void* userData)
{
handlePtr->handleMidiCallback(timeStamp, message);
}

#undef handlePtr

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
};

// -----------------------------------------

static std::vector<RtAudio::Api> sRtAudioApis;

static void initRtApis()
{
static bool initiated = false;

if (! initiated)
{
initiated = true;

RtAudio::getCompiledApi(sRtAudioApis);
}
}

CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
{
RtAudio::Api rtApi = RtAudio::UNSPECIFIED;

switch (api)
{
case RTAUDIO_DUMMY:
rtApi = RtAudio::RTAUDIO_DUMMY;
break;
case RTAUDIO_LINUX_ALSA:
rtApi = RtAudio::LINUX_ALSA;
break;
case RTAUDIO_LINUX_PULSE:
rtApi = RtAudio::LINUX_PULSE;
break;
case RTAUDIO_LINUX_OSS:
rtApi = RtAudio::LINUX_OSS;
break;
case RTAUDIO_UNIX_JACK:
rtApi = RtAudio::UNIX_JACK;
break;
case RTAUDIO_MACOSX_CORE:
rtApi = RtAudio::MACOSX_CORE;
break;
case RTAUDIO_WINDOWS_ASIO:
rtApi = RtAudio::WINDOWS_ASIO;
break;
case RTAUDIO_WINDOWS_DS:
rtApi = RtAudio::WINDOWS_DS;
break;
}

return new CarlaEngineRtAudio(rtApi);
}

size_t CarlaEngine::getRtAudioApiCount()
{
initRtApis();

return sRtAudioApis.size();
}

const char* CarlaEngine::getRtAudioApiName(const unsigned int index)
{
initRtApis();

if (index < sRtAudioApis.size())
{
const RtAudio::Api& api(sRtAudioApis[index]);

switch (api)
{
case RtAudio::UNSPECIFIED:
return "Unspecified";
case RtAudio::LINUX_ALSA:
return "ALSA";
case RtAudio::LINUX_PULSE:
return "PulseAudio";
case RtAudio::LINUX_OSS:
return "OSS";
case RtAudio::UNIX_JACK:
return "JACK (RtAudio)";
case RtAudio::MACOSX_CORE:
return "CoreAudio";
case RtAudio::WINDOWS_ASIO:
return "ASIO";
case RtAudio::WINDOWS_DS:
return "DirectSound";
case RtAudio::RTAUDIO_DUMMY:
return "Dummy";
}
}

return nullptr;
}

// -----------------------------------------

CARLA_BACKEND_END_NAMESPACE

#endif // CARLA_ENGINE_RTAUDIO

+ 3
- 3
source/backend/engine/Makefile View File

@@ -44,10 +44,10 @@ endif

OBJS = \
CarlaEngine.cpp.o \
CarlaEngineJack.cpp.o \
CarlaEngineRtAudio.cpp.o \
CarlaEngineOsc.cpp.o \
CarlaEngineThread.cpp.o \
jack.cpp.o \
rtaudio.cpp.o
CarlaEngineThread.cpp.o

ifeq ($(CARLA_RTAUDIO_SUPPORT),true)
OBJS += \


source/backend/engine/plugin/DistrhoPluginInfo.h → source/backend/engine/distrho/DistrhoPluginInfo.h View File


+ 0
- 421
source/backend/engine/rtaudio.cpp View File

@@ -1,421 +0,0 @@
/*
* Carla RtAudio Engine
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the GPL.txt file
*/

#ifdef WANT_RTAUDIO

#include "CarlaEngineInternal.hpp"
#include "CarlaBackendUtils.hpp"
#include "CarlaMIDI.h"

#include "RtAudio.h"
#include "RtMidi.h"

CARLA_BACKEND_START_NAMESPACE

#if 0
} // Fix editor indentation
#endif

// -------------------------------------------------------------------------------------------------------------------
// RtAudio Engine

class CarlaEngineRtAudio : public CarlaEngine
{
public:
CarlaEngineRtAudio(RtAudio::Api api)
: CarlaEngine(),
audio(api)
{
qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api);

evIn = nullptr;
evOut = nullptr;

m_audioInterleaved = false;
m_inBuf1 = nullptr;
m_inBuf2 = nullptr;
m_outBuf1 = nullptr;
m_outBuf2 = nullptr;

// just to make sure
fOptions.forceStereo = true;
fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK;
}

~CarlaEngineRtAudio()
{
qDebug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");
}

// -------------------------------------

bool init(const char* const clientName)
{
qDebug("CarlaEngineRtAudio::init(\"%s\")", clientName);

if (audio.getDeviceCount() < 1)
{
setLastError("No audio devices available for this driver");
return false;
}

fBufferSize = fOptions.preferredBufferSize;
fSampleRate = fOptions.preferredSampleRate;

RtAudio::StreamParameters iParams, oParams;
iParams.deviceId = audio.getDefaultInputDevice();
oParams.deviceId = audio.getDefaultOutputDevice();
iParams.nChannels = 2;
oParams.nChannels = 2;

RtAudio::StreamOptions rtOptions;
rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME;
rtOptions.numberOfBuffers = 2;
rtOptions.streamName = clientName;
rtOptions.priority = 85;

if (audio.getCurrentApi() != RtAudio::LINUX_PULSE)
{
rtOptions.flags |= RTAUDIO_NONINTERLEAVED;
m_audioInterleaved = false;

if (audio.getCurrentApi() == RtAudio::LINUX_ALSA)
rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT;
}
else
m_audioInterleaved = true;

try {
audio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, fSampleRate, &fBufferSize, carla_rtaudio_process_callback, this, &rtOptions);
}
catch (RtError& e)
{
setLastError(e.what());
return false;
}

try {
audio.startStream();
}
catch (RtError& e)
{
setLastError(e.what());
return false;
}

fSampleRate = audio.getStreamSampleRate();

m_inBuf1 = new float[fBufferSize];
m_inBuf2 = new float[fBufferSize];
m_outBuf1 = new float[fBufferSize];
m_outBuf2 = new float[fBufferSize];

//midiIn = new MidiInAlsa(clientName, 512);
//midiIn->openVirtualPort("control-in");
//midiIn->openVirtualPort("midi-in");

//midiOut = new MidiOutAlsa(clientName);
//midiOut->openVirtualPort("control-out");
//midiOut->openVirtualPort("midi-out");

fName = clientName;
fName.toBasic();

CarlaEngine::init(fName);
return true;
}

bool close()
{
qDebug("CarlaEngineRtAudio::close()");
CarlaEngine::close();

if (audio.isStreamRunning())
audio.stopStream();

if (audio.isStreamOpen())
audio.closeStream();

#if 0
if (midiIn)
{
midiIn->cancelCallback();
midiIn->closePort();
delete midiIn;
midiIn = nullptr;
}

if (midiOut)
{
midiOut->closePort();
delete midiOut;
midiOut = nullptr;
}
#endif

if (m_inBuf1)
{
delete[] m_inBuf1;
m_inBuf1 = nullptr;
}

if (m_inBuf2)
{
delete[] m_inBuf2;
m_inBuf2 = nullptr;
}

if (m_outBuf1)
{
delete[] m_outBuf1;
m_outBuf1 = nullptr;
}

if (m_outBuf2)
{
delete[] m_outBuf2;
m_outBuf2 = nullptr;
}

return true;
}

bool isRunning() const
{
return audio.isStreamRunning();
}

bool isOffline() const
{
return false;
}

EngineType type() const
{
return kEngineTypeRtAudio;
}

// -------------------------------------

protected:
void handleProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status)
{
if (maxPluginNumber() == 0)
return;

// get buffers from RtAudio
float* insPtr = (float*)inputBuffer;
float* outsPtr = (float*)outputBuffer;

// assert buffers
CARLA_ASSERT(insPtr);
CARLA_ASSERT(outsPtr);

// initialize audio input
if (m_audioInterleaved)
{
for (unsigned int i=0; i < nframes*2; i++)
{
if (i % 2)
m_inBuf2[i/2] = insPtr[i];
else
m_inBuf1[i/2] = insPtr[i];
}
}
else
{
for (unsigned int i=0; i < nframes; i++)
m_inBuf1[i] = insPtr[i];

for (unsigned int i=0, j=nframes; i < nframes; i++, j++)
m_inBuf2[i] = insPtr[j];
}

// create audio buffers
float* inBuf[2] = { m_inBuf1, m_inBuf2 };
float* outBuf[2] = { m_outBuf1, m_outBuf2 };

// initialize events input
//memset(rackEventsIn, 0, sizeof(EngineEvent)*MAX_EVENTS);
{
// TODO
}

processRack(inBuf, outBuf, nframes);

// output audio
if (m_audioInterleaved)
{
for (unsigned int i=0; i < nframes*2; i++)
{
if (i % 2)
outsPtr[i] = m_outBuf2[i/2];
else
outsPtr[i] = m_outBuf1[i/2];
}
}
else
{
for (unsigned int i=0; i < nframes; i++)
outsPtr[i] = m_outBuf1[i];

for (unsigned int i=0, j=nframes; i < nframes; i++, j++)
outsPtr[j] = m_outBuf2[i];
}

// output control
{
// TODO
}

// output midi
{
// TODO
}

Q_UNUSED(streamTime);
Q_UNUSED(status);
}

// -------------------------------------

private:
RtAudio audio;
ScopedPointer<MidiInApi> evIn;
ScopedPointer<MidiOutApi> evOut;

bool m_audioInterleaved;
float* m_inBuf1;
float* m_inBuf2;
float* m_outBuf1;
float* m_outBuf2;

static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData)
{
CarlaEngineRtAudio* const _this_ = (CarlaEngineRtAudio*)userData;
_this_->handleProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
return 0;
}

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
};

// -----------------------------------------

static std::vector<RtAudio::Api> rtApis;

static void initRtApis()
{
static bool initiated = false;

if (! initiated)
{
initiated = true;

RtAudio::getCompiledApi(rtApis);
}
}

CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
{
RtAudio::Api rtApi = RtAudio::UNSPECIFIED;

switch (api)
{
case RTAUDIO_DUMMY:
rtApi = RtAudio::RTAUDIO_DUMMY;
break;
case RTAUDIO_LINUX_ALSA:
rtApi = RtAudio::LINUX_ALSA;
break;
case RTAUDIO_LINUX_PULSE:
rtApi = RtAudio::LINUX_PULSE;
break;
case RTAUDIO_LINUX_OSS:
rtApi = RtAudio::LINUX_OSS;
break;
case RTAUDIO_UNIX_JACK:
rtApi = RtAudio::UNIX_JACK;
break;
case RTAUDIO_MACOSX_CORE:
rtApi = RtAudio::MACOSX_CORE;
break;
case RTAUDIO_WINDOWS_ASIO:
rtApi = RtAudio::WINDOWS_ASIO;
break;
case RTAUDIO_WINDOWS_DS:
rtApi = RtAudio::WINDOWS_DS;
break;
}

return new CarlaEngineRtAudio(rtApi);
}

unsigned int CarlaEngine::getRtAudioApiCount()
{
initRtApis();

return rtApis.size();
}

const char* CarlaEngine::getRtAudioApiName(unsigned int index)
{
initRtApis();

if (index < rtApis.size())
{
const RtAudio::Api& api(rtApis[index]);

switch (api)
{
case RtAudio::UNSPECIFIED:
return "Unspecified";
case RtAudio::LINUX_ALSA:
return "ALSA";
case RtAudio::LINUX_PULSE:
return "PulseAudio";
case RtAudio::LINUX_OSS:
return "OSS";
case RtAudio::UNIX_JACK:
return "JACK (RtAudio)";
case RtAudio::MACOSX_CORE:
return "CoreAudio";
case RtAudio::WINDOWS_ASIO:
return "ASIO";
case RtAudio::WINDOWS_DS:
return "DirectSound";
case RtAudio::RTAUDIO_DUMMY:
return "Dummy";
}
}

return nullptr;
}

// -----------------------------------------

CARLA_BACKEND_END_NAMESPACE

#ifdef QTCREATOR_TEST
int main()
{
return 0;
}

#endif

#endif // CARLA_ENGINE_RTAUDIO

+ 1
- 0
source/backend/plugin/CarlaPluginInternal.hpp View File

@@ -443,6 +443,7 @@ struct CarlaPluginProtectedData {

void appendRT(const PluginPostRtEvent& event)
{
// FIXME!! need lock?
dataPendingRT.append(event);
}



+ 2
- 1
source/tests/ANSI.cpp View File

@@ -16,7 +16,8 @@
*/

// still need qt classes check
#include "engine/CarlaEngineThread.cpp"
//#include "CarlaPlugin.hpp"
#include "engine/RtAudio.cpp"

#if 0
#include "CarlaDefines.hpp"


+ 2
- 2
source/tests/Makefile View File

@@ -8,9 +8,9 @@ include ../Makefile.mk

# --------------------------------------------------------------

BUILD_CXX_FLAGS += -I../backend -I../includes -I../utils -Wall -Wextra
BUILD_CXX_FLAGS += -I../backend -I../includes -I../libs -I../utils -Wall -Wextra
BUILD_CXX_FLAGS += -DWANT_JACK -DWANT_RTAUDIO
BUILD_CXX_FLAGS += -isystem /usr/include/qt4
BUILD_CXX_FLAGS += -isystem /usr/include/qt4 -isystem ../backend/engine/rtaudio-4.0.11
# BUILD_CXX_FLAGS += -D_FORTIFY_SOURCE=2 -fstack-protector
# BUILD_CXX_FLAGS += -I/opt/mingw32/include



+ 3
- 3
source/utils/CarlaUtils.hpp View File

@@ -237,7 +237,7 @@ const T& carla_fixValue(const T& min, const T& max, const T& value)

template<typename T>
static inline
void carla_fill(T* data, const unsigned int size, const T v)
void carla_fill(T* data, const size_t size, const T v)
{
CARLA_ASSERT(data != nullptr);
CARLA_ASSERT(size > 0);
@@ -250,13 +250,13 @@ void carla_fill(T* data, const unsigned int size, const T v)
}

static inline
void carla_zeroDouble(double* data, const unsigned size)
void carla_zeroDouble(double* data, const size_t size)
{
carla_fill<double>(data, size, 0.0);
}

static inline
void carla_zeroFloat(float* data, const unsigned size)
void carla_zeroFloat(float* data, const size_t size)
{
carla_fill<float>(data, size, 0.0f);
}


Loading…
Cancel
Save