Browse Source

Basic LinuxSampler (GIG+SFZ) support (plays audio)

tags/v0.9.0
falkTX 13 years ago
parent
commit
3e4cf55d86
7 changed files with 678 additions and 114 deletions
  1. +1
    -1
      src/carla-backend/Makefile
  2. +1
    -1
      src/carla-backend/carla_backend.cpp
  3. +2
    -1
      src/carla-backend/dssi.cpp
  4. +81
    -84
      src/carla-backend/fluidsynth.cpp
  5. +588
    -7
      src/carla-backend/linuxsampler.cpp
  6. +1
    -1
      src/carla-backend/qtcreator/carla-backend.pro
  7. +4
    -19
      src/carla-discovery/carla-discovery.cpp

+ 1
- 1
src/carla-backend/Makefile View File

@@ -13,7 +13,7 @@ CARLA_CXX_FLAGS += -DCARLA_BACKEND_NO_NAMESPACE -DCARLA_ENGINE_JACK $(CXXFLAGS)
CARLA_CXX_FLAGS += -DVESTIGE_HEADER -I../carla-includes/vestige # Comment this line to not use vestige header
CARLA_CXX_FLAGS += -DNDEBUG -DQT_NO_DEBUG -DQT_NO_DEBUG_STREAM -DQT_NO_DEBUG_OUTPUT -O2 -ffast-math -fomit-frame-pointer -fvisibility=hidden -mtune=generic -msse
# CARLA_CXX_FLAGS += -DDEBUG -O0 -g
CARLA_LINK_FLAGS = -shared -fPIC -ldl `pkg-config --libs jack fluidsynth liblo QtCore QtGui` $(LDFLAGS)
CARLA_LINK_FLAGS = -shared -fPIC -ldl `pkg-config --libs jack fluidsynth linuxsampler liblo QtCore QtGui` $(LDFLAGS)

OBJS = carla_backend.o carla_bridge.o carla_engine_jack.o carla_osc.o carla_shared.o carla_threads.o ladspa.o dssi.o lv2.o vst.o fluidsynth.o linuxsampler.o lv2-rtmempool/rtmempool.o



+ 1
- 1
src/carla-backend/carla_backend.cpp View File

