Browse Source

Cleanup; Convert AudioFile to C++ (incomplete)

tags/1.9.4
falkTX 12 years ago
parent
commit
4c5c6f6146
14 changed files with 726 additions and 849 deletions
  1. +5
    -1
      source/backend/Makefile
  2. +97
    -0
      source/backend/native/CarlaNative.pro
  3. +29
    -14
      source/backend/native/Makefile
  4. +520
    -0
      source/backend/native/audio-file.cpp
  5. +0
    -702
      source/backend/native/audiofile.c
  6. +0
    -53
      source/backend/native/carla_native.pro
  7. +2
    -2
      source/backend/native/distrho-3bandeq.cpp
  8. +2
    -2
      source/backend/native/distrho-3bandsplitter.cpp
  9. +2
    -2
      source/backend/native/distrho-notes.cpp
  10. +2
    -2
      source/backend/native/distrho-pingpongpan.cpp
  11. +62
    -64
      source/backend/native/zynaddsubfx.cpp
  12. +0
    -1
      source/backend/plugin/CarlaPlugin.pro
  13. +1
    -0
      source/backend/plugin/Lv2Plugin.cpp
  14. +4
    -6
      source/utils/CarlaString.hpp

+ 5
- 1
source/backend/Makefile View File

@@ -87,7 +87,11 @@ endif

@echo "\033[33m||| Internal plugins: \033[0m"
ifeq ($(HAVE_AF_DEPS),true)
@echo "AudioFile: $(ANS_YES)"
ifeq ($(HAVE_FFMPEG),true)
@echo "AudioFile: $(ANS_YES) (with ffmpeg)"
else
@echo "AudioFIle: $(ANS_YES) (without ffmpeg)"
endif
else
@echo "AudioFIle: $(ANS_NO)"
endif


+ 97
- 0
source/backend/native/CarlaNative.pro View File

@@ -0,0 +1,97 @@
# QtCreator project file

TARGET = CarlaPlugin
TEMPLATE = lib
VERSION = 1.0

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

QT = core gui

CONFIG = debug
CONFIG += link_pkgconfig qt shared warn_on

DEFINES = DEBUG
DEFINES += HAVE_CPP11_SUPPORT
DEFINES += QTCREATOR_TEST MOC_PARSING

# Shared
DEFINES += WANT_NATIVE
DEFINES += WANT_LADSPA
DEFINES += WANT_DSSI
DEFINES += WANT_LV2
DEFINES += WANT_VST
DEFINES += WANT_PLUGIN
DEFINES += WANT_RTAUDIO
DEFINES += WANT_FLUIDSYNTH
DEFINES += WANT_LINUXSAMPLER
DEFINES += WANT_OPENGL
DEFINES += WANT_AUDIOFILE
DEFINES += WANT_MIDIFILE
DEFINES += WANT_ZYNADDSUBFX
DEFINES += WANT_ZYNADDSUBFX_UI

# Audio file
DEFINES += HAVE_FFMPEG
PKGCONFIG += sndfile libavcodec libavformat libavutil

# MIDI file
PKGCONFIG += smf

# DISTRHO
PKGCONFIG += gl

# ZynAddSubFX
DEFINES += NTK_GUI
PKGCONFIG += fftw3 mxml zlib ntk ntk_images

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

SOURCES = \
bypass.c \
lfo.c \
midi-split.c \
midi-through.c \
midi-transpose.c \
nekofilter.c

SOURCES += \
audio-file.cpp \
midi-file.cpp \
midi-sequencer.cpp \
sunvox-file.cpp \
zynaddsubfx.cpp \
zynaddsubfx-src.cpp \
zynaddsubfx-ui.cpp

SOURCES += \
distrho-3bandeq.cpp

HEADERS = \
midi-base.hpp

HEADERS += \
../CarlaNative.h \
../CarlaNative.hpp

HEADERS += \
distrho/DistrhoPluginCarla.cpp

HEADERS += \
../../utils/CarlaUtils.hpp \
../../utils/CarlaJuceUtils.hpp \
../../utils/CarlaLibUtils.hpp \
../../utils/CarlaOscUtils.hpp \
../../utils/CarlaStateUtils.hpp \
../../utils/CarlaMutex.hpp \
../../utils/CarlaString.hpp

INCLUDEPATH = . .. \
3bandeq distrho \
../../includes \
../../libs/distrho \
../../utils \
../../widgets

QMAKE_CFLAGS *= -std=c99
QMAKE_CXXFLAGS *= -std=c++0x

+ 29
- 14
source/backend/native/Makefile View File

@@ -62,7 +62,10 @@ OBJS = \
# AudioFile
ifeq ($(HAVE_AF_DEPS),true)
OBJS += \
audiofile.c.o
audio-file.cpp.o \
audio_decoder/ad_ffmpeg.c.o \
audio_decoder/ad_plugin.c.o \
audio_decoder/ad_soundfile.c.o
endif

# MidiFile
@@ -147,10 +150,13 @@ debug:

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

%.c.o: %.c ../CarlaNative.h
CDEPS = ../CarlaNative.h
CXXDEPS = ../CarlaNative.h ../CarlaNative.hpp

%.c.o: %.c $(CDEPS)
$(CC) $< $(BUILD_C_FLAGS) -c -o $@

%.cpp.o: %.cpp ../CarlaNative.h ../CarlaNative.hpp
%.cpp.o: %.cpp $(CXXDEPS)
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

$(TARGET): $(OBJS)
@@ -158,37 +164,46 @@ $(TARGET): $(OBJS)

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

audiofile.c.o: audiofile.c
audio_decoder/%.c.o: audio_decoder/%.c
$(CC) $< $(AF_C_FLAGS) -c -o $@

distrho-3bandeq.cpp.o: distrho-3bandeq.cpp 3bandeq/DistrhoArtwork3BandEQ.cpp 3bandeq/DistrhoPlugin3BandEQ.cpp 3bandeq/DistrhoUI3BandEQ.cpp distrho/DistrhoPluginCarla.cpp
audio-file.cpp.o: audio-file.cpp $(CXXDEPS)
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

