Browse Source

Enable midisequencer plugin, prepare it for the upcoming UI

tags/1.9.6
falkTX 10 years ago
parent
commit
d783d19df9
6 changed files with 243 additions and 45 deletions
  1. +2
    -0
      source/backend/Makefile
  2. +1
    -0
      source/native-plugins/Makefile
  3. +6
    -6
      source/native-plugins/_all.c
  4. +41
    -0
      source/native-plugins/midi-base.hpp
  5. +2
    -1
      source/native-plugins/midi-file.cpp
  6. +191
    -38
      source/native-plugins/midi-sequencer.cpp

+ 2
- 0
source/backend/Makefile View File

@@ -54,6 +54,7 @@ UTILS_LIBS += $(MODULEDIR)/juce_audio_formats.a
UTILS_LIBS += $(MODULEDIR)/juce_core.a
UTILS_LIBS += $(MODULEDIR)/lilv.a
UTILS_LIBS += $(MODULEDIR)/native-plugins.a
UTILS_LIBS += $(MODULEDIR)/rtmempool.a

ifeq ($(HAVE_DGL),true)
UTILS_LIBS += $(MODULEDIR)/dgl.a
@@ -109,6 +110,7 @@ UTILS_LINK_FLAGS += $(JUCE_AUDIO_FORMATS_LIBS)
UTILS_LINK_FLAGS += $(JUCE_CORE_LIBS)
UTILS_LINK_FLAGS += $(LILV_LIBS)
UTILS_LINK_FLAGS += $(NATIVE_PLUGINS_LIBS)
UTILS_LINK_FLAGS += $(RTMEMPOOL_LIBS)

ifneq ($(HAIKU),true)
UTILS_LINK_FLAGS += -lpthread


+ 1
- 0
source/native-plugins/Makefile View File

@@ -72,6 +72,7 @@ OBJS += \
$(OBJDIR)/audio-file.cpp.o \
$(OBJDIR)/bigmeter.cpp.o \
$(OBJDIR)/midi-file.cpp.o \
$(OBJDIR)/midi-sequencer.cpp.o \
$(OBJDIR)/notes.cpp.o

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


+ 6
- 6
source/native-plugins/_all.c View File

@@ -32,11 +32,12 @@ extern void carla_register_native_plugin_midithrough(void);
extern void carla_register_native_plugin_miditranspose(void);
extern void carla_register_native_plugin_nekofilter(void);

// Audio File
// Audio file
extern void carla_register_native_plugin_audiofile(void);

// MIDI File
// MIDI file and sequencer
extern void carla_register_native_plugin_midifile(void);
extern void carla_register_native_plugin_midisequencer(void);

// Carla
extern void carla_register_native_plugin_carla(void);
@@ -70,8 +71,6 @@ extern void carla_register_native_plugin_zita_jaaa(void);

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

void carla_register_all_plugins(void);

void carla_register_all_plugins(void)
{
// Simple plugins
@@ -83,11 +82,12 @@ void carla_register_all_plugins(void)
carla_register_native_plugin_miditranspose();
carla_register_native_plugin_nekofilter();

// Audio File
// Audio file
carla_register_native_plugin_audiofile();

// MIDI File
// MIDI file and sequencer
carla_register_native_plugin_midifile();
carla_register_native_plugin_midisequencer();

// Carla
carla_register_native_plugin_carla();


+ 41
- 0
source/native-plugins/midi-base.hpp View File

@@ -186,6 +186,34 @@ public:
appendSorted(rawEvent);
}

// -------------------------------------------------------------------
// remove data

void removeRaw(const uint64_t time, const uint8_t* const data, const uint8_t size)
{
const CarlaMutexLocker sl(fMutex);

for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin(); it.valid(); it.next())
{
const RawMidiEvent* const rawMidiEvent(it.getValue(nullptr));
CARLA_SAFE_ASSERT_CONTINUE(rawMidiEvent != nullptr);

if (rawMidiEvent->time != time)
continue;
if (rawMidiEvent->size != size)
continue;
if (std::memcmp(rawMidiEvent->data, data, size) != 0)
continue;

delete rawMidiEvent;
fData.remove(it);

return;
}

carla_stderr("MidiPattern::removeRaw(" P_INT64 ", %p, %i) - unable to find event to remove", time, data, size);
}

// -------------------------------------------------------------------
// clear

@@ -239,6 +267,19 @@ public:
}

// -------------------------------------------------------------------
// special

const CarlaMutex& getLock() const noexcept
{
return fMutex;
}

LinkedList<const RawMidiEvent*>::Itenerator iteneratorBegin() const noexcept
{
return fData.begin();
}

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

