Browse Source

Fluidsynth working; first attempts at sample-accurate automation

tags/1.9.4
falkTX 12 years ago
parent
commit
0e52cc7067
7 changed files with 839 additions and 811 deletions
  1. +1
    -1
      source/backend/Makefile.mk
  2. +4
    -2
      source/backend/engine/jack.cpp
  3. +2
    -1
      source/backend/plugin/carla_plugin.pro
  4. +146
    -122
      source/backend/plugin/dssi.cpp
  5. +592
    -632
      source/backend/plugin/fluidsynth.cpp
  6. +88
    -49
      source/backend/plugin/ladspa.cpp
  7. +6
    -4
      source/carla_shared.py

+ 1
- 1
source/backend/Makefile.mk View File

@@ -32,7 +32,7 @@ BUILD_CXX_FLAGS += -DWANT_JACK
endif

ifeq ($(HAVE_FLUIDSYNTH),true)
# BUILD_CXX_FLAGS += -DWANT_FLUIDSYNTH
BUILD_CXX_FLAGS += -DWANT_FLUIDSYNTH
endif

ifeq ($(HAVE_LINUXSAMPLER),true)


+ 4
- 2
source/backend/engine/jack.cpp View File

@@ -1044,8 +1044,10 @@ private:
float inPeaks[inCount];
float outPeaks[outCount];

carla_zeroFloat(inPeaks, inCount);
carla_zeroFloat(outPeaks, outCount);
if (inCount > 0)
carla_zeroFloat(inPeaks, inCount);
if (outCount > 0)
carla_zeroFloat(outPeaks, outCount);

for (uint32_t i=0; i < inCount; i++)
{


+ 2
- 1
source/backend/plugin/carla_plugin.pro View File

@@ -11,7 +11,8 @@ DEFINES += WANT_LADSPA WANT_DSSI
# WANT_LV2 WANT_VST

# Samplers
#DEFINES += WANT_FLUIDSYNTH WANT_LINUXSAMPLER
DEFINES += WANT_FLUIDSYNTH
# WANT_LINUXSAMPLER

# ZynAddSubFX
DEFINES += WANT_ZYNADDSUBFX


+ 146
- 122
source/backend/plugin/dssi.cpp View File

@@ -98,7 +98,7 @@ public:
// -------------------------------------------------------------------
// Information (base)

virtual PluginType type() const
PluginType type() const
{
return PLUGIN_DSSI;
}
@@ -891,13 +891,81 @@ public:
}

// --------------------------------------------------------------------------------------------------------
// Event Input
// Check if active before

if (kData->event.portIn != nullptr && kData->activeBefore)
if (! kData->activeBefore)
{
if (kData->event.portIn != nullptr)
{
for (k=0, i=MAX_MIDI_CHANNELS; k < MAX_MIDI_CHANNELS; k++)
{
carla_zeroStruct<snd_seq_event_t>(fMidiEvents[k]);
carla_zeroStruct<snd_seq_event_t>(fMidiEvents[k+i]);

fMidiEvents[k].type = SND_SEQ_EVENT_CONTROLLER;
fMidiEvents[k].data.control.channel = k;
fMidiEvents[k].data.control.param = MIDI_CONTROL_ALL_SOUND_OFF;

fMidiEvents[k+i].type = SND_SEQ_EVENT_CONTROLLER;
fMidiEvents[k+i].data.control.channel = k;
fMidiEvents[k+i].data.control.param = MIDI_CONTROL_ALL_NOTES_OFF;
}

midiEventCount = MAX_MIDI_CHANNELS*2;
}

if (kData->latency > 0)
{
for (i=0; i < kData->audioIn.count; i++)
carla_zeroFloat(kData->latencyBuffers[i], kData->latency);
}

if (fDescriptor->activate != nullptr)
{
fDescriptor->activate(fHandle);

if (fHandle2 != nullptr)
fDescriptor->activate(fHandle2);
}
}

// --------------------------------------------------------------------------------------------------------
// Event Input and Processing