distrho-3bandeq.cpp.o: distrho-3bandeq.cpp 3bandeq/*.cpp 3bandeq/*.h 3bandeq/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS)
$(CXX) $< $(GL_CXX_FLAGS) -I3bandeq -DDISTRHO_NAMESPACE=DISTRHO_3BandEQ -c -o $@

distrho-3bandsplitter.cpp.o: distrho-3bandsplitter.cpp 3bandsplitter/DistrhoArtwork3BandSplitter.cpp 3bandsplitter/DistrhoPlugin3BandSplitter.cpp 3bandsplitter/DistrhoUI3BandSplitter.cpp distrho/DistrhoPluginCarla.cpp
distrho-3bandsplitter.cpp.o: distrho-3bandsplitter.cpp 3bandsplitter/*.cpp 3bandsplitter/*.h 3bandsplitter/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS)
$(CXX) $< $(GL_CXX_FLAGS) -I3bandsplitter -DDISTRHO_NAMESPACE=DISTRHO_3BandSplitter -c -o $@

distrho-pingpongpan.cpp.o: distrho-pingpongpan.cpp pingpongpan/DistrhoArtworkPingPongPan.cpp pingpongpan/DistrhoPluginPingPongPan.cpp pingpongpan/DistrhoUIPingPongPan.cpp distrho/DistrhoPluginCarla.cpp
distrho-pingpongpan.cpp.o: distrho-pingpongpan.cpp pingpongpan/*.cpp pingpongpan/*.h pingpongpan/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS)
$(CXX) $< $(GL_CXX_FLAGS) -Ipingpongpan -DDISTRHO_NAMESPACE=DISTRHO_PingPongPan -c -o $@

distrho-notes.cpp.o: distrho-notes.cpp notes/DistrhoPluginNotes.cpp notes/DistrhoUINotes.cpp distrho/DistrhoPluginCarla.cpp moc_DistrhoUINotes.cpp
distrho-notes.cpp.o: distrho-notes.cpp notes/moc_DistrhoUINotes.cpp notes/*.cpp notes/*.h notes/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS)
$(CXX) $< $(BUILD_CXX_FLAGS) -Inotes -DDISTRHO_NAMESPACE=DISTRHO_Notes -c -o $@

midi-file.cpp.o: midi-file.cpp
midi-file.cpp.o: midi-file.cpp midi-base.hpp $(CXXDEPS)
$(CXX) $< $(MF_CXX_FLAGS) -c -o $@

zynaddsubfx.cpp.o: zynaddsubfx.cpp $(ZYN_UI_FILES_H)
midi-sequencer.cpp.o: midi-sequencer.cpp midi-base.hpp $(CXXDEPS)
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

nekofilter.c.o: nekofilter.c nekofilter/*.c nekofilter/*.h $(CDEPS)
$(CC) $< $(BUILD_C_FLAGS) -c -o $@

zynaddsubfx.cpp.o: zynaddsubfx.cpp $(CXXDEPS) $(ZYN_UI_FILES_H)
$(CXX) $< $(ZYN_CXX_FLAGS) -c -o $@

zynaddsubfx-src.cpp.o: zynaddsubfx-src.cpp
zynaddsubfx-src.cpp.o: zynaddsubfx-src.cpp $(ZYN_UI_FILES_CPP)
$(CXX) $< $(ZYN_CXX_FLAGS) -c -o $@

zynaddsubfx-ui.cpp.o: zynaddsubfx-ui.cpp $(ZYN_UI_FILES_CPP)
zynaddsubfx-ui.cpp.o: zynaddsubfx-ui.cpp $(ZYN_UI_FILES_H)
$(CXX) $< $(ZYN_CXX_FLAGS) -c -o $@

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

moc_DistrhoUINotes.cpp: notes/DistrhoUINotes.hpp
$(MOC) $< -o $@
moc_%.cpp: %.hpp
$(MOC) $< -DMOC_PARSING -o $@

zynaddsubfx/UI/%.cpp: zynaddsubfx/UI/%.fl
ntk-fluid -c -o zynaddsubfx/UI/$*.cpp -h zynaddsubfx/UI/$*.h $<


+ 520
- 0
source/backend/native/audio-file.cpp View File

@@ -0,0 +1,520 @@
/*
* Carla Native Plugins
* Copyright (C) 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
*/

#include "CarlaNative.hpp"
#include "CarlaMutex.hpp"
#include "CarlaString.hpp"

#include <QtCore/QThread>

extern "C" {
#include "audio_decoder/ad.h"
}

#define PROGRAM_COUNT 16

typedef struct adinfo ADInfo;