@@ -1257,7 +1257,7 @@ int main(int argc, char* argv[])
if (engine_init("carla_demo"))
{
set_callback_function(main_callback);
short id = add_plugin_dssi("/usr/lib/dssi/calf.so", "Reverb", "/usr/lib/dssi/calf/calf_gtk");
short id = add_plugin_sfz("/home/falktx/Personal/Muzyks/Kits/SFZ/AcousticGuitarFREE/AcousticGuitarFREE Samples/AcousticGuitar.sfz", "xaxaxa");

if (id >= 0)
{


+ 2
- 1
src/carla-backend/dssi.cpp View File

@@ -928,7 +928,8 @@ public:
snd_seq_event_t* midi_event = &midi_events[midi_event_count];
memset(midi_event, 0, sizeof(snd_seq_event_t));

midi_event->type = extMidiNotes[i].onoff ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF;
midi_event->type = extMidiNotes[i].onoff ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF;
midi_event->time.tick = nframesOffset; // FIXME - other types may also need time-check here
midi_event->data.note.channel = cin_channel;
midi_event->data.note.note = extMidiNotes[i].note;
midi_event->data.note.velocity = extMidiNotes[i].velo;


+ 81
- 84
src/carla-backend/fluidsynth.cpp View File

@@ -82,9 +82,9 @@ public:
{
switch (param_id)
{
case Sf2ChorusType:
case FluidSynthChorusType:
return 2;
case Sf2Interpolation:
case FluidSynthInterpolation:
return 4;
default:
return 0;
@@ -103,7 +103,7 @@ public:
{
switch (param_id)
{
case Sf2ChorusType:
case FluidSynthChorusType:
switch (scalepoint_id)
{
case 0:
@@ -113,7 +113,7 @@ public:
default:
return FLUID_CHORUS_DEFAULT_TYPE;
}
case Sf2Interpolation:
case FluidSynthInterpolation:
switch (scalepoint_id)
{
case 0:
@@ -156,46 +156,46 @@ public:
{
switch (param_id)
{
case Sf2ReverbOnOff:
case FluidSynthReverbOnOff:
strncpy(buf_str, "Reverb On/Off", STR_MAX);
break;
case Sf2ReverbRoomSize:
case FluidSynthReverbRoomSize:
strncpy(buf_str, "Reverb Room Size", STR_MAX);
break;
case Sf2ReverbDamp:
case FluidSynthReverbDamp:
strncpy(buf_str, "Reverb Damp", STR_MAX);
break;
case Sf2ReverbLevel:
case FluidSynthReverbLevel:
strncpy(buf_str, "Reverb Level", STR_MAX);
break;
case Sf2ReverbWidth:
case FluidSynthReverbWidth:
strncpy(buf_str, "Reverb Width", STR_MAX);
break;
case Sf2ChorusOnOff:
case FluidSynthChorusOnOff:
strncpy(buf_str, "Chorus On/Off", STR_MAX);
break;
case Sf2ChorusNr:
case FluidSynthChorusNr:
strncpy(buf_str, "Chorus Voice Count", STR_MAX);
break;
case Sf2ChorusLevel:
case FluidSynthChorusLevel:
strncpy(buf_str, "Chorus Level", STR_MAX);
break;
case Sf2ChorusSpeedHz:
case FluidSynthChorusSpeedHz:
strncpy(buf_str, "Chorus Speed", STR_MAX);
break;
case Sf2ChorusDepthMs:
case FluidSynthChorusDepthMs:
strncpy(buf_str, "Chorus Depth", STR_MAX);
break;
case Sf2ChorusType:
case FluidSynthChorusType:
strncpy(buf_str, "Chorus Type", STR_MAX);
break;
case Sf2Polyphony:
case FluidSynthPolyphony:
strncpy(buf_str, "Polyphony", STR_MAX);
break;
case Sf2Interpolation:
case FluidSynthInterpolation:
strncpy(buf_str, "Interpolation", STR_MAX);
break;
case Sf2VoiceCount:
case FluidSynthVoiceCount:
strncpy(buf_str, "Voice Count", STR_MAX);
break;
default:
@@ -208,10 +208,10 @@ public:
{
switch (param_id)
{
case Sf2ChorusSpeedHz:
case FluidSynthChorusSpeedHz:
strncpy(buf_str, "Hz", STR_MAX);
break;
case Sf2ChorusDepthMs:
case FluidSynthChorusDepthMs:
strncpy(buf_str, "ms", STR_MAX);
break;
default:
@@ -224,7 +224,7 @@ public:
{
switch (param_id)
{
case Sf2ChorusType:
case FluidSynthChorusType:
switch (scalepoint_id)
{
case 0:
@@ -234,7 +234,7 @@ public:
strncpy(buf_str, "Triangle wave", STR_MAX);
return;
}
case Sf2Interpolation:
case FluidSynthInterpolation:
switch (scalepoint_id)
{
case 0:
@@ -263,19 +263,19 @@ public:

switch(param_id)
{
case Sf2ReverbOnOff:
case FluidSynthReverbOnOff:
value = value > 0.5 ? 1 : 0;
fluid_synth_set_reverb_on(f_synth, value);
break;

case Sf2ReverbRoomSize:
case Sf2ReverbDamp:
case Sf2ReverbLevel:
case Sf2ReverbWidth:
fluid_synth_set_reverb(f_synth, param_buffers[Sf2ReverbRoomSize], param_buffers[Sf2ReverbDamp], param_buffers[Sf2ReverbWidth], param_buffers[Sf2ReverbLevel]);
case FluidSynthReverbRoomSize:
case FluidSynthReverbDamp:
case FluidSynthReverbLevel:
case FluidSynthReverbWidth:
fluid_synth_set_reverb(f_synth, param_buffers[FluidSynthReverbRoomSize], param_buffers[FluidSynthReverbDamp], param_buffers[FluidSynthReverbWidth], param_buffers[FluidSynthReverbLevel]);
break;

case Sf2ChorusOnOff:
case FluidSynthChorusOnOff:
{
const CarlaPluginScopedDisabler m(this, ! CarlaEngine::isOffline());
value = value > 0.5 ? 1 : 0;
@@ -283,25 +283,25 @@ public:
break;
}

case Sf2ChorusNr:
case Sf2ChorusLevel:
case Sf2ChorusSpeedHz:
case Sf2ChorusDepthMs:
case Sf2ChorusType:
case FluidSynthChorusNr:
case FluidSynthChorusLevel:
case FluidSynthChorusSpeedHz:
case FluidSynthChorusDepthMs:
case FluidSynthChorusType:
{
const CarlaPluginScopedDisabler m(this, ! CarlaEngine::isOffline());
fluid_synth_set_chorus(f_synth, rint(param_buffers[Sf2ChorusNr]), param_buffers[Sf2ChorusLevel], param_buffers[Sf2ChorusSpeedHz], param_buffers[Sf2ChorusDepthMs], rint(param_buffers[Sf2ChorusType]));
fluid_synth_set_chorus(f_synth, rint(param_buffers[FluidSynthChorusNr]), param_buffers[FluidSynthChorusLevel], param_buffers[FluidSynthChorusSpeedHz], param_buffers[FluidSynthChorusDepthMs], rint(param_buffers[FluidSynthChorusType]));
break;
}

case Sf2Polyphony:
case FluidSynthPolyphony:
{
const CarlaPluginScopedDisabler m(this, ! CarlaEngine::isOffline());
fluid_synth_set_polyphony(f_synth, rint(value));
break;
}

case Sf2Interpolation:
case FluidSynthInterpolation:
{
const CarlaPluginScopedDisabler m(this, ! CarlaEngine::isOffline());
for (int i=0; i < 16; i++)
@@ -360,7 +360,7 @@ public:

uint32_t aouts, params, j;
aouts = 2;
params = Sf2ParametersMax;
params = FluidSynthParametersMax;

aout.ports = new CarlaEngineAudioPort*[aouts];
aout.rindexes = new uint32_t[aouts];
@@ -443,7 +443,7 @@ public:
param.port_cout = (CarlaEngineControlPort*)x_client->addPort(port_name, CarlaEnginePortTypeControl, false);

// ----------------------
j = Sf2ReverbOnOff;
j = FluidSynthReverbOnOff;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -459,7 +459,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2ReverbRoomSize;
j = FluidSynthReverbRoomSize;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -475,7 +475,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2ReverbDamp;
j = FluidSynthReverbDamp;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -491,7 +491,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2ReverbLevel;
j = FluidSynthReverbLevel;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -507,7 +507,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2ReverbWidth;
j = FluidSynthReverbWidth;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -523,7 +523,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2ChorusOnOff;
j = FluidSynthChorusOnOff;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -539,7 +539,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2ChorusNr;
j = FluidSynthChorusNr;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -555,7 +555,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2ChorusLevel;
j = FluidSynthChorusLevel;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -571,7 +571,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2ChorusSpeedHz;
j = FluidSynthChorusSpeedHz;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -587,7 +587,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2ChorusDepthMs;
j = FluidSynthChorusDepthMs;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -603,7 +603,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2ChorusType;
j = FluidSynthChorusType;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -619,7 +619,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2Polyphony;
j = FluidSynthPolyphony;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -635,7 +635,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2Interpolation;
j = FluidSynthInterpolation;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_INPUT;
@@ -651,7 +651,7 @@ public:
param_buffers[j] = param.ranges[j].def;

// ----------------------
j = Sf2VoiceCount;
j = FluidSynthVoiceCount;
param.data[j].index = j;
param.data[j].rindex = j;
param.data[j].type = PARAMETER_OUTPUT;
@@ -743,27 +743,24 @@ public:
callback_action(CALLBACK_RELOAD_PROGRAMS, m_id, 0, 0, 0.0);
#endif

if (init)
if (init && midiprog.count > 0)
{
if (midiprog.count > 0)
{
fluid_synth_program_reset(f_synth);
fluid_synth_program_reset(f_synth);

for (i=0; i < 16 && i != 9; i++)
{
for (i=0; i < 16 && i != 9; i++)
{
#ifdef FLUIDSYNTH_VERSION_NEW_API
fluid_synth_set_channel_type(f_synth, i, CHANNEL_TYPE_MELODIC);
fluid_synth_set_channel_type(f_synth, i, CHANNEL_TYPE_MELODIC);
#endif
fluid_synth_program_select(f_synth, i, f_id, midiprog.data[0].bank, midiprog.data[0].program);
}
fluid_synth_program_select(f_synth, i, f_id, midiprog.data[0].bank, midiprog.data[0].program);
}

#ifdef FLUIDSYNTH_VERSION_NEW_API
fluid_synth_set_channel_type(f_synth, 9, CHANNEL_TYPE_DRUM);
fluid_synth_set_channel_type(f_synth, 9, CHANNEL_TYPE_DRUM);
#endif
fluid_synth_program_select(f_synth, 9, f_id, 128, 0);
fluid_synth_program_select(f_synth, 9, f_id, 128, 0);

set_midi_program(0, false, false, false, true);
}
set_midi_program(0, false, false, false, true);
}
}

@@ -773,7 +770,7 @@ public:
void process(float** ains_buffer, float** aouts_buffer, uint32_t nframes, uint32_t nframesOffset)
{
uint32_t i, k;
unsigned int midi_event_count = 0;
uint32_t midi_event_count = 0;

double aouts_peak_tmp[2] = { 0.0 };

@@ -1154,7 +1151,7 @@ public:
if (nframesOffset == 0 || ! m_active_before)
param.port_cout->initBuffer(cout_buffer);

k = Sf2VoiceCount;
k = FluidSynthVoiceCount;
param_buffers[k] = rint(fluid_synth_get_active_voice_count(f_synth));
fix_parameter_value(param_buffers[k], param.ranges[k]);

@@ -1199,29 +1196,29 @@ public:
}

private:
enum Sf2InputParameters {
Sf2ReverbOnOff = 0,
Sf2ReverbRoomSize = 1,
Sf2ReverbDamp = 2,
Sf2ReverbLevel = 3,
Sf2ReverbWidth = 4,
Sf2ChorusOnOff = 5,
Sf2ChorusNr = 6,
Sf2ChorusLevel = 7,
Sf2ChorusSpeedHz = 8,
Sf2ChorusDepthMs = 9,
Sf2ChorusType = 10,
Sf2Polyphony = 11,
Sf2Interpolation = 12,
Sf2VoiceCount = 13,
Sf2ParametersMax = 14
enum FluidSynthInputParameters {
FluidSynthReverbOnOff = 0,
FluidSynthReverbRoomSize = 1,
FluidSynthReverbDamp = 2,
FluidSynthReverbLevel = 3,
FluidSynthReverbWidth = 4,
FluidSynthChorusOnOff = 5,
FluidSynthChorusNr = 6,
FluidSynthChorusLevel = 7,
FluidSynthChorusSpeedHz = 8,
FluidSynthChorusDepthMs = 9,
FluidSynthChorusType = 10,
FluidSynthPolyphony = 11,
FluidSynthInterpolation = 12,
FluidSynthVoiceCount = 13,
FluidSynthParametersMax = 14
};

fluid_settings_t* f_settings;
fluid_synth_t* f_synth;
int f_id;

double param_buffers[Sf2ParametersMax];
double param_buffers[FluidSynthParametersMax];
const char* m_label;
};



+ 588
- 7
src/carla-backend/linuxsampler.cpp View File

@@ -21,12 +21,124 @@

#include "carla_plugin.h"

#include <linuxsampler/Sampler.h>
#include "linuxsampler/EngineFactory.h"

#include <QtCore/QFileInfo>

CARLA_BACKEND_START_NAMESPACE

#if 0
} /* adjust editor indent */
#endif

#define LINUXSAMPLER_VOLUME_MAX 3.16227766f // +10 dB
#define LINUXSAMPLER_VOLUME_MIN 0.0f // -inf dB

class AudioOutputDevicePlugin : public LinuxSampler::AudioOutputDevice
{
public:
AudioOutputDevicePlugin(CarlaPlugin* plugin) :
AudioOutputDevice(std::map<String,LinuxSampler::DeviceCreationParameter*>()),
m_plugin(plugin)
{
}

// -------------------------------------------------------------------
// LinuxSampler virtual methods

void Play()
{
}

bool IsPlaying()
{
return m_plugin && m_plugin->enabled();
}

void Stop()
{
}

uint MaxSamplesPerCycle()
{
return get_buffer_size();
}

uint SampleRate()
{
return get_sample_rate();
}

String Driver()
{
return "AudioOutputDevicePlugin";
}

LinuxSampler::AudioChannel* CreateChannel(uint channelNr)
{
return new LinuxSampler::AudioChannel(channelNr, nullptr, 0);
}

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

int Render(uint samples)
{
return RenderAudio(samples);
}

private:
CarlaPlugin* m_plugin;
};

class MidiInputDevicePlugin : public LinuxSampler::MidiInputDevice
{
public:
MidiInputDevicePlugin(LinuxSampler::Sampler* sampler) : LinuxSampler::MidiInputDevice(std::map<String, LinuxSampler::DeviceCreationParameter*>(), sampler)
{
}

// -------------------------------------------------------------------
// MIDI Port implementation for this plugin MIDI input driver

class MidiInputPortPlugin : public LinuxSampler::MidiInputPort
{
protected:
MidiInputPortPlugin(MidiInputDevicePlugin* device, int portNumber) : LinuxSampler::MidiInputPort(device, portNumber)
{
}
friend class MidiInputDevicePlugin;
};

// -------------------------------------------------------------------
// LinuxSampler virtual methods

void Listen()
{
}

void StopListen()
{
}

String Driver()
{
return "MidiInputDevicePlugin";
}

LinuxSampler::MidiInputPort* CreateMidiPort()
{
return new MidiInputPortPlugin(this, Ports.size());
}

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

void DeleteMidiPort(LinuxSampler::MidiInputPort* port)
{
delete (MidiInputPortPlugin*)port;
}
};

class LinuxSamplerPlugin : public CarlaPlugin
{
public:
@@ -35,15 +147,42 @@ public:
qDebug("LinuxSamplerPlugin::LinuxSamplerPlugin()");
m_type = isGIG ? PLUGIN_GIG : PLUGIN_SFZ;

sampler = new LinuxSampler::Sampler;

audioOutputDevice = new AudioOutputDevicePlugin(this);
midiInputDevice = new MidiInputDevicePlugin(sampler);
midiInputPort = midiInputDevice->CreateMidiPort();

m_isGIG = isGIG;
m_name = nullptr;
m_label = nullptr;
m_maker = nullptr;
}

~LinuxSamplerPlugin()
{
qDebug("LinuxSamplerPlugin::~LinuxSamplerPlugin()");

if (sampler_channel)
{
midiInputPort->Disconnect(sampler_channel->GetEngineChannel());
sampler->RemoveSamplerChannel(sampler_channel);
}

midiInputDevice->DeleteMidiPort(midiInputPort);

delete audioOutputDevice;
delete midiInputDevice;
delete sampler;

if (m_name)
free((void*)m_name);

if (m_label)
free((void*)m_label);

if (m_maker)
free((void*)m_maker);
}

// -------------------------------------------------------------------
@@ -54,24 +193,466 @@ public:
return PLUGIN_CATEGORY_SYNTH;
}

// -------------------------------------------------------------------
// Information (per-plugin data)

void get_label(char* buf_str)
{
strncpy(buf_str, m_label, STR_MAX);
}

void get_maker(char* buf_str)
{
strncpy(buf_str, m_maker, STR_MAX);
}

void get_copyright(char* buf_str)
{
strncpy(buf_str, m_maker, STR_MAX);
}

void get_real_name(char* buf_str)
{
strncpy(buf_str, m_name, STR_MAX);
}

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

void reload()
{
qDebug("LinuxSamplerPlugin::reload() - start");

// Safely disable plugin for reload
const CarlaPluginScopedDisabler m(this);

if (x_client->isActive())
x_client->deactivate();

// Remove client ports
remove_client_ports();

// Delete old data
delete_buffers();

uint32_t aouts;
aouts = 2;

aout.ports = new CarlaEngineAudioPort*[aouts];
aout.rindexes = new uint32_t[aouts];

const int port_name_size = CarlaEngine::maxPortNameSize() - 1;
char port_name[port_name_size];

// ---------------------------------------
// Audio Outputs

#ifndef BUILD_BRIDGE
if (carla_options.global_jack_client)
{
strcpy(port_name, m_name);
strcat(port_name, ":out-left");
}
else
#endif
strcpy(port_name, "out-left");

aout.ports[0] = (CarlaEngineAudioPort*)x_client->addPort(port_name, CarlaEnginePortTypeAudio, false);
aout.rindexes[0] = 0;

#ifndef BUILD_BRIDGE
if (carla_options.global_jack_client)
{
strcpy(port_name, m_name);
strcat(port_name, ":out-right");
}
else
#endif
strcpy(port_name, "out-right");

aout.ports[1] = (CarlaEngineAudioPort*)x_client->addPort(port_name, CarlaEnginePortTypeAudio, false);
aout.rindexes[1] = 1;

// ---------------------------------------
// MIDI Input

#ifndef BUILD_BRIDGE
if (carla_options.global_jack_client)
{
strcpy(port_name, m_name);
strcat(port_name, ":midi-in");
}
else
#endif
strcpy(port_name, "midi-in");

midi.port_min = (CarlaEngineMidiPort*)x_client->addPort(port_name, CarlaEnginePortTypeMIDI, true);

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

aout.count = aouts;

// plugin checks
m_hints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE);

m_hints |= PLUGIN_IS_SYNTH;
m_hints |= PLUGIN_CAN_VOLUME;
m_hints |= PLUGIN_CAN_BALANCE;

reload_programs(true);

x_client->activate();

qDebug("LinuxSamplerPlugin::reload() - end");
}

void reload_programs(bool init)
{
qDebug("LinuxSamplerPlugin::reload_programs(%s)", bool2str(init));

// Delete old programs
if (midiprog.count > 0)
{
for (uint32_t i=0; i < midiprog.count; i++)
free((void*)midiprog.data[i].name);

delete[] midiprog.data;
}

midiprog.count = 0;
midiprog.data = nullptr;

// Query new programs
uint32_t i = 0;
midiprog.count += instrumentIds.size();

if (midiprog.count > 0)
midiprog.data = new midi_program_t [midiprog.count];

// Update data
for (i=0; i < midiprog.count; i++)
{
LinuxSampler::InstrumentManager::instrument_info_t info = instrument->GetInstrumentInfo(instrumentIds[i]);

midiprog.data[i].bank = 0;
midiprog.data[i].program = i;
midiprog.data[i].name = strdup(info.InstrumentName.c_str());
}

#ifndef BUILD_BRIDGE
// Update OSC Names
osc_global_send_set_midi_program_count(m_id, midiprog.count);

for (i=0; i < midiprog.count; i++)
osc_global_send_set_midi_program_data(m_id, i, midiprog.data[i].bank, midiprog.data[i].program, midiprog.data[i].name);

callback_action(CALLBACK_RELOAD_PROGRAMS, m_id, 0, 0, 0.0);
#endif

if (init && midiprog.count > 0)
{
set_midi_program(0, false, false, false, true);
}
}

// -------------------------------------------------------------------
// Plugin processing

void process(float** ains_buffer, float** aouts_buffer, uint32_t nframes, uint32_t nframesOffset = 0)
{
uint32_t i, k;
uint32_t midi_event_count = 0;

double aouts_peak_tmp[2] = { 0.0 };

CARLA_PROCESS_CONTINUE_CHECK;

// --------------------------------------------------------------------------------------------------------
// MIDI Input (External)

if (cin_channel >= 0 && cin_channel < 16 && m_active && m_active_before)
{
carla_midi_lock();

for (i=0; i < MAX_MIDI_EVENTS && midi_event_count < MAX_MIDI_EVENTS; i++)
{
if (extMidiNotes[i].valid)
{
if (extMidiNotes[i].onoff)
midiInputPort->DispatchNoteOn(extMidiNotes[i].note, extMidiNotes[i].velo, cin_channel, nframesOffset);
else
midiInputPort->DispatchNoteOff(extMidiNotes[i].note, extMidiNotes[i].velo, cin_channel, nframesOffset);

extMidiNotes[i].valid = false;
midi_event_count += 1;
}
else
break;
}

carla_midi_unlock();

} // End of MIDI Input (External)

CARLA_PROCESS_CONTINUE_CHECK;

// --------------------------------------------------------------------------------------------------------
// MIDI Input (System)

if (m_active && m_active_before)
{
void* min_buffer = midi.port_min->getBuffer();

const CarlaEngineMidiEvent* min_event;
uint32_t time, n_min_events = midi.port_min->getEventCount(min_buffer);

for (i=0; i < n_min_events && midi_event_count < MAX_MIDI_EVENTS; i++)
{
min_event = midi.port_min->getEvent(min_buffer, i);

if (! min_event)
continue;

time = min_event->time - nframesOffset;

if (time >= nframes)
continue;

uint8_t status = min_event->data[0];
uint8_t channel = status & 0x0F;

// Fix bad note-off
if (MIDI_IS_STATUS_NOTE_ON(status) && min_event->data[2] == 0)
status -= 0x10;

if (MIDI_IS_STATUS_NOTE_OFF(status))
{
uint8_t note = min_event->data[1];

midiInputPort->DispatchNoteOff(note, 0, channel, time);

if (channel == cin_channel)
postpone_event(PluginPostEventNoteOff, note, 0.0);
}
else if (MIDI_IS_STATUS_NOTE_ON(status))
{
uint8_t note = min_event->data[1];
uint8_t velo = min_event->data[2];

midiInputPort->DispatchNoteOn(note, velo, channel, time);

if (channel == cin_channel)
postpone_event(PluginPostEventNoteOn, note, velo);
}
else if (MIDI_IS_STATUS_AFTERTOUCH(status))
{
uint8_t pressure = min_event->data[1];

midiInputPort->DispatchControlChange(MIDI_STATUS_AFTERTOUCH, pressure, channel, time);
}
else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status))
{
uint8_t lsb = min_event->data[1];
uint8_t msb = min_event->data[2];

midiInputPort->DispatchPitchbend(((msb << 7) | lsb) - 8192, channel, time);
}
else
continue;

midi_event_count += 1;
}
} // End of MIDI Input (System)

CARLA_PROCESS_CONTINUE_CHECK;

// --------------------------------------------------------------------------------------------------------
// Plugin processing

if (m_active)
{
if (! m_active_before)
{
if (cin_channel >= 0 && cin_channel < 16)
{
midiInputPort->DispatchControlChange(MIDI_CONTROL_ALL_SOUND_OFF, 0, cin_channel);
midiInputPort->DispatchControlChange(MIDI_CONTROL_ALL_NOTES_OFF, 0, cin_channel);
}
}

audioOutputDevice->Channel(0)->SetBuffer(aouts_buffer[0]);
audioOutputDevice->Channel(1)->SetBuffer(aouts_buffer[1]);
// QUESTION: Need to clear it before?
audioOutputDevice->Render(nframes);
}

// --------------------------------------------------------------------------------------------------------
// Post-processing (dry/wet, volume and balance)

if (m_active)
{
bool do_volume = x_vol != 1.0;
bool do_balance = (x_bal_left != -1.0 || x_bal_right != 1.0);

double bal_rangeL, bal_rangeR;
float old_bal_left[do_balance ? nframes : 0];

for (i=0; i < aout.count; i++)
{
// Volume
if (do_volume)
{
for (k=0; k<nframes; k++)
aouts_buffer[i][k] *= x_vol;
}

// Balance
if (do_balance)
{
if (i%2 == 0)
memcpy(&old_bal_left, aouts_buffer[i], sizeof(float)*nframes);

bal_rangeL = (x_bal_left+1.0)/2;
bal_rangeR = (x_bal_right+1.0)/2;

for (k=0; k<nframes; k++)
{
if (i%2 == 0)
{
// left output
aouts_buffer[i][k] = old_bal_left[k]*(1.0-bal_rangeL);
aouts_buffer[i][k] += aouts_buffer[i+1][k]*(1.0-bal_rangeR);
}
else
{
// right
aouts_buffer[i][k] = aouts_buffer[i][k]*bal_rangeR;
aouts_buffer[i][k] += old_bal_left[k]*bal_rangeL;
}
}
}

// Output VU
for (k=0; k < nframes && i < 2; k++)
{
if (abs_d(aouts_buffer[i][k]) > aouts_peak_tmp[i])
aouts_peak_tmp[i] = abs_d(aouts_buffer[i][k]);
}
}
}
else
{
// disable any output sound if not active
for (i=0; i < aout.count; i++)
memset(aouts_buffer[i], 0.0f, sizeof(float)*nframes);

aouts_peak_tmp[0] = 0.0;
aouts_peak_tmp[1] = 0.0;

} // End of Post-processing

CARLA_PROCESS_CONTINUE_CHECK;

// --------------------------------------------------------------------------------------------------------
// Peak Values

aouts_peak[(m_id*2)+0] = aouts_peak_tmp[0];
aouts_peak[(m_id*2)+1] = aouts_peak_tmp[1];

m_active_before = m_active;
}

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

bool init(const char* filename, const char* label)
{
m_filename = strdup(filename);
m_label = strdup(label);
m_name = get_unique_name(label);
x_client = new CarlaEngineClient(this);
QFileInfo file(filename);

if (x_client->isOk())
return true;
if (file.exists() && file.isFile() && file.isReadable())
{
const char* stype = m_isGIG ? "gig" : "sfz";

try {
engine = LinuxSampler::EngineFactory::Create(stype);
}
catch (LinuxSampler::Exception& e)
{
set_last_error(e.what());
return false;
}

try {
instrument = engine->GetInstrumentManager();
}
catch (LinuxSampler::Exception& e)
{
set_last_error(e.what());
return false;
}

try {
instrumentIds = instrument->GetInstrumentFileContent(filename);
}
catch (LinuxSampler::Exception& e)
{
set_last_error(e.what());
return false;
}

if (instrumentIds.size() > 0)
{
LinuxSampler::InstrumentManager::instrument_info_t info = instrument->GetInstrumentInfo(instrumentIds[0]);

m_name = strdup(info.InstrumentName.c_str());
m_label = strdup(info.Product.c_str());
m_maker = strdup(info.Artists.c_str());
m_filename = strdup(filename);

sampler_channel = sampler->AddSamplerChannel();
sampler_channel->SetEngineType(stype);
sampler_channel->SetAudioOutputDevice(audioOutputDevice);
//sampler_channel->SetMidiInputDevice(midiInputDevice);
//sampler_channel->SetMidiInputChannel(LinuxSampler::midi_chan_1);
midiInputPort->Connect(sampler_channel->GetEngineChannel(), LinuxSampler::midi_chan_all);

engine_channel = sampler_channel->GetEngineChannel();
engine_channel->Connect(audioOutputDevice);
engine_channel->PrepareLoadInstrument(filename, 0); // todo - find instrument from label
engine_channel->LoadInstrument();
engine_channel->Volume(LINUXSAMPLER_VOLUME_MAX);

x_client = new CarlaEngineClient(this);

if (x_client->isOk())
return true;
else
set_last_error("Failed to register plugin client");
}
else
set_last_error("Failed to find any instruments");
}
else
set_last_error("Requested file is not valid or does not exist");

set_last_error("Failed to register plugin client");
return false;
}

private:
LinuxSampler::Sampler* sampler;
LinuxSampler::SamplerChannel* sampler_channel;
LinuxSampler::Engine* engine;
LinuxSampler::EngineChannel* engine_channel;
LinuxSampler::InstrumentManager* instrument;
std::vector<LinuxSampler::InstrumentManager::instrument_id_t> instrumentIds;

AudioOutputDevicePlugin* audioOutputDevice;
MidiInputDevicePlugin* midiInputDevice;
LinuxSampler::MidiInputPort* midiInputPort;

bool m_isGIG;
const char* m_name;
const char* m_label;
const char* m_maker;
};

short add_plugin_linuxsampler(const char* filename, const char* label, bool isGIG)


+ 1
- 1
src/carla-backend/qtcreator/carla-backend.pro View File

@@ -3,7 +3,7 @@
QT = core gui

CONFIG = debug link_pkgconfig qt warn_on
PKGCONFIG = jack liblo fluidsynth
PKGCONFIG = jack liblo fluidsynth linuxsampler

TARGET = carla_backend
TEMPLATE = app


+ 4
- 19
src/carla-discovery/carla-discovery.cpp View File

@@ -1150,25 +1150,10 @@ void do_linuxsampler_check(const char* filename, const char* stype)

QFileInfo file(filename);

if (! file.exists())
{
DISCOVERY_OUT("error", "Requested file does not exist");
return;
}

if (! file.isFile())
{
DISCOVERY_OUT("error", "Requested filename is not a file");
return;
}

if (! file.isReadable())
{
DISCOVERY_OUT("error", "Requested file is not readable");
return;
}

const ScopedEngine engine(filename, stype);
if (file.exists() && file.isFile() && file.isReadable())
const ScopedEngine engine(filename, stype);
else
DISCOVERY_OUT("error", "Requested file is not valid or does not exist");

#else
(void)filename;


Loading…
Cancel
Save