Browse Source

Added 16 stereo outs option for Soundfonts

tags/1.9.4
falkTX 11 years ago
parent
commit
4e4ef6cea9
10 changed files with 234 additions and 47 deletions
  1. +1
    -1
      source/backend/CarlaPlugin.hpp
  2. +1
    -1
      source/backend/engine/CarlaEngine.cpp
  3. +14
    -14
      source/backend/engine/CarlaEngineJack.cpp
  4. +3
    -3
      source/backend/plugin/DssiPlugin.cpp
  5. +143
    -24
      source/backend/plugin/FluidSynthPlugin.cpp
  6. +1
    -2
      source/backend/plugin/LadspaPlugin.cpp
  7. +8
    -0
      source/carla.py
  8. +5
    -0
      source/discovery/Makefile
  9. +34
    -2
      source/discovery/carla-discovery.cpp
  10. +24
    -0
      source/utils/CarlaString.hpp

+ 1
- 1
source/backend/CarlaPlugin.hpp View File

@@ -798,8 +798,8 @@ public:
static CarlaPlugin* newLV2(const Initializer& init);
static CarlaPlugin* newVST(const Initializer& init);
static CarlaPlugin* newGIG(const Initializer& init);
static CarlaPlugin* newSF2(const Initializer& init, const bool use16Outs);
static CarlaPlugin* newSFZ(const Initializer& init);
static CarlaPlugin* newSF2(const Initializer& init);

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



+ 1
- 1
source/backend/engine/CarlaEngine.cpp View File

@@ -713,7 +713,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, cons
break;

case PLUGIN_SF2:
plugin = CarlaPlugin::newSF2(init);
plugin = CarlaPlugin::newSF2(init, (extra != nullptr));
break;

case PLUGIN_SFZ:


+ 14
- 14
source/backend/engine/CarlaEngineJack.cpp View File