class AudioFilePlugin : public PluginDescriptorClass
{
public:
AudioFilePlugin(const HostDescriptor* const host)
: PluginDescriptorClass(host),
filePtr(nullptr),
lastFrame(0),
maxFrame(0),
loopMode(false),
doProcess(false)
{
static bool adInitiated = false;

if (! adInitiated)
{
ad_init();
adInitiated = true;
}

ad_clear_nfo(&fileNfo);

pool.create(getSampleRate());
thread.setPoolSize(pool.size);
}

~AudioFilePlugin() override
{
doProcess = false;

thread.stopNow();

if (filePtr != nullptr)
ad_close(filePtr);

pool.destroy();
}

protected:
// -------------------------------------------------------------------
// Plugin parameter calls

uint32_t getParameterCount() override
{
return 0; // FIXME
return 1;
}

const Parameter* getParameterInfo(const uint32_t index) override
{
return nullptr; // FIXME - loop mode needs work

if (index != 0)
return nullptr;

static Parameter param;

param.name = "Loop Mode";
param.unit = nullptr;
param.hints = static_cast<ParameterHints>(PARAMETER_IS_ENABLED|PARAMETER_IS_BOOLEAN);
param.ranges.def = 1.0f;
param.ranges.min = 0.0f;
param.ranges.max = 1.0f;
param.ranges.step = 1.0f;
param.ranges.stepSmall = 1.0f;
param.ranges.stepLarge = 1.0f;
param.scalePointCount = 0;
param.scalePoints = nullptr;

return &param;
}

float getParameterValue(const uint32_t index) override
{
if (index != 0)
return 0.0f;

return loopMode ? 1.0f : 0.0f;
}

// -------------------------------------------------------------------
// Plugin midi-program calls

uint32_t getMidiProgramCount() override
{
return PROGRAM_COUNT;
}

const MidiProgram* getMidiProgramInfo(const uint32_t index) override
{
if (index >= PROGRAM_COUNT)
return NULL;

static MidiProgram midiProgram;

midiProgram.bank = 0;
midiProgram.program = index;
midiProgram.name = (const char*)programs.shortNames[index];

return &midiProgram;
}

// -------------------------------------------------------------------
// Plugin state calls

void setParameterValue(const uint32_t index, const float value) override
{
if (index != 0)
return;

bool b = (value > 0.5f);

if (b == loopMode)
return;

loopMode = b;
thread.setNeedsRead();
}

void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
{
if (bank != 0 || program >= PROGRAM_COUNT)
return;

if (programs.current != program)
{
loadFilename(programs.fullNames[program]);
programs.current = program;
}
}

void setCustomData(const char* const key, const char* const value) override
{
if (std::strlen(key) != 6)
return;
if (std::strncmp(key, "file", 4) != 0)
return;
if (key[4] < '0' || key[4] > '9')
return;
if (key[5] < '0' || key[5] > '9')
return;

uint8_t tens = key[4]-'0';
uint8_t nums = key[5]-'0';

uint32_t program = tens*10 + nums;

if (program >= PROGRAM_COUNT)
return;

programs.fullNames[program] = value;

if (const char* shortName = std::strrchr(value, OS_SEP))
programs.shortNames[program] = shortName+1;
else
programs.shortNames[program] = value;

programs.shortNames[program].truncate(programs.shortNames[program].rfind('.'));

if (programs.current == program)
loadFilename(value);
}

// -------------------------------------------------------------------
// Plugin process calls

void process(float**, float** const outBuffer, const uint32_t frames, const uint32_t, const MidiEvent* const) override
{
const TimeInfo* const timePos(getTimeInfo());

float* out1 = outBuffer[0];
float* out2 = outBuffer[1];

if (! doProcess)
{
lastFrame = timePos->frame;

carla_zeroFloat(out1, frames);
carla_zeroFloat(out2, frames);
return;
}

// not playing
if (! timePos->playing)
{
if (timePos->frame == 0 && lastFrame > 0)
thread.setNeedsRead();

lastFrame = timePos->frame;

carla_zeroFloat(out1, frames);
carla_zeroFloat(out2, frames);
return;
}

const CarlaMutex::ScopedLocker sl(&mutex);

// out of reach
if (timePos->frame + frames < pool.startFrame || timePos->frame >= maxFrame) /*&& ! loopMode)*/
{
lastFrame = timePos->frame;
thread.setNeedsRead();

carla_zeroFloat(out1, frames);
carla_zeroFloat(out2, frames);
return;
}

int64_t poolFrame = (int64_t)timePos->frame - pool.startFrame;
int64_t poolSize = pool.size;

for (uint32_t i=0; i < frames; ++i, ++poolFrame)
{
if (poolFrame >= 0 && poolFrame < poolSize)
{
out1[i] = pool.buffer[0][poolFrame];
out2[i] = pool.buffer[1][poolFrame];

// reset
pool.buffer[0][poolFrame] = 0.0f;
pool.buffer[1][poolFrame] = 0.0f;
}
else
{
out1[i] = 0.0f;
out2[i] = 0.0f;
}
}

lastFrame = timePos->frame;
}

// -------------------------------------------------------------------
// Plugin UI calls

void uiShow(const bool show) override
{
if (! show)
return;

if (const char* const filename = uiOpenFile(false, "Open Audio File", ""))
{
char fileStr[] = { 'f', 'i', 'l', 'e', '\0', '\0', '\0' };
fileStr[4] = '0' + (programs.current / 10);
fileStr[5] = '0' + (programs.current % 10);

uiCustomDataChanged(fileStr, filename);
}

uiClosed();
}

private:
struct Pool {
float* buffer[2];
uint32_t startFrame;
uint32_t size;

Pool()
: buffer{nullptr},
startFrame(0),
size(0) {}

~Pool()
{
CARLA_ASSERT(buffer[0] == nullptr);
CARLA_ASSERT(buffer[1] == nullptr);
CARLA_ASSERT(startFrame == 0);
CARLA_ASSERT(size == 0);
}

void create(const uint32_t sampleRate)
{
CARLA_ASSERT(buffer[0] == nullptr);
CARLA_ASSERT(buffer[1] == nullptr);
CARLA_ASSERT(startFrame == 0);
CARLA_ASSERT(size == 0);

size = sampleRate * 6;

buffer[0] = new float[size];
buffer[1] = new float[size];

carla_zeroFloat(buffer[0], size);
carla_zeroFloat(buffer[1], size);
}

void destroy()
{
CARLA_ASSERT(buffer[0] != nullptr);
CARLA_ASSERT(buffer[1] != nullptr);
CARLA_ASSERT(size != 0);

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

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

startFrame = 0;
size = 0;
}
};

struct Programs {
uint32_t current;
CarlaString fullNames[PROGRAM_COUNT];
CarlaString shortNames[PROGRAM_COUNT];

Programs()
: current(0) {}
};

class AudioFileThread : public QThread
{
public:
AudioFileThread()
: QThread(nullptr),
fNeedsRead(false),
fQuitNow(true),
fLastFrame(0),
fPoolStartFrame(0),
fPoolSize(0)
{
}

~AudioFileThread()
{
CARLA_ASSERT(fQuitNow == true);
CARLA_ASSERT(! isRunning());
}

void stopNow()
{
fNeedsRead = false;
fQuitNow = true;

if (isRunning() && ! wait(1000))
terminate();
}

void readPoll()
{
}

void setNeedsRead()
{
fNeedsRead = true;
}

void setLastFrame(const uint32_t lastFrame)
{
fLastFrame = lastFrame;
}

void setPoolStart(const uint32_t poolStartFrame)
{
fPoolStartFrame = poolStartFrame;
}

void setPoolSize(const uint32_t poolSize)
{
fPoolSize = poolSize;
}

protected:
void run() override
{
while (! fQuitNow)
{
if (fNeedsRead || (fLastFrame >= fPoolStartFrame && fLastFrame - fPoolStartFrame >= fPoolSize*3/4))
readPoll();
else
carla_msleep(50);
}
}

private:
bool fNeedsRead;
bool fQuitNow;

uint32_t fLastFrame;
uint32_t fPoolStartFrame;
uint32_t fPoolSize;
};

void* filePtr;
ADInfo fileNfo;

uint32_t lastFrame;
uint32_t maxFrame;

bool loopMode;
bool doProcess;

Pool pool;
Programs programs;

CarlaMutex mutex;
AudioFileThread thread;

void loadFilename(const char* const filename)
{
// wait for jack processing to end
doProcess = false;

{
const CarlaMutex::ScopedLocker sl(&mutex);

maxFrame = 0;
pool.startFrame = 0;

thread.stopNow();
}

// clear old data
if (filePtr != nullptr)
{
ad_close(filePtr);
filePtr = nullptr;
}

ad_clear_nfo(&fileNfo);

if (filename == nullptr)
return;

// open new
filePtr = ad_open(filename, &fileNfo);

if (filePtr == nullptr)
return;

ad_dump_nfo(99, &fileNfo);

if (fileNfo.frames == 0)
carla_stderr("L: filename \"%s\" has 0 frames", filename);

if ((fileNfo.channels == 1 || fileNfo.channels == 2) && fileNfo.frames > 0)
{
maxFrame = fileNfo.frames;
thread.readPoll();
doProcess = true;

thread.start();
}
else
{
ad_clear_nfo(&fileNfo);
ad_close(filePtr);
filePtr = nullptr;
}
}

PluginDescriptorClassEND(AudioFilePlugin)
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AudioFilePlugin)
};

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