else if (kData->event.portIn != nullptr)
{
// ----------------------------------------------------------------------------------------------------
// MIDI Input (External)

if (kData->extNotes.mutex.tryLock())
{
while (midiEventCount < MAX_MIDI_EVENTS && ! kData->extNotes.data.isEmpty())
{
const ExternalMidiNote& note = kData->extNotes.data.getFirst(true);

CARLA_ASSERT(note.channel >= 0);

carla_zeroStruct<snd_seq_event_t>(fMidiEvents[midiEventCount]);

fMidiEvents[midiEventCount].type = (note.velo > 0) ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF;
fMidiEvents[midiEventCount].data.note.channel = note.channel;
fMidiEvents[midiEventCount].data.note.note = note.note;
fMidiEvents[midiEventCount].data.note.velocity = note.velo;

midiEventCount += 1;
}

kData->extNotes.mutex.unlock();

} // End of MIDI Input (External)

// ----------------------------------------------------------------------------------------------------
// Event Input (System)

bool allNotesOffSent = false;

uint32_t time, nEvents = kData->event.portIn->getEventCount();
uint32_t timeOffset = 0;

uint32_t nextBankId = 0;
if (kData->midiprog.current >= 0 && kData->midiprog.count > 0)
@@ -912,6 +980,15 @@ public:
if (time >= frames)
continue;

CARLA_ASSERT(time >= timeOffset);

if (time > timeOffset)
{
processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset, midiEventCount);
midiEventCount = 0;
timeOffset = time;
}