@@ -49,7 +49,7 @@ public:
kClient(client),
kPort(port)
{
qDebug("CarlaEngineJackAudioPort::CarlaEngineJackAudioPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port);
carla_debug("CarlaEngineJackAudioPort::CarlaEngineJackAudioPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port);

if (processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
@@ -63,7 +63,7 @@ public:

~CarlaEngineJackAudioPort()
{
qDebug("CarlaEngineJackAudioPort::~CarlaEngineJackAudioPort()");
carla_debug("CarlaEngineJackAudioPort::~CarlaEngineJackAudioPort()");

if (kClient != nullptr && kPort != nullptr)
jackbridge_port_unregister(kClient, kPort);
@@ -111,7 +111,7 @@ public:
kPort(port),
fJackBuffer(nullptr)
{
qDebug("CarlaEngineJackEventPort::CarlaEngineJackEventPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port);
carla_debug("CarlaEngineJackEventPort::CarlaEngineJackEventPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port);

if (processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
@@ -125,7 +125,7 @@ public:

~CarlaEngineJackEventPort()
{
qDebug("CarlaEngineJackEventPort::~CarlaEngineJackEventPort()");
carla_debug("CarlaEngineJackEventPort::~CarlaEngineJackEventPort()");

if (kClient != nullptr && kPort != nullptr)
jackbridge_port_unregister(kClient, kPort);
@@ -368,7 +368,7 @@ public:
kClient(client),
kUseClient(processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
qDebug("CarlaEngineJackClient::CarlaEngineJackClient(%s, %s, %p)", EngineType2Str(engineType), ProcessMode2Str(processMode), client);
carla_debug("CarlaEngineJackClient::CarlaEngineJackClient(%s, %s, %p)", EngineType2Str(engineType), ProcessMode2Str(processMode), client);

if (kUseClient)
{
@@ -382,7 +382,7 @@ public:

~CarlaEngineJackClient()
{
qDebug("CarlaEngineClient::~CarlaEngineClient()");
carla_debug("CarlaEngineClient::~CarlaEngineClient()");

if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
@@ -393,7 +393,7 @@ public:

void activate()
{
qDebug("CarlaEngineJackClient::activate()");
carla_debug("CarlaEngineJackClient::activate()");

if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
@@ -408,7 +408,7 @@ public:

void deactivate()
{
qDebug("CarlaEngineJackClient::deactivate()");
carla_debug("CarlaEngineJackClient::deactivate()");

if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
@@ -423,7 +423,7 @@ public:

bool isOk() const
{
qDebug("CarlaEngineJackClient::isOk()");
carla_debug("CarlaEngineJackClient::isOk()");

if (kUseClient)
return bool(kClient);
@@ -441,7 +441,7 @@ public:

const CarlaEnginePort* addPort(const EnginePortType portType, const char* const name, const bool isInput)
{
qDebug("CarlaEngineJackClient::addPort(%s, \"%s\", %s)", EnginePortType2Str(portType), name, bool2str(isInput));
carla_debug("CarlaEngineJackClient::addPort(%s, \"%s\", %s)", EnginePortType2Str(portType), name, bool2str(isInput));

jack_port_t* port = nullptr;

@@ -500,7 +500,7 @@ public:
#endif
fFreewheel(false)
{
qDebug("CarlaEngineJack::CarlaEngineJack()");
carla_debug("CarlaEngineJack::CarlaEngineJack()");

#ifdef BUILD_BRIDGE
fOptions.processMode = PROCESS_MODE_MULTIPLE_CLIENTS;
@@ -511,7 +511,7 @@ public:

~CarlaEngineJack()
{
qDebug("CarlaEngineJack::~CarlaEngineJack()");
carla_debug("CarlaEngineJack::~CarlaEngineJack()");
CARLA_ASSERT(fClient == nullptr);
}

@@ -539,7 +539,7 @@ public:

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

fFreewheel = false;
fTransportState = JackTransportStopped;
@@ -607,7 +607,7 @@ public:

bool close()
{
qDebug("CarlaEngineJack::close()");
carla_debug("CarlaEngineJack::close()");
CarlaEngine::close();

#ifdef BUILD_BRIDGE


+ 3
- 3
source/backend/plugin/DssiPlugin.cpp View File

@@ -53,10 +53,10 @@ public:
{
showGui(false);

// Wait a bit first, try safe quit, then force kill
// Wait a bit first, then force kill
if (kData->osc.thread.isRunning() && ! kData->osc.thread.stop(kData->engine->getOptions().oscUiTimeout))
{
carla_stderr("Failed to properly stop DSSI GUI thread");
carla_stderr("DSSI GUI thread still running, forcing termination now");
kData->osc.thread.terminate();
}
}
@@ -1170,7 +1170,7 @@ public:
const EngineMidiEvent& midiEvent = event.midi;

uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data);
uint8_t channel = event.channel;

// Fix bad note-off (per DSSI spec)
if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0)


+ 143
- 24
source/backend/plugin/FluidSynthPlugin.cpp View File

@@ -28,15 +28,22 @@ CARLA_BACKEND_START_NAMESPACE
class FluidSynthPlugin : public CarlaPlugin
{
public:
FluidSynthPlugin(CarlaEngine* const engine, const unsigned int id)
: CarlaPlugin(engine, id)
FluidSynthPlugin(CarlaEngine* const engine, const unsigned int id, const bool use16Outs)
: CarlaPlugin(engine, id),
kUses16Outs(use16Outs),
fSettings(nullptr),
fSynth(nullptr),
fSynthId(-1),
fAudio16Buffers(nullptr)
{
carla_debug("FluidSynthPlugin::FluidSynthPlugin()");
carla_debug("FluidSynthPlugin::FluidSynthPlugin(%p, %i, %s)", engine, id, bool2str(use16Outs));

// create settings
fSettings = new_fluid_settings();

// define settings
fluid_settings_setint(fSettings, "synth.audio-channels", use16Outs ? 16 : 1);
fluid_settings_setint(fSettings, "synth.audio-groups", use16Outs ? 16 : 1);
fluid_settings_setnum(fSettings, "synth.sample-rate", kData->engine->getSampleRate());
fluid_settings_setint(fSettings, "synth.threadsafe-api ", 0);

@@ -66,6 +73,8 @@ public:

delete_fluid_synth(fSynth);
delete_fluid_settings(fSettings);

deleteBuffers();
}

// -------------------------------------------------------------------
@@ -400,7 +409,7 @@ public:
deleteBuffers();

uint32_t aOuts, params, j;
aOuts = 2;
aOuts = kUses16Outs ? 32 : 2;
params = FluidSynthParametersMax;

kData->audioOut.createNew(aOuts);
@@ -412,7 +421,44 @@ public:
// ---------------------------------------
// Audio Outputs

if (kUses16Outs)
{
for (j=0; j < 32; j++)
{
portName.clear();

if (processMode == PROCESS_MODE_SINGLE_CLIENT)
{
portName = fName;
portName += ":";
}

portName += "out-";

if ((j+2)/2 < 9)
portName += "0";

portName += CarlaString((j+2)/2);

if (j % 2 == 0)
portName += "L";
else
portName += "R";

portName.truncate(portNameSize);

kData->audioOut.ports[j].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false);
kData->audioOut.ports[j].rindex = j;
}

fAudio16Buffers = new float*[aOuts];

for (j=0; j < aOuts; j++)
fAudio16Buffers[j] = nullptr;
}
else
{
// out-left
portName.clear();

if (processMode == PROCESS_MODE_SINGLE_CLIENT)
@@ -426,9 +472,8 @@ public:

kData->audioOut.ports[0].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false);
kData->audioOut.ports[0].rindex = 0;
}

{
// out-right
portName.clear();

if (processMode == PROCESS_MODE_SINGLE_CLIENT)
@@ -714,6 +759,7 @@ public:
fHints |= PLUGIN_CAN_BALANCE;
fHints |= PLUGIN_CAN_FORCE_STEREO;

bufferSizeChanged(kData->engine->getBufferSize());
reloadPrograms(true);

kData->client->activate();
@@ -819,7 +865,6 @@ public:
void process(float** const, float** const outBuffer, const uint32_t frames, const uint32_t framesOffset)
{
uint32_t i, k;
uint32_t midiEventCount = 0;

// --------------------------------------------------------------------------------------------------------
// Check if active
@@ -871,8 +916,6 @@ public:
fluid_synth_noteon(fSynth, note.channel, note.note, note.velo);
else
fluid_synth_noteoff(fSynth,note.channel, note.note);

midiEventCount += 1;
}

kData->extNotes.mutex.unlock();
@@ -905,7 +948,11 @@ public:

if (time > timeOffset)
{
fluid_synth_write_float(fSynth, time - timeOffset, outBuffer[0] + timeOffset, 0, 1, outBuffer[1] + timeOffset, 0, 1);
if (kUses16Outs)
processSingle(outBuffer, time - timeOffset, timeOffset);
else
fluid_synth_write_float(fSynth, time - timeOffset, outBuffer[0] + timeOffset, 0, 1, outBuffer[1] + timeOffset, 0, 1);

timeOffset = time;
}

@@ -1011,7 +1058,7 @@ public:
}

case kEngineControlEventTypeMidiBank:
if (event.channel < 16 && event.channel != 9) // FIXME
if (event.channel < 16)
nextBankIds[event.channel] = ctrlEvent.param;
break;

@@ -1068,13 +1115,10 @@ public:

case kEngineEventTypeMidi:
{
if (midiEventCount >= MAX_MIDI_EVENTS)
continue;

const EngineMidiEvent& midiEvent = event.midi;

uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data);
uint8_t channel = event.channel;

// Fix bad note-off
if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0)
@@ -1103,8 +1147,18 @@ public:
const uint8_t pressure = midiEvent.data[2];

// TODO, not in fluidsynth API?
Q_UNUSED(note);
Q_UNUSED(pressure);
continue;

// unused
(void)note;
(void)pressure;
}
else if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (fHints & PLUGIN_OPTION_SELF_AUTOMATION) != 0)
{
const uint8_t control = midiEvent.data[1];
const uint8_t value = midiEvent.data[2];

fluid_synth_cc(fSynth, channel, control, value);
}
else if (MIDI_IS_STATUS_AFTERTOUCH(status))
{
@@ -1122,8 +1176,6 @@ public:
else
continue;

midiEventCount += 1;

break;
}
}
@@ -1132,7 +1184,12 @@ public:
kData->postRtEvents.trySplice();

if (frames > timeOffset)
fluid_synth_write_float(fSynth, frames - timeOffset, outBuffer[0] + timeOffset, 0, 1, outBuffer[1] + timeOffset, 0, 1);
{
if (kUses16Outs)
processSingle(outBuffer, frames - timeOffset, timeOffset);
else
fluid_synth_write_float(fSynth, frames - timeOffset, outBuffer[0] + timeOffset, 0, 1, outBuffer[1] + timeOffset, 0, 1);
}

} // End of Event Input and Processing

@@ -1208,6 +1265,60 @@ public:
kData->activeBefore = kData->active;
}

void processSingle(float** const outBuffer, const uint32_t frames, const uint32_t timeOffset)
{
for (uint32_t i=0; i < kData->audioOut.count; i++)
carla_zeroFloat(fAudio16Buffers[i], frames);

fluid_synth_process(fSynth, frames, 0, nullptr, kData->audioOut.count, fAudio16Buffers);

for (uint32_t i=0, k; i < kData->audioOut.count; i++)
{
for (k=0; k < frames; k++)
outBuffer[i][k+timeOffset] = fAudio16Buffers[i][k];
}
}

void bufferSizeChanged(const uint32_t newBufferSize)
{
if (! kUses16Outs)
return;

for (uint32_t i=0; i < kData->audioOut.count; i++)
{
if (fAudio16Buffers[i] != nullptr)
delete[] fAudio16Buffers[i];
fAudio16Buffers[i] = new float[newBufferSize];
}
}

// -------------------------------------------------------------------
// Cleanup

void deleteBuffers()
{
carla_debug("FluidSynthPlugin::deleteBuffers() - start");

if (fAudio16Buffers != nullptr)
{
for (uint32_t i=0; i < kData->audioOut.count; i++)
{
if (fAudio16Buffers[i] != nullptr)
{
delete[] fAudio16Buffers[i];
fAudio16Buffers[i] = nullptr;
}
}

delete[] fAudio16Buffers;
fAudio16Buffers = nullptr;
}

CarlaPlugin::deleteBuffers();

carla_debug("FluidSynthPlugin::deleteBuffers() - end");
}

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

bool init(const char* const filename, const char* const name, const char* const label)
@@ -1271,13 +1382,16 @@ private:
FluidSynthParametersMax = 14
};

const bool kUses16Outs;

CarlaString fLabel;

fluid_settings_t* fSettings;
fluid_synth_t* fSynth;
int fSynthId;

double fParamBuffers[FluidSynthParametersMax];
float** fAudio16Buffers;
double fParamBuffers[FluidSynthParametersMax];
};

/**@}*/
@@ -1290,19 +1404,24 @@ CARLA_BACKEND_END_NAMESPACE

CARLA_BACKEND_START_NAMESPACE

CarlaPlugin* CarlaPlugin::newSF2(const Initializer& init)
CarlaPlugin* CarlaPlugin::newSF2(const Initializer& init, const bool use16Outs)
{
carla_debug("CarlaPlugin::newSF2({%p, \"%s\", \"%s\", \"%s\"})", init.engine, init.filename, init.name, init.label);

#ifdef WANT_FLUIDSYNTH

if (! fluid_is_soundfont(init.filename))
{
init.engine->setLastError("Requested file is not a valid SoundFont");
return nullptr;
}

FluidSynthPlugin* const plugin = new FluidSynthPlugin(init.engine, init.id);
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && use16Outs)
{
init.engine->setLastError("Carla's rack mode can only work with Stereo modules, please choose the 2-channel only SoundFont version");
return nullptr;
}

FluidSynthPlugin* const plugin = new FluidSynthPlugin(init.engine, init.id, use16Outs);

if (! plugin->init(init.filename, init.name, init.label))
{


+ 1
- 2
source/backend/plugin/LadspaPlugin.cpp View File

@@ -509,7 +509,7 @@ public:

if (max - min == 0.0f)
{
carla_stderr2("Broken plugin parameter: max - min == 0");
carla_stderr2("WARNING - Broken plugin parameter '%s': max - min == 0.0f", fDescriptor->PortNames[i]);
max = min + 0.1f;
}

@@ -1069,7 +1069,6 @@ public:
#endif
} // End of Post-processing


CARLA_PROCESS_CONTINUE_CHECK;

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


+ 8
- 0
source/carla.py View File

@@ -1075,6 +1075,14 @@ class CarlaMainW(QMainWindow):
if gui:
return gui.encode("utf-8")

elif ptype == PLUGIN_SF2:
if plugin['name'].endswith(" (16 outputs)"):
# return a dummy non-null pointer
INTPOINTER = POINTER(c_int)
ptr = c_int(0x1)
addr = addressof(ptr)
return cast(addr, INTPOINTER)

return c_nullptr

def loadRDFs(self):


+ 5
- 0
source/discovery/Makefile View File

@@ -86,3 +86,8 @@ carla-discovery-win64.exe: $(OBJS) ../libs/lilv_win64.a

clean:
rm -f carla-discovery-*

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

debug:
$(MAKE) DEBUG=true

+ 34
- 2
source/discovery/carla-discovery.cpp View File

@@ -1291,9 +1291,21 @@ void do_fluidsynth_check(const char* const filename, const bool init)
delete_fluid_settings(f_settings);
}

#if CARLA_OS_WIN
int sep = '\\';
#else
int sep = '/';
#endif

CarlaString name(std::strrchr(filename, sep)+1);
name.truncate(name.rfind('.'));

CarlaString label(name);

// 2 channels
DISCOVERY_OUT("init", "-----------");
DISCOVERY_OUT("name", "");
DISCOVERY_OUT("label", "");
DISCOVERY_OUT("name", (const char*)name);
DISCOVERY_OUT("label", (const char*)label);
DISCOVERY_OUT("maker", "");
DISCOVERY_OUT("copyright", "");
DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
@@ -1307,6 +1319,26 @@ void do_fluidsynth_check(const char* const filename, const bool init)
DISCOVERY_OUT("parameters.total", 14);
DISCOVERY_OUT("build", BINARY_NATIVE);
DISCOVERY_OUT("end", "------------");

// 16 channels
if (name.isNotEmpty())
name += " (16 outputs)";
DISCOVERY_OUT("init", "-----------");
DISCOVERY_OUT("name", "");
DISCOVERY_OUT("name", (const char*)name);
DISCOVERY_OUT("label", (const char*)label);
DISCOVERY_OUT("copyright", "");
DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
DISCOVERY_OUT("audio.outs", 32);
DISCOVERY_OUT("audio.total", 32);
DISCOVERY_OUT("midi.ins", 1);
DISCOVERY_OUT("midi.total", 1);
DISCOVERY_OUT("programs.total", programs);
DISCOVERY_OUT("parameters.ins", 13); // defined in Carla
DISCOVERY_OUT("parameters.outs", 1);
DISCOVERY_OUT("parameters.total", 14);
DISCOVERY_OUT("build", BINARY_NATIVE);
DISCOVERY_OUT("end", "------------");
#else
DISCOVERY_OUT("error", "SF2 support not available");
Q_UNUSED(filename);


+ 24
- 0
source/utils/CarlaString.hpp View File

@@ -187,6 +187,30 @@ public:
truncate(0);
}

size_t find(const char c)
{
for (size_t i=0; i < bufferLen; i++)
{
if (buffer[i] == c)
return i;
}

return 0;
}

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

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

return pos;
}

void replace(const char before, const char after)
{
if (after == '\0')


Loading…
Cancel
Save