static const PluginDescriptor audiofileDesc = {
/* category */ PLUGIN_CATEGORY_UTILITY,
/* hints */ static_cast<PluginHints>(PLUGIN_HAS_GUI),
/* audioIns */ 0,
/* audioOuts */ 2,
/* midiIns */ 0,
/* midiOuts */ 0,
/* paramIns */ 1,
/* paramOuts */ 0,
/* name */ "Audio File",
/* label */ "audiofile",
/* maker */ "falkTX",
/* copyright */ "GNU GPL v2+",
PluginDescriptorFILL(AudioFilePlugin)
};

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

void carla_register_native_plugin_audiofile()
{
carla_register_native_plugin(&audiofileDesc);
}

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

+ 0
- 702
source/backend/native/audiofile.c View File

@@ -1,702 +0,0 @@
/*
* Carla Native Plugins
* Copyright (C) 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
*/

#include "CarlaNative.h"

#include "audio_decoder/ad.h"

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define PROGRAM_COUNT 16

#ifdef _WIN32
# define OS_SEP '\\'
#else
# define OS_SEP '/'
#endif

typedef struct adinfo ADInfo;
typedef pthread_mutex_t Mutex;
typedef pthread_t Thread;

typedef struct _AudioFilePool {
float* buffer[2];
uint32_t startFrame;
uint32_t size;

} AudioFilePool;

typedef struct _AudioFilePrograms {
uint32_t current;
const char* fullNames[PROGRAM_COUNT];
const char* shortNames[PROGRAM_COUNT];
} AudioFilePrograms;

typedef struct _AudioFileInstance {
HostDescriptor* host;

void* filePtr;
ADInfo fileNfo;

uint32_t lastFrame;
uint32_t maxFrame;
AudioFilePool pool;
AudioFilePrograms programs;

bool loopMode;
bool needsRead;
bool doProcess;
bool doQuit;

Mutex mutex;
Thread thread;

} AudioFileInstance;

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

void zeroFloat(float* data, unsigned size)
{
for (unsigned i=0; i < size; ++i)
*data++ = 0.0f;
}

void audiofile_read_poll(AudioFileInstance* const handlePtr)
{
if (handlePtr == NULL)
{
fprintf(stderr, "R: invalid instance\n");
return;
}

if (handlePtr->fileNfo.frames == 0 || handlePtr->maxFrame == 0)
{
//fprintf(stderr, "R: no song loaded\n");
handlePtr->needsRead = false;
return;
}

int64_t lastFrame = handlePtr->lastFrame;
int64_t readFrame = lastFrame;

if (lastFrame >= handlePtr->maxFrame)
{
if (handlePtr->loopMode)
{
//fprintf(stderr, "R: DEBUG read loop, lastFrame:%i, maxFrame:%i\n", handlePtr->lastFrame, handlePtr->maxFrame);

if (handlePtr->maxFrame >= handlePtr->pool.size)
{
readFrame %= handlePtr->maxFrame;
}
else
{
readFrame = 0;
lastFrame -= lastFrame % handlePtr->maxFrame;
}
}
else
{
//fprintf(stderr, "R: transport out of bounds\n");
handlePtr->needsRead = false;
return;
}
}

// temp data buffer
const uint32_t tmpSize = handlePtr->pool.size * handlePtr->fileNfo.channels;

float tmpData[tmpSize];
zeroFloat(tmpData, tmpSize);

{
fprintf(stderr, "R: poll data - reading at %li:%02li\n", readFrame/44100/60, (readFrame/44100) % 60);

ad_seek(handlePtr->filePtr, readFrame);
ssize_t i, j, rv = ad_read(handlePtr->filePtr, tmpData, tmpSize);
i = j = 0;

// lock, and put data asap
pthread_mutex_lock(&handlePtr->mutex);

for (; i < handlePtr->pool.size && j < rv; ++j)
{
if (handlePtr->fileNfo.channels == 1)
{
handlePtr->pool.buffer[0][i] = tmpData[j];
handlePtr->pool.buffer[1][i] = tmpData[j];
i++;
}
else
{
if (j % 2 == 0)
{
handlePtr->pool.buffer[0][i] = tmpData[j];
}
else
{
handlePtr->pool.buffer[1][i] = tmpData[j];
i++;
}
}
}

if (handlePtr->loopMode && i < handlePtr->pool.size)
{
while (i < handlePtr->pool.size)
{
for (j=0; i < handlePtr->pool.size && j < rv; ++j)
{
if (handlePtr->fileNfo.channels == 1)
{
handlePtr->pool.buffer[0][i] = tmpData[j];
handlePtr->pool.buffer[1][i] = tmpData[j];
i++;
}
else
{
if (j % 2 == 0)
{
handlePtr->pool.buffer[0][i] = tmpData[j];
}
else
{
handlePtr->pool.buffer[1][i] = tmpData[j];
i++;
}
}
}
}
}
else
{
for (; i < handlePtr->pool.size; ++i)
{
handlePtr->pool.buffer[0][i] = 0.0f;
handlePtr->pool.buffer[1][i] = 0.0f;
}
}

handlePtr->pool.startFrame = lastFrame;

// done
pthread_mutex_unlock(&handlePtr->mutex);
}

handlePtr->needsRead = false;
}

static void audiofile_thread_idle(void* ptr)
{
AudioFileInstance* const handlePtr = (AudioFileInstance*)ptr;

while (! handlePtr->doQuit)
{
if (handlePtr->needsRead || handlePtr->lastFrame - handlePtr->pool.startFrame >= handlePtr->pool.size*3/4)
audiofile_read_poll(handlePtr);
else
usleep(50*1000);
}

pthread_exit(NULL);
}

void audiofile_load_filename(AudioFileInstance* const handlePtr, const char* const filename)
{
// wait for jack processing to end
handlePtr->doProcess = false;
pthread_mutex_lock(&handlePtr->mutex);

handlePtr->maxFrame = 0;
handlePtr->pool.startFrame = 0;

// stop thread
if (! handlePtr->doQuit)
{
handlePtr->doQuit = true;
pthread_join(handlePtr->thread, NULL);
}

pthread_mutex_unlock(&handlePtr->mutex);

// clear old data
if (handlePtr->filePtr != NULL)
{
ad_close(handlePtr->filePtr);
handlePtr->filePtr = NULL;
}
ad_clear_nfo(&handlePtr->fileNfo);

if (filename == NULL)
return;

// open new
handlePtr->filePtr = ad_open(filename, &handlePtr->fileNfo);

if (handlePtr->filePtr != NULL)
{
ad_dump_nfo(99, &handlePtr->fileNfo);

if (handlePtr->fileNfo.frames == 0)
fprintf(stderr, "L: filename \"%s\" has 0 frames\n", filename);

if ((handlePtr->fileNfo.channels == 1 || handlePtr->fileNfo.channels == 2) && handlePtr->fileNfo.frames > 0)
{
handlePtr->maxFrame = handlePtr->fileNfo.frames;
audiofile_read_poll(handlePtr);
handlePtr->doProcess = true;

// start thread
handlePtr->doQuit = false;
pthread_create(&handlePtr->thread, NULL, (void*)&audiofile_thread_idle, handlePtr);
}
else
{
ad_close(handlePtr->filePtr);
handlePtr->filePtr = NULL;
ad_clear_nfo(&handlePtr->fileNfo);
}
}
}

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

static bool gADInitiated = false;

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

static PluginHandle audiofile_instantiate(const PluginDescriptor* _this_, HostDescriptor* host)
{
AudioFileInstance* const handlePtr = (AudioFileInstance*)malloc(sizeof(AudioFileInstance));

if (handlePtr == NULL)
return NULL;

if (! gADInitiated)
{
ad_init();
gADInitiated = true;
}

// init
handlePtr->host = host;
handlePtr->filePtr = NULL;
handlePtr->lastFrame = 0;
handlePtr->maxFrame = 0;
handlePtr->pool.buffer[0] = NULL;
handlePtr->pool.buffer[1] = NULL;
handlePtr->pool.startFrame = 0;
handlePtr->pool.size = 0;
handlePtr->programs.current = 0;

handlePtr->loopMode = false;
handlePtr->needsRead = false;
handlePtr->doProcess = false;
handlePtr->doQuit = true;

ad_clear_nfo(&handlePtr->fileNfo);
pthread_mutex_init(&handlePtr->mutex, NULL);

for (uint32_t i=0; i < PROGRAM_COUNT; ++i)
{
handlePtr->programs.fullNames[i] = NULL;
handlePtr->programs.shortNames[i] = NULL;
}

// create audio pool
handlePtr->pool.size = host->get_sample_rate(host->handle) * 6; // 6 secs

handlePtr->pool.buffer[0] = (float*)malloc(sizeof(float) * handlePtr->pool.size);
if (handlePtr->pool.buffer[0] == NULL)
{
free(handlePtr);
return NULL;
}

handlePtr->pool.buffer[1] = (float*)malloc(sizeof(float) * handlePtr->pool.size);
if (handlePtr->pool.buffer[1] == NULL)
{
free(handlePtr->pool.buffer[0]);
free(handlePtr);
return NULL;
}

zeroFloat(handlePtr->pool.buffer[0], handlePtr->pool.size);
zeroFloat(handlePtr->pool.buffer[1], handlePtr->pool.size);

return handlePtr;

// unused
(void)_this_;
}

static void audiofile_cleanup(PluginHandle handle)
{
AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;

// wait for processing to end
handlePtr->doProcess = false;
pthread_mutex_lock(&handlePtr->mutex);

// stop thread
if (! handlePtr->doQuit)
{
handlePtr->doQuit = true;
pthread_join(handlePtr->thread, NULL);
}

pthread_mutex_unlock(&handlePtr->mutex);
pthread_mutex_destroy(&handlePtr->mutex);

if (handlePtr->filePtr != NULL)
ad_close(handlePtr->filePtr);

if (handlePtr->pool.buffer[0] != NULL)
free(handlePtr->pool.buffer[0]);

if (handlePtr->pool.buffer[1] != NULL)
free(handlePtr->pool.buffer[1]);

for (uint32_t i=0; i < PROGRAM_COUNT; ++i)
{
if (handlePtr->programs.fullNames[i] != NULL)
free((void*)handlePtr->programs.fullNames[i]);
if (handlePtr->programs.shortNames[i] != NULL)
free((void*)handlePtr->programs.shortNames[i]);
}

free(handlePtr);
}

static uint32_t audiofile_get_parameter_count(PluginHandle handle)
{
return 0; // FIXME - loop mode needs work

// unused
(void)handle;
}

static const Parameter* audiofile_get_parameter_info(PluginHandle handle, uint32_t index)
{
// FIXME - loop mode needs work
return NULL;

if (index != 0)
return NULL;

static Parameter param;

param.name = "Loop Mode";
param.unit = NULL;
param.hints = PARAMETER_IS_ENABLED|PARAMETER_IS_BOOLEAN;
param.ranges.def = 1.0f;
param.ranges.min = 0.0f;
param.ranges.max = 1.0f;
param.ranges.step = 1.0f;
param.ranges.stepSmall = 1.0f;
param.ranges.stepLarge = 1.0f;
param.scalePointCount = 0;
param.scalePoints = NULL;

return &param;

// unused
(void)handle;
}

static float audiofile_get_parameter_value(PluginHandle handle, uint32_t index)
{
// FIXME - loop mode needs work
return 0.0f;

AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;

if (index != 0)
return 0.0f;

return handlePtr->loopMode ? 1.0f : 0.0f;

// unused
(void)handle;
}

static uint32_t audiofile_get_program_count(PluginHandle handle)
{
return PROGRAM_COUNT;

// unused
(void)handle;
}

const MidiProgram* audiofile_get_program_info(PluginHandle handle, uint32_t index)
{
AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;

if (index >= PROGRAM_COUNT)
return NULL;

static MidiProgram midiProgram;

midiProgram.bank = 0;
midiProgram.program = index;
midiProgram.name = handlePtr->programs.shortNames[index];

if (midiProgram.name == NULL)
midiProgram.name = "";

return &midiProgram;
}

static void audiofile_set_parameter_value(PluginHandle handle, uint32_t index, float value)
{
// FIXME - loop mode needs work
return;

AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;

if (index != 0)
return;

handlePtr->loopMode = (value > 0.5f);
handlePtr->needsRead = true;
}

static void audiofile_set_program(PluginHandle handle, uint8_t channel, uint32_t bank, uint32_t program)
{
AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;

if (bank != 0 || program >= PROGRAM_COUNT)
return;

if (handlePtr->programs.current != program)
{
audiofile_load_filename(handlePtr, handlePtr->programs.fullNames[program]);
handlePtr->programs.current = program;
}

return;

// unused
(void)channel;
}

static void audiofile_set_custom_data(PluginHandle handle, const char* key, const char* value)
{
AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;

if (strncmp(key, "file", 4) != 0)
return;
if (key[4] < '0' || key[4] > '9')
return;
if (key[5] < '0' || key[5] > '9')
return;

uint8_t tens = key[4]-'0';
uint8_t nums = key[5]-'0';

uint32_t program = tens*10 + nums;

if (program >= PROGRAM_COUNT)
return;

if (handlePtr->programs.fullNames[program] != NULL)
free((void*)handlePtr->programs.fullNames[program]);
if (handlePtr->programs.shortNames[program] != NULL)
free((void*)handlePtr->programs.shortNames[program]);

handlePtr->programs.fullNames[program] = strdup(value);

{
const char* shortName1 = strrchr(value, OS_SEP)+1;
//const char* shortName2 = strchr(shortName1, '.');

handlePtr->programs.shortNames[program] = strdup(shortName1);
}

if (handlePtr->programs.current == program)
audiofile_load_filename(handlePtr, value);
}

static void audiofile_ui_show(PluginHandle handle, bool show)
{
AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;

if (! show)
return;

const char* const filename = handlePtr->host->ui_open_file(handlePtr->host->handle, false, "Open Audio File", "");

if (filename != NULL)
{
char fileStr[4+2+1] = { 'f', 'i', 'l', 'e', 0, 0, 0 };
fileStr[4] = '0' + (handlePtr->programs.current / 10);
fileStr[5] = '0' + (handlePtr->programs.current % 10);

handlePtr->host->ui_custom_data_changed(handlePtr->host->handle, fileStr, filename);
}

handlePtr->host->ui_closed(handlePtr->host->handle);
}

static void audiofile_process(PluginHandle handle, float** inBuffer, float** outBuffer, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents)
{
AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;

const TimeInfo* const timePos = handlePtr->host->get_time_info(handlePtr->host->handle);

float* out1 = outBuffer[0];
float* out2 = outBuffer[1];

if (! handlePtr->doProcess)
{
//fprintf(stderr, "P: no process\n");
handlePtr->lastFrame = timePos->frame;

zeroFloat(out1, frames);
zeroFloat(out2, frames);
return;
}

// not playing
if (! timePos->playing)
{
//fprintf(stderr, "P: not rolling\n");

if (timePos->frame == 0 && handlePtr->lastFrame > 0)
handlePtr->needsRead = true;

handlePtr->lastFrame = timePos->frame;

zeroFloat(out1, frames);
zeroFloat(out2, frames);
return;
}

pthread_mutex_lock(&handlePtr->mutex);

// out of reach
if (timePos->frame + frames < handlePtr->pool.startFrame || (timePos->frame >= handlePtr->maxFrame && ! handlePtr->loopMode))
{
//fprintf(stderr, "P: non-continuous playback, out of reach %u vs %u\n", timePos->frame + frames, handlePtr->maxFrame);
handlePtr->lastFrame = timePos->frame;
handlePtr->needsRead = true;
pthread_mutex_unlock(&handlePtr->mutex);

zeroFloat(out1, frames);
zeroFloat(out2, frames);
return;
}

int64_t poolFrame = (int64_t)timePos->frame - handlePtr->pool.startFrame;
int64_t poolSize = handlePtr->pool.size;

for (uint32_t i=0; i < frames; ++i, ++poolFrame)
{
if (poolFrame >= 0 && poolFrame < poolSize)
{
out1[i] = handlePtr->pool.buffer[0][poolFrame];
out2[i] = handlePtr->pool.buffer[1][poolFrame];

// reset
handlePtr->pool.buffer[0][poolFrame] = 0.0f;
handlePtr->pool.buffer[1][poolFrame] = 0.0f;
}
else
{
out1[i] = 0.0f;
out2[i] = 0.0f;
}
}

handlePtr->lastFrame = timePos->frame;
pthread_mutex_unlock(&handlePtr->mutex);

return;

// unused
(void)inBuffer;
(void)midiEventCount;
(void)midiEvents;
}

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

static const PluginDescriptor audiofileDesc = {
.category = PLUGIN_CATEGORY_UTILITY,
.hints = PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI,
.audioIns = 0,
.audioOuts = 2,
.midiIns = 0,
.midiOuts = 0,
.parameterIns = 1,
.parameterOuts = 0,
.name = "Audio File",
.label = "audiofile",
.maker = "falkTX",
.copyright = "GNU GPL v2+",

.instantiate = audiofile_instantiate,
.cleanup = audiofile_cleanup,

.get_parameter_count = audiofile_get_parameter_count,
.get_parameter_info = audiofile_get_parameter_info,
.get_parameter_value = audiofile_get_parameter_value,
.get_parameter_text = NULL,

.get_midi_program_count = audiofile_get_program_count,
.get_midi_program_info = audiofile_get_program_info,

.set_parameter_value = audiofile_set_parameter_value,
.set_midi_program = audiofile_set_program,
.set_custom_data = audiofile_set_custom_data,

.ui_show = audiofile_ui_show,
.ui_idle = NULL,

.ui_set_parameter_value = NULL,
.ui_set_midi_program = NULL,
.ui_set_custom_data = NULL,

.activate = NULL,
.deactivate = NULL,
.process = audiofile_process,

.get_state = NULL,
.set_state = NULL,

.dispatcher = NULL
};

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

void carla_register_native_plugin_audiofile()
{
carla_register_native_plugin(&audiofileDesc);
}

// -----------------------------------------------------------------------
// amalgamated build

#include "audio_decoder/ad_ffmpeg.c"
#include "audio_decoder/ad_plugin.c"
#include "audio_decoder/ad_soundfile.c"

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

+ 0
- 53
source/backend/native/carla_native.pro View File

@@ -1,53 +0,0 @@
# QtCreator project file

QT = core gui

CONFIG = debug
CONFIG += link_pkgconfig qt shared warn_on

DEFINES = DEBUG
DEFINES += HAVE_CPP11_SUPPORT
DEFINES += QTCREATOR_TEST

# ZynAddSubFX
DEFINES += WANT_ZYNADDSUBFX

PKGCONFIG = fftw3 mxml

TARGET = carla_native
TEMPLATE = lib
VERSION = 0.5.0

SOURCES = \
bypass.c \
midi-split.c \
midi-through.c \
zynaddsubfx.cpp \
zynaddsubfx-src.cpp

SOURCES += \
distrho-3bandeq.cpp

HEADERS = \
../carla_native.h \
../carla_native.hpp

HEADERS += \
distrho/DistrhoPluginCarla.cpp

HEADERS += \
../../includes/carla_defines.hpp \
../../includes/carla_midi.h \
../../utils/carla_utils.hpp \
../../utils/carla_juce_utils.hpp

INCLUDEPATH = . .. \
3bandeq distrho \
../../includes \
../../utils \
../../libs/distrho-plugin-toolkit

LIBS = -lGL -lpthread

QMAKE_CFLAGS *= -std=c99
QMAKE_CXXFLAGS *= -std=c++0x

+ 2
- 2
source/backend/native/distrho-3bandeq.cpp View File

@@ -30,8 +30,8 @@ START_NAMESPACE_DISTRHO
// -----------------------------------------------------------------------

static const PluginDescriptor tBandEqDesc = {
/* category */ ::PLUGIN_CATEGORY_EQ,
/* hints */ static_cast<PluginHints>(::PLUGIN_IS_RTSAFE | ::PLUGIN_HAS_GUI),
/* category */ PLUGIN_CATEGORY_EQ,
/* hints */ static_cast<PluginHints>(PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI),
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS,
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS,
/* midiIns */ 0,


+ 2
- 2
source/backend/native/distrho-3bandsplitter.cpp View File

@@ -30,8 +30,8 @@ START_NAMESPACE_DISTRHO
// -----------------------------------------------------------------------

static const PluginDescriptor tBandSplitterDesc = {
/* category */ ::PLUGIN_CATEGORY_EQ,
/* hints */ static_cast<PluginHints>(::PLUGIN_IS_RTSAFE | ::PLUGIN_HAS_GUI),
/* category */ PLUGIN_CATEGORY_EQ,
/* hints */ static_cast<PluginHints>(PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI),
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS,
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS,
/* midiIns */ 0,


+ 2
- 2
source/backend/native/distrho-notes.cpp View File

@@ -29,8 +29,8 @@ START_NAMESPACE_DISTRHO
// -----------------------------------------------------------------------

static const PluginDescriptor notesDesc = {
/* category */ ::PLUGIN_CATEGORY_UTILITY,
/* hints */ static_cast<PluginHints>(::PLUGIN_IS_RTSAFE|::PLUGIN_HAS_GUI|::PLUGIN_USES_SINGLE_THREAD),
/* category */ PLUGIN_CATEGORY_UTILITY,
/* hints */ static_cast<PluginHints>(PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI|PLUGIN_USES_SINGLE_THREAD),
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS,
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS,
/* midiIns */ 0,


+ 2
- 2
source/backend/native/distrho-pingpongpan.cpp View File

@@ -30,8 +30,8 @@ START_NAMESPACE_DISTRHO
// -----------------------------------------------------------------------

static PluginDescriptor tBandEqDesc = {
/* category */ ::PLUGIN_CATEGORY_UTILITY,
/* hints */ static_cast<PluginHints>(::PLUGIN_IS_RTSAFE | ::PLUGIN_HAS_GUI),
/* category */ PLUGIN_CATEGORY_UTILITY,
/* hints */ static_cast<PluginHints>(PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI),
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS,
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS,
/* midiIns */ 0,


+ 62
- 64
source/backend/native/zynaddsubfx.cpp View File

@@ -433,7 +433,7 @@ private:
#endif

protected:
void run()
void run() override
{
while (! fQuit)
{
@@ -566,63 +566,6 @@ private:
static int sInstanceCount;
static NonRtList<ProgramInfo*> sPrograms;

public:
static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host)
{
if (sInstanceCount++ == 0)
{
CARLA_ASSERT(synth == nullptr);
CARLA_ASSERT(denormalkillbuf == nullptr);

synth = new SYNTH_T();
synth->buffersize = host->get_buffer_size(host->handle);
synth->samplerate = host->get_sample_rate(host->handle);
synth->alias();

config.init();
config.cfg.SoundBufferSize = synth->buffersize;
config.cfg.SampleRate = synth->samplerate;
config.cfg.GzipCompression = 0;

sprng(std::time(nullptr));
denormalkillbuf = new float[synth->buffersize];
for (int i=0; i < synth->buffersize; ++i)
denormalkillbuf[i] = (RND - 0.5f) * 1e-16;

Master::getInstance();

#ifdef WANT_ZYNADDSUBFX_UI
if (gPixmapPath.isEmpty())
{
gPixmapPath = host->resource_dir;
gPixmapPath += PIXMAP_PATH;
gUiPixmapPath = gPixmapPath;
}
#endif
}

return new ZynAddSubFxPlugin(host);
}

static void _cleanup(PluginHandle handle)
{
delete (ZynAddSubFxPlugin*)handle;

if (--sInstanceCount == 0)
{
CARLA_ASSERT(synth != nullptr);
CARLA_ASSERT(denormalkillbuf != nullptr);

Master::deleteInstance();

delete[] denormalkillbuf;
denormalkillbuf = nullptr;

delete synth;
synth = nullptr;
}
}

static void maybeInitPrograms(Master* const master)
{
static bool doSearch = true;
@@ -691,7 +634,64 @@ public:
}
}

static void clearPrograms()
public:
static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host)
{
if (sInstanceCount++ == 0)
{
CARLA_ASSERT(synth == nullptr);
CARLA_ASSERT(denormalkillbuf == nullptr);

synth = new SYNTH_T();
synth->buffersize = host->get_buffer_size(host->handle);
synth->samplerate = host->get_sample_rate(host->handle);
synth->alias();

config.init();
config.cfg.SoundBufferSize = synth->buffersize;
config.cfg.SampleRate = synth->samplerate;
config.cfg.GzipCompression = 0;

sprng(std::time(nullptr));
denormalkillbuf = new float[synth->buffersize];
for (int i=0; i < synth->buffersize; ++i)
denormalkillbuf[i] = (RND - 0.5f) * 1e-16;

Master::getInstance();

#ifdef WANT_ZYNADDSUBFX_UI
if (gPixmapPath.isEmpty())
{
gPixmapPath = host->resource_dir;
gPixmapPath += PIXMAP_PATH;
gUiPixmapPath = gPixmapPath;
}
#endif
}

return new ZynAddSubFxPlugin(host);
}

static void _cleanup(PluginHandle handle)
{
delete (ZynAddSubFxPlugin*)handle;

if (--sInstanceCount == 0)
{
CARLA_ASSERT(synth != nullptr);
CARLA_ASSERT(denormalkillbuf != nullptr);

Master::deleteInstance();

delete[] denormalkillbuf;
denormalkillbuf = nullptr;

delete synth;
synth = nullptr;
}
}

static void _clearPrograms()
{
for (auto it = sPrograms.begin(); it.valid(); it.next())
{
@@ -709,11 +709,9 @@ private:
int ZynAddSubFxPlugin::sInstanceCount = 0;
NonRtList<ZynAddSubFxPlugin::ProgramInfo*> ZynAddSubFxPlugin::sPrograms;

struct ProgramsDestructor {
ProgramsDestructor() {}
~ProgramsDestructor()
{
ZynAddSubFxPlugin::clearPrograms();
static const struct ProgramsDestructor {
~ProgramsDestructor() {
ZynAddSubFxPlugin::_clearPrograms();
}
} programsDestructor;



+ 0
- 1
source/backend/plugin/CarlaPlugin.pro View File

@@ -76,7 +76,6 @@ HEADERS += \
../../utils/CarlaString.hpp

INCLUDEPATH = . .. \
../engine \
../../includes \
../../libs \
../../utils


+ 1
- 0
source/backend/plugin/Lv2Plugin.cpp View File

@@ -4181,6 +4181,7 @@ public:
uint32_t i = 0;
while ((fDescriptor = descFn(i++)))
{
carla_debug("LV2 Init @%i => '%s' vs '%s'", i, fDescriptor->URI, uri);
if (std::strcmp(fDescriptor->URI, uri) == 0)
break;
}


+ 4
- 6
source/utils/CarlaString.hpp View File

@@ -195,15 +195,13 @@ public:

size_t rfind(const char c) const
{
size_t pos = 0;

for (size_t i=0; i < bufferLen; ++i)
for (size_t i=bufferLen; i > 0; --i)
{
if (buffer[i] == c)
pos = i;
if (buffer[i-1] == c)
return i-1;
}

return pos;
return 0;
}

void replace(const char before, const char after)


Loading…
Cancel
Save