// Control change
switch (event.type)
{
@@ -1021,7 +1098,7 @@ public:
case kEngineControlEventTypeMidiProgram:
if (event.channel == kData->ctrlInChannel)
{
uint32_t nextProgramId = ctrlEvent.param;
const uint32_t nextProgramId = ctrlEvent.param;

for (k=0; k < kData->midiprog.count; k++)
{
@@ -1038,7 +1115,7 @@ public:
case kEngineControlEventTypeAllSoundOff:
if (event.channel == kData->ctrlInChannel)
{
if (/*midi.portMin &&*/ ! allNotesOffSent)
if (! allNotesOffSent)
sendMidiAllNotesOff();

if (fDescriptor->deactivate != nullptr)
@@ -1067,7 +1144,7 @@ public:
case kEngineControlEventTypeAllNotesOff:
if (event.channel == kData->ctrlInChannel)
{
if (/*midi.portMin &&*/ ! allNotesOffSent)
if (! allNotesOffSent)
sendMidiAllNotesOff();

allNotesOffSent = true;
@@ -1157,39 +1234,26 @@ public:

kData->postRtEvents.trySplice();

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

if (kData->extNotes.mutex.tryLock())
{
while (midiEventCount < MAX_MIDI_EVENTS && ! kData->extNotes.data.isEmpty())
{
const ExternalMidiNote& note = kData->extNotes.data.getFirst(true);

CARLA_ASSERT(note.channel >= 0);

carla_zeroStruct<snd_seq_event_t>(fMidiEvents[midiEventCount]);

fMidiEvents[midiEventCount].type = (note.velo > 0) ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF;
fMidiEvents[midiEventCount].data.note.channel = note.channel;
fMidiEvents[midiEventCount].data.note.note = note.note;
fMidiEvents[midiEventCount].data.note.velocity = note.velo;

midiEventCount += 1;
}
if (frames > timeOffset)
processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset, midiEventCount);

kData->extNotes.mutex.unlock();
} // End of Event Input and Processing

} // End of MIDI Input (External)
// --------------------------------------------------------------------------------------------------------
// Plugin processing (no events)

} // End of Event Input
else
{
processSingle(inBuffer, outBuffer, frames, 0, 0);

CARLA_PROCESS_CONTINUE_CHECK;
} // End of Plugin processing (no events)

// --------------------------------------------------------------------------------------------------------
// Special Parameters

#if 0
CARLA_PROCESS_CONTINUE_CHECK;

for (k=0; k < param.count; k++)
{
if (param.data[k].type == PARAMETER_LATENCY)
@@ -1201,98 +1265,6 @@ public:
CARLA_PROCESS_CONTINUE_CHECK;
#endif

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

{
if (! kData->activeBefore)
{
#if 0
if (midi.portMin)
{
for (k=0; k < MAX_MIDI_CHANNELS; k++)
{
memset(&midiEvents[k], 0, sizeof(snd_seq_event_t)); //FIXME
midiEvents[k].type = SND_SEQ_EVENT_CONTROLLER;
midiEvents[k].data.control.channel = k;
midiEvents[k].data.control.param = MIDI_CONTROL_ALL_SOUND_OFF;

memset(&midiEvents[k*2], 0, sizeof(snd_seq_event_t)); //FIXME
midiEvents[k*2].type = SND_SEQ_EVENT_CONTROLLER;
midiEvents[k*2].data.control.channel = k;
midiEvents[k*2].data.control.param = MIDI_CONTROL_ALL_NOTES_OFF;
}

midiEventCount = MAX_MIDI_CHANNELS;
}
#endif

if (kData->latency > 0)
{
for (i=0; i < kData->audioIn.count; i++)
carla_zeroFloat(kData->latencyBuffers[i], kData->latency);
}

if (fDescriptor->activate != nullptr)
{
fDescriptor->activate(fHandle);

if (fHandle2 != nullptr)
fDescriptor->activate(fHandle2);
}
}

if (fHandle2 == nullptr)
{
for (i=0; i < kData->audioIn.count; i++)
fDescriptor->connect_port(fHandle, kData->audioIn.ports[i].rindex, inBuffer[i]);

for (i=0; i < kData->audioOut.count; i++)
fDescriptor->connect_port(fHandle, kData->audioOut.ports[i].rindex, outBuffer[i]);
}
else
{
if (kData->audioIn.count > 0)
{
CARLA_ASSERT(kData->audioIn.count == 2);

fDescriptor->connect_port(fHandle, kData->audioIn.ports[0].rindex, inBuffer[0]);
fDescriptor->connect_port(fHandle2, kData->audioIn.ports[1].rindex, inBuffer[1]);
}

if (kData->audioOut.count > 0)
{
CARLA_ASSERT(kData->audioOut.count == 2);

fDescriptor->connect_port(fHandle, kData->audioOut.ports[0].rindex, outBuffer[0]);
fDescriptor->connect_port(fHandle2, kData->audioOut.ports[1].rindex, outBuffer[1]);
}
}

if (fDssiDescriptor->run_synth != nullptr)
{
fDssiDescriptor->run_synth(fHandle, frames, fMidiEvents, midiEventCount);

if (fHandle2)
fDssiDescriptor->run_synth(fHandle2, frames, fMidiEvents, midiEventCount);
}
else if (fDssiDescriptor->run_multiple_synths != nullptr)
{
LADSPA_Handle handlePtr[2] = { fHandle, fHandle2 };
snd_seq_event_t* midiEventsPtr[2] = { fMidiEvents, fMidiEvents };
unsigned long midiEventCountPtr[2] = { midiEventCount, midiEventCount };
fDssiDescriptor->run_multiple_synths((fHandle2 != nullptr) ? 2 : 1, handlePtr, frames, midiEventsPtr, midiEventCountPtr);
}
else
{
fDescriptor->run(fHandle, frames);

if (fHandle2)
fDescriptor->run(fHandle2, frames);
}

} // End of Plugin processing

CARLA_PROCESS_CONTINUE_CHECK;

// --------------------------------------------------------------------------------------------------------
@@ -1411,6 +1383,58 @@ public:
kData->activeBefore = kData->active;
}

void processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset, const uint32_t midiEventCount)
{
if (fHandle2 == nullptr)
{
for (uint32_t i=0; i < kData->audioIn.count; i++)
fDescriptor->connect_port(fHandle, kData->audioIn.ports[i].rindex, inBuffer[i]+timeOffset);

for (uint32_t i=0; i < kData->audioOut.count; i++)
fDescriptor->connect_port(fHandle, kData->audioOut.ports[i].rindex, outBuffer[i]+timeOffset);
}
else
{
if (kData->audioIn.count > 0)
{
CARLA_ASSERT(kData->audioIn.count == 2);

fDescriptor->connect_port(fHandle, kData->audioIn.ports[0].rindex, inBuffer[0]+timeOffset);
fDescriptor->connect_port(fHandle2, kData->audioIn.ports[1].rindex, inBuffer[1]+timeOffset);
}

if (kData->audioOut.count > 0)
{
CARLA_ASSERT(kData->audioOut.count == 2);

fDescriptor->connect_port(fHandle, kData->audioOut.ports[0].rindex, outBuffer[0]+timeOffset);
fDescriptor->connect_port(fHandle2, kData->audioOut.ports[1].rindex, outBuffer[1]+timeOffset);
}
}

if (fDssiDescriptor->run_synth != nullptr)
{
fDssiDescriptor->run_synth(fHandle, frames, fMidiEvents, midiEventCount);

if (fHandle2)
fDssiDescriptor->run_synth(fHandle2, frames, fMidiEvents, midiEventCount);
}
else if (fDssiDescriptor->run_multiple_synths != nullptr)
{
LADSPA_Handle handlePtr[2] = { fHandle, fHandle2 };
snd_seq_event_t* midiEventsPtr[2] = { fMidiEvents, fMidiEvents };
unsigned long midiEventCountPtr[2] = { midiEventCount, midiEventCount };
fDssiDescriptor->run_multiple_synths((fHandle2 != nullptr) ? 2 : 1, handlePtr, frames, midiEventsPtr, midiEventCountPtr);
}
else
{
fDescriptor->run(fHandle, frames);

if (fHandle2)
fDescriptor->run(fHandle2, frames);
}
}

// -------------------------------------------------------------------
// Post-poned events



+ 592
- 632
source/backend/plugin/fluidsynth.cpp
File diff suppressed because it is too large
View File


+ 88
- 49
source/backend/plugin/ladspa.cpp View File

@@ -82,7 +82,7 @@ public:
// -------------------------------------------------------------------
// Information (base)

virtual PluginType type() const
PluginType type() const
{
return PLUGIN_LADSPA;
}
@@ -762,11 +762,35 @@ public:
}