private:
AbstractMidiPlayer* const kPlayer;


+ 2
- 1
source/native-plugins/midi-file.cpp View File

@@ -199,7 +199,8 @@ static const NativePluginDescriptor midifileDesc = {
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY,
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE
|NATIVE_PLUGIN_HAS_UI
|NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE),
|NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE
|NATIVE_PLUGIN_USES_TIME),
/* supports */ static_cast<NativePluginSupports>(0x0),
/* audioIns */ 0,
/* audioOuts */ 0,


+ 191
- 38
source/native-plugins/midi-sequencer.cpp View File

@@ -15,19 +15,24 @@
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/

#include "CarlaNative.hpp"
#include "CarlaNativeExtUI.hpp"
#include "RtLinkedList.hpp"

#include "midi-base.hpp"

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

class MidiSequencerPlugin : public NativePluginClass,
class MidiSequencerPlugin : public NativePluginAndUiClass,
public AbstractMidiPlayer
{
public:
MidiSequencerPlugin(const NativeHostDescriptor* const host)
: NativePluginClass(host),
: NativePluginAndUiClass(host, CARLA_OS_SEP_STR "midiseq-ui"),
fWantInEvents(false),
fMidiOut(this)
fWasPlayingBefore(false),
fInEvents(),
fMidiOut(this),
leakDetector_MidiSequencerPlugin()
{
// TEST SONG (unsorted to test RtList API)

@@ -122,22 +127,10 @@ public:
fMidiOut.addNote(3456*m, 0, 62, 90, 325*m);
}

~MidiSequencerPlugin() override
{
}

protected:
// -------------------------------------------------------------------
// Plugin process calls

void activate() override
{
}

void deactivate() override
{
}

void process(float**, float**, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
{
const NativeTimeInfo* const timePos = getTimeInfo();
@@ -155,26 +148,80 @@ protected:
rawMidiEvent.data[2] = midiEvent->data[2];
rawMidiEvent.data[3] = midiEvent->data[3];
rawMidiEvent.size = midiEvent->size;
rawMidiEvent.time = timePos->frame + midiEvent->time;
rawMidiEvent.time = timePos->playing ? timePos->frame + midiEvent->time : 0;

fInEvents.appendRT(rawMidiEvent);
}

if (fInEvents.mutex.tryLock())
{
fInEvents.splice();
fInEvents.mutex.unlock();
}
fInEvents.trySplice();
}

if (timePos->playing)
{
fMidiOut.play(timePos->frame, frames);
}
else if (fWasPlayingBefore)
{
NativeMidiEvent midiEvent;

midiEvent.port = 0;
midiEvent.time = 0;
midiEvent.data[0] = MIDI_STATUS_CONTROL_CHANGE;
midiEvent.data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
midiEvent.data[2] = 0;
midiEvent.data[3] = 0;
midiEvent.size = 3;

for (int i=0; i < MAX_MIDI_CHANNELS; ++i)
{
midiEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE+i);
NativePluginAndUiClass::writeMidiEvent(&midiEvent);
}

carla_stdout("WAS PLAYING BEFORE, NOW STOPPED");
}

fWasPlayingBefore = timePos->playing;
}

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

void writeMidiEvent(const uint8_t port, const uint32_t timePosFrame, const RawMidiEvent* const event) override
void uiShow(const bool show) override
{
NativePluginAndUiClass::uiShow(show);

if (show)
_sendEventsToUI();
}

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

char* getState() const override
{
// TODO: malloc list of events

return nullptr;
}

void setState(const char* const data) override
{
CARLA_SAFE_ASSERT_RETURN(data != nullptr,);

return;

fMidiOut.clear();

// TODO: set events according to data

_sendEventsToUI();
}

// -------------------------------------------------------------------
// AbstractMidiPlayer calls

void writeMidiEvent(const uint8_t port, const uint64_t timePosFrame, const RawMidiEvent* const event) override
{
NativeMidiEvent midiEvent;

@@ -186,48 +233,151 @@ protected:
midiEvent.data[3] = event->data[3];
midiEvent.size = event->size;

NativePluginClass::writeMidiEvent(&midiEvent);
NativePluginAndUiClass::writeMidiEvent(&midiEvent);
}

// -------------------------------------------------------------------
// Pipe Server calls

bool msgReceived(const char* const msg) noexcept override
{
if (NativePluginAndUiClass::msgReceived(msg))
return true;

if (std::strcmp(msg, "midi-clear-all") == 0)
{
fMidiOut.clear();
return true;
}

if (std::strcmp(msg, "midievent-add") == 0)
{
uint64_t time;
uint8_t size;

CARLA_SAFE_ASSERT_RETURN(readNextLineAsULong(time), true);
CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(size), true);

uint8_t data[size], dvalue;

for (uint8_t i=0; i<size; ++i)
{
CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(dvalue), true);
data[i] = dvalue;
}

fMidiOut.addRaw(time, data, size);

return true;
}

if (std::strcmp(msg, "midievent-remove") == 0)
{
uint64_t time;
uint8_t size;

CARLA_SAFE_ASSERT_RETURN(readNextLineAsULong(time), true);
CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(size), true);

uint8_t data[size], dvalue;

for (uint8_t i=0; i<size; ++i)
{
CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(dvalue), true);
data[i] = dvalue;
}

fMidiOut.removeRaw(time, data, size);

return true;
}

return false;
}

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

private:
bool fWantInEvents;
bool fWasPlayingBefore;

struct InRtEvents {
CarlaMutex mutex;
RtList<RawMidiEvent>::Pool dataPool;
RtList<RawMidiEvent> data;
RtList<RawMidiEvent> dataPendingRT;
RtLinkedList<RawMidiEvent>::Pool dataPool;
RtLinkedList<RawMidiEvent> data;
RtLinkedList<RawMidiEvent> dataPendingRT;

InRtEvents()
: dataPool(MIN_PREALLOCATED_EVENT_COUNT, MAX_PREALLOCATED_EVENT_COUNT),
InRtEvents() noexcept
: mutex(),
dataPool(MIN_PREALLOCATED_EVENT_COUNT, MAX_PREALLOCATED_EVENT_COUNT),
data(dataPool),
dataPendingRT(dataPool) {}

~InRtEvents()
~InRtEvents() noexcept
{
clear();
}

void appendRT(const RawMidiEvent& event)
void appendRT(const RawMidiEvent& event) noexcept
{
dataPendingRT.append(event);
}

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

void splice()
void trySplice() noexcept
{
dataPendingRT.spliceAppend(data);
if (mutex.tryLock())
{
if (dataPendingRT.count() > 0)
dataPendingRT.moveTo(data, true);
mutex.unlock();
}
}

CARLA_DECLARE_NON_COPY_STRUCT(InRtEvents);

} fInEvents;

MidiPattern fMidiOut;

void _sendEventsToUI() const noexcept
{
char strBuf[0xff+1];
strBuf[0xff] = '\0';

const CarlaMutexLocker cml1(getPipeLock());
const CarlaMutexLocker cml2(fMidiOut.getLock());

writeMessage("midi-clear-all\n", 16);

for (LinkedList<const RawMidiEvent*>::Itenerator it = fMidiOut.iteneratorBegin(); it.valid(); it.next())
{
const RawMidiEvent* const rawMidiEvent(it.getValue(nullptr));
CARLA_SAFE_ASSERT_CONTINUE(rawMidiEvent != nullptr);

writeMessage("midievent-add\n", 14);

std::snprintf(strBuf, 0xff, P_INT64 "\n", rawMidiEvent->time);
writeMessage(strBuf);

std::snprintf(strBuf, 0xff, "%i\n", rawMidiEvent->size);
writeMessage(strBuf);

for (uint8_t i=0, size=rawMidiEvent->size; i<size; ++i)
{
std::snprintf(strBuf, 0xff, "%i\n", rawMidiEvent->data[i]);
writeMessage(strBuf);
}
}
}

PluginClassEND(MidiSequencerPlugin)
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiSequencerPlugin)
};
@@ -236,8 +386,11 @@ private:

static const NativePluginDescriptor midisequencerDesc = {
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY,
/* hints */ NATIVE_PLUGIN_IS_RTSAFE/*|NATIVE_PLUGIN_HAS_GUI*/,
/* supports */ static_cast<NativePluginSupports>(0x0),
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE
|NATIVE_PLUGIN_HAS_UI
|NATIVE_PLUGIN_USES_STATE
|NATIVE_PLUGIN_USES_TIME),
/* supports */ NATIVE_PLUGIN_SUPPORTS_EVERYTHING,
/* audioIns */ 0,
/* audioOuts */ 0,
/* midiIns */ 1,
@@ -246,7 +399,7 @@ static const NativePluginDescriptor midisequencerDesc = {
/* paramOuts */ 0,
/* name */ "MIDI Sequencer",
/* label */ "midisequencer",
/* maker */ "falkTX",
/* maker */ "falkTX, tatch",
/* copyright */ "GNU GPL v2+",
PluginDescriptorFILL(MidiSequencerPlugin)
};


Loading…
Cancel
Save