// --------------------------------------------------------------------------------------------------------
// Parameters Input [Automation]
// Check if active before

if (kData->event.portIn != nullptr && kData->activeBefore)
if (! kData->activeBefore)
{
if (kData->latency > 0)
{
for (i=0; i < kData->audioIn.count; i++)
carla_zeroFloat(kData->latencyBuffers[i], kData->latency);
}

if (fDescriptor->activate != nullptr)
{
fDescriptor->activate(fHandle);

if (fHandle2 != nullptr)
fDescriptor->activate(fHandle2);
}
}

// --------------------------------------------------------------------------------------------------------
// Event Input and Processing

else if (kData->event.portIn != nullptr)
{
// ----------------------------------------------------------------------------------------------------
// Event Input (System)

uint32_t time, nEvents = kData->event.portIn->getEventCount();
uint32_t timeOffset = 0;

for (i=0; i < nEvents; i++)
{
@@ -777,6 +801,14 @@ public:
if (time >= frames)
continue;

CARLA_ASSERT(time >= timeOffset);

if (time > timeOffset)
{
processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset);
timeOffset = time;
}

// Control change
switch (event.type)
{
@@ -921,64 +953,36 @@ public:

kData->postRtEvents.trySplice();

} // End of Parameters Input
if (frames > timeOffset)
processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset);

CARLA_PROCESS_CONTINUE_CHECK;
} // End of Event Input and Processing

// --------------------------------------------------------------------------------------------------------
// Plugin processing
// Plugin processing (no events)

else
{
if (! kData->activeBefore)
{
if (kData->latency > 0)
{
for (i=0; i < kData->audioIn.count; i++)
carla_zeroFloat(kData->latencyBuffers[i], kData->latency);
}
processSingle(inBuffer, outBuffer, frames, 0);

if (fDescriptor->activate != nullptr)
{
fDescriptor->activate(fHandle);
} // End of Plugin processing (no events)

if (fHandle2 != nullptr)
fDescriptor->activate(fHandle2);
}
}
// --------------------------------------------------------------------------------------------------------
// Special Parameters

if (fHandle2 == nullptr)
{
for (i=0; i < kData->audioIn.count; i++)
fDescriptor->connect_port(fHandle, kData->audioIn.ports[i].rindex, inBuffer[i]);
#if 0
CARLA_PROCESS_CONTINUE_CHECK;

for (i=0; i < kData->audioOut.count; i++)
fDescriptor->connect_port(fHandle, kData->audioOut.ports[i].rindex, outBuffer[i]);
}
else
for (k=0; k < param.count; k++)
{
if (param.data[k].type == PARAMETER_LATENCY)
{
if (kData->audioIn.count > 0)
{
CARLA_ASSERT(kData->audioIn.count == 2);

fDescriptor->connect_port(fHandle, kData->audioIn.ports[0].rindex, inBuffer[0]);
fDescriptor->connect_port(fHandle2, kData->audioIn.ports[1].rindex, inBuffer[1]);
}

if (kData->audioOut.count > 0)
{
CARLA_ASSERT(kData->audioOut.count == 2);

fDescriptor->connect_port(fHandle, kData->audioOut.ports[0].rindex, outBuffer[0]);
fDescriptor->connect_port(fHandle2, kData->audioOut.ports[1].rindex, outBuffer[1]);
}
// TODO
}
}

fDescriptor->run(fHandle, frames);

if (fHandle2 != nullptr)
fDescriptor->run(fHandle2, frames);

} // End of Plugin processing
CARLA_PROCESS_CONTINUE_CHECK;
#endif

CARLA_PROCESS_CONTINUE_CHECK;

@@ -1088,6 +1092,41 @@ public:
kData->activeBefore = kData->active;
}

void processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset)
{
if (fHandle2 == nullptr)
{
for (uint32_t i=0; i < kData->audioIn.count; i++)
fDescriptor->connect_port(fHandle, kData->audioIn.ports[i].rindex, inBuffer[i]+timeOffset);

for (uint32_t i=0; i < kData->audioOut.count; i++)
fDescriptor->connect_port(fHandle, kData->audioOut.ports[i].rindex, outBuffer[i]+timeOffset);
}
else
{
if (kData->audioIn.count > 0)
{
CARLA_ASSERT(kData->audioIn.count == 2);

fDescriptor->connect_port(fHandle, kData->audioIn.ports[0].rindex, inBuffer[0]+timeOffset);
fDescriptor->connect_port(fHandle2, kData->audioIn.ports[1].rindex, inBuffer[1]+timeOffset);
}

if (kData->audioOut.count > 0)
{
CARLA_ASSERT(kData->audioOut.count == 2);

fDescriptor->connect_port(fHandle, kData->audioOut.ports[0].rindex, outBuffer[0]+timeOffset);
fDescriptor->connect_port(fHandle2, kData->audioOut.ports[1].rindex, outBuffer[1]+timeOffset);
}
}

fDescriptor->run(fHandle, frames);

if (fHandle2 != nullptr)
fDescriptor->run(fHandle2, frames);
}

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



+ 6
- 4
source/carla_shared.py View File

@@ -1462,6 +1462,8 @@ class PluginEdit(QDialog):

self.connect(self.ui.keyboard, SIGNAL("noteOn(int)"), SLOT("slot_noteOn(int)"))
self.connect(self.ui.keyboard, SIGNAL("noteOff(int)"), SLOT("slot_noteOff(int)"))
self.connect(self.ui.keyboard, SIGNAL("notesOn()"), SLOT("slot_notesOn()"))
self.connect(self.ui.keyboard, SIGNAL("notesOff()"), SLOT("slot_notesOff()"))

self.connect(self.ui.cb_programs, SIGNAL("currentIndexChanged(int)"), SLOT("slot_programIndexChanged(int)"))
self.connect(self.ui.cb_midi_programs, SIGNAL("currentIndexChanged(int)"), SLOT("slot_midiProgramIndexChanged(int)"))
@@ -1724,7 +1726,7 @@ class PluginEdit(QDialog):
mpData = Carla.host.get_midi_program_data(self.fPluginId, i)
mpBank = int(mpData['bank'])
mpProg = int(mpData['program'])
mpLabel = cString(mpData['label'])
mpLabel = cString(mpData['name'])
self.ui.cb_midi_programs.addItem("%03i:%03i - %s" % (mpBank, mpProg, mpLabel))

self.fCurrentMidiProgram = Carla.host.get_current_midi_program_index(self.fPluginId)
@@ -1753,7 +1755,7 @@ class PluginEdit(QDialog):
mpData = Carla.host.get_midi_program_data(self.fPluginId, mpIndex)
mpBank = int(mpData['bank'])
mpProg = int(mpData['program'])
mpLabel = cString(mpData['label'])
mpLabel = cString(mpData['name'])
self.ui.cb_midi_programs.setItemText(mpIndex, "%03i:%03i - %s" % (mpBank, mpProg, mpLabel))

# Update all parameter values
@@ -1948,12 +1950,12 @@ class PluginEdit(QDialog):
@pyqtSlot()
def slot_notesOn(self):
if self.fRealParent:
self.fRealParent.led_midi.setChecked(True)
self.fRealParent.ui.led_midi.setChecked(True)

@pyqtSlot()
def slot_notesOff(self):
if self.fRealParent:
self.fRealParent.led_midi.setChecked(False)
self.fRealParent.ui.led_midi.setChecked(False)

@pyqtSlot()
def slot_finished(self):


Loading…
Cancel
Save