Browse Source

Add initial midi-sequencer plugin code; misc changes

tags/1.9.4
falkTX 11 years ago
parent
commit
dce4c746c5
10 changed files with 370 additions and 10 deletions
  1. +1
    -0
      source/backend/CarlaEngine.hpp
  2. +1
    -0
      source/backend/CarlaNative.h
  3. +15
    -2
      source/backend/engine/CarlaEngine.cpp
  4. +21
    -4
      source/backend/engine/CarlaEngineInternal.hpp
  5. +1
    -0
      source/backend/native/Makefile
  6. +320
    -0
      source/backend/native/midi-sequencer.cpp
  7. +1
    -0
      source/backend/plugin/NativePlugin.cpp
  8. +5
    -0
      source/bridges/CarlaBridgePlugin.cpp
  9. +1
    -1
      source/bridges/qtcreator/carla-bridge-plugin.pro
  10. +4
    -3
      source/utils/CarlaJuceUtils.hpp

+ 1
- 0
source/backend/CarlaEngine.hpp View File

@@ -975,6 +975,7 @@ protected:
EngineOptions fOptions;
EngineTimeInfo fTimeInfo;

friend struct CarlaEngineProtectedData;
CarlaEngineProtectedData* const kData;

/*!


+ 1
- 0
source/backend/CarlaNative.h View File

@@ -195,6 +195,7 @@ void carla_register_native_plugin(const PluginDescriptor* desc);

// Simple plugins
void carla_register_native_plugin_bypass();
void carla_register_native_plugin_midiSequencer();
void carla_register_native_plugin_midiSplit();
void carla_register_native_plugin_midiThrough();
void carla_register_native_plugin_midiTranspose();


+ 15
- 2
source/backend/engine/CarlaEngine.cpp View File

@@ -569,6 +569,7 @@ bool CarlaEngine::init(const char* const clientName)
break;
}

//kData->pluginsPool.resize(maxPluginNumber, 999);
kData->plugins = new EnginePluginData[kData->maxPluginNumber];

kData->osc.init(clientName);
@@ -609,6 +610,7 @@ bool CarlaEngine::close()
kData->curPluginCount = 0;
kData->maxPluginNumber = 0;

//kData->plugins.clear();
if (kData->plugins != nullptr)
{
delete[] kData->plugins;
@@ -637,6 +639,17 @@ void CarlaEngine::idle()
CARLA_ASSERT(kData->plugins != nullptr);
CARLA_ASSERT(isRunning());

#if 0
for (auto it = kData->plugins.begin(); it.valid(); it.next())
{
CarlaPlugin* const plugin = (*it).plugin;
CARLA_ASSERT(plugin != nullptr);

if (plugin && plugin->enabled())
plugin->idleGui();
}
#endif

for (unsigned int i=0; i < kData->curPluginCount; i++)
{
CarlaPlugin* const plugin = kData->plugins[i].plugin;
@@ -1101,7 +1114,7 @@ float CarlaEngine::getInputPeak(const unsigned int pluginId, const unsigned shor
CARLA_ASSERT(pluginId < kData->curPluginCount);
CARLA_ASSERT(id-1 < MAX_PEAKS);

if (id > MAX_PEAKS)
if (id == 0 || id > MAX_PEAKS)
return 0.0f;

return kData->plugins[pluginId].insPeak[id-1];
@@ -1112,7 +1125,7 @@ float CarlaEngine::getOutputPeak(const unsigned int pluginId, const unsigned sho
CARLA_ASSERT(pluginId < kData->curPluginCount);
CARLA_ASSERT(id-1 < MAX_PEAKS);

if (id > MAX_PEAKS)
if (id == 0 || id > MAX_PEAKS)
return 0.0f;

return kData->plugins[pluginId].outsPeak[id-1];


+ 21
- 4
source/backend/engine/CarlaEngineInternal.hpp View File

@@ -22,6 +22,7 @@
#include "CarlaEngineThread.hpp"
#include "CarlaEngine.hpp"
#include "CarlaPlugin.hpp"
#include "RtList.hpp"

#ifndef BUILD_BRIDGE
# include <QtCore/QProcessEnvironment>
@@ -92,10 +93,6 @@ const char* EngineControlEventType2Str(const EngineControlEventType type)

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

/*!
* Maximum number of peaks per plugin.\n
* \note There are both input and output peaks.
*/
const uint32_t PATCHBAY_BUFFER_SIZE = 128;
const unsigned short PATCHBAY_EVENT_COUNT = 512;
const unsigned short RACK_EVENT_COUNT = 512;
@@ -116,6 +113,7 @@ struct EnginePostEvent {
enum EnginePostAction {
EnginePostActionNull,
EnginePostActionIdle,
EnginePostActionInsertPlugin,
EnginePostActionRemovePlugin
};

@@ -185,6 +183,9 @@ struct CarlaEngineProtectedData {
frame(0) {}
} time;

//RtList<EnginePluginData>::Pool pluginsPool;
//RtList<EnginePluginData> plugins;

EnginePluginData* plugins;

CarlaEngineProtectedData(CarlaEngine* const engine)
@@ -195,8 +196,24 @@ struct CarlaEngineProtectedData {
callbackPtr(nullptr),
aboutToClose(false),
curPluginCount(0),
//pluginsPool(1, 999),
//plugins(&pluginsPool)
maxPluginNumber(0),
plugins(nullptr) {}

~CarlaEngineProtectedData()
{
//plugins.clear();
}

CarlaEngineProtectedData() = delete;
CarlaEngineProtectedData(CarlaEngineProtectedData&) = delete;
CarlaEngineProtectedData(const CarlaEngineProtectedData&) = delete;

//static RtList<EnginePluginData>::Itenerator pluginsBegin(CarlaEngine* const engine)
//{
// return engine->kData->plugins.begin();
//}
};

CARLA_BACKEND_END_NAMESPACE


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

@@ -29,6 +29,7 @@ endif
# Simple plugins
OBJS = \
bypass.c.o \
midi-sequencer.cpp.o \
midi-split.c.o \
midi-through.c.o \
midi-transpose.c.o \


+ 320
- 0
source/backend/native/midi-sequencer.cpp View File

@@ -0,0 +1,320 @@
/*
* 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 "CarlaMIDI.h"
#include "CarlaMutex.hpp"
#include "RtList.hpp"

#define MAX_EVENT_DATA_SIZE 3
#define MIN_PREALLOCATED_EVENT_COUNT 100
#define MAX_PREALLOCATED_EVENT_COUNT 1000

struct RawMidiEvent {
unsigned char data[MAX_EVENT_DATA_SIZE];
//size_t dataSize;
uint32_t time;
//double value; // used for special events
};

class MidiSequencerPlugin : public PluginDescriptorClass
{
public:
MidiSequencerPlugin(const HostDescriptor* const host)
: PluginDescriptorClass(host),
fWantInEvents(false)
{
// TEST SONG

uint32_t m = 44;

fOutEvents.addControl(0*m, 0, 7, 99);
fOutEvents.addControl(0*m, 0, 10, 63);
fOutEvents.addProgram(0*m, 0, 0, 0);

// 0 On ch=1 n=64 v=90
// 325 Off ch=1 n=64 v=90
// 384 On ch=1 n=62 v=90
// 709 Off ch=1 n=62 v=90
// 768 On ch=1 n=60 v=90
//1093 Off ch=1 n=60 v=90
fOutEvents.addNote( 0*m, 0, 64, 90, 325*m);
fOutEvents.addNote(384*m, 0, 62, 90, 325*m);
fOutEvents.addNote(768*m, 0, 60, 90, 325*m);

// 1152 On ch=1 n=62 v=90
// 1477 Off ch=1 n=62 v=90
// 1536 On ch=1 n=64 v=90
// 1861 Off ch=1 n=64 v=90
// 1920 On ch=1 n=64 v=90
// 2245 Off ch=1 n=64 v=90
fOutEvents.addNote(1152*m, 0, 62, 90, 325*m);
fOutEvents.addNote(1536*m, 0, 64, 90, 325*m);
fOutEvents.addNote(1920*m, 0, 64, 90, 325*m);

// 2304 On ch=1 n=64 v=90
// 2955 Off ch=1 n=64 v=90
// 3072 On ch=1 n=62 v=90
// 3397 Off ch=1 n=62 v=90
// 3456 On ch=1 n=62 v=90
// 3781 Off ch=1 n=62 v=90
fOutEvents.addNote(2304*m, 0, 64, 90, 650*m);
fOutEvents.addNote(3072*m, 0, 62, 90, 325*m);
fOutEvents.addNote(3456*m, 0, 62, 90, 325*m);

// 3840 On ch=1 n=62 v=90
// 4491 Off ch=1 n=62 v=90
// 4608 On ch=1 n=64 v=90
// 4933 Off ch=1 n=64 v=90
// 4992 On ch=1 n=67 v=90
// 5317 Off ch=1 n=67 v=90
fOutEvents.addNote(3840*m, 0, 62, 90, 650*m);
fOutEvents.addNote(4608*m, 0, 64, 90, 325*m);
fOutEvents.addNote(4992*m, 0, 67, 90, 325*m);

// 5376 On ch=1 n=67 v=90
// 6027 Off ch=1 n=67 v=90
// 6144 On ch=1 n=64 v=90
// 6469 Off ch=1 n=64 v=90
// 6528 On ch=1 n=62 v=90
// 6853 Off ch=1 n=62 v=90
fOutEvents.addNote(5376*m, 0, 67, 90, 650*m);
fOutEvents.addNote(6144*m, 0, 64, 90, 325*m);
fOutEvents.addNote(6528*m, 0, 62, 90, 325*m);

// 6912 On ch=1 n=60 v=90
// 7237 Off ch=1 n=60 v=90
// 7296 On ch=1 n=62 v=90
// 7621 Off ch=1 n=62 v=90
// 7680 On ch=1 n=64 v=90
// 8005 Off ch=1 n=64 v=90
fOutEvents.addNote(6912*m, 0, 60, 90, 325*m);
fOutEvents.addNote(7296*m, 0, 62, 90, 325*m);
fOutEvents.addNote(7680*m, 0, 64, 90, 325*m);

// 8064 On ch=1 n=64 v=90
// 8389 Off ch=1 n=64 v=90
// 8448 On ch=1 n=64 v=90
// 9099 Off ch=1 n=64 v=90
// 9216 On ch=1 n=62 v=90
// 9541 Off ch=1 n=62 v=90
fOutEvents.addNote(8064*m, 0, 64, 90, 325*m);
fOutEvents.addNote(8448*m, 0, 64, 90, 650*m);
fOutEvents.addNote(9216*m, 0, 62, 90, 325*m);

// 9600 On ch=1 n=62 v=90
// 9925 Off ch=1 n=62 v=90
// 9984 On ch=1 n=64 v=90
// 10309 Off ch=1 n=64 v=90
// 10368 On ch=1 n=62 v=90
// 10693 Off ch=1 n=62 v=90
fOutEvents.addNote(9600*m, 0, 62, 90, 325*m);
fOutEvents.addNote(9984*m, 0, 64, 90, 325*m);
fOutEvents.addNote(10368*m, 0, 62, 90, 325*m);

// 10752 On ch=1 n=60 v=90
// 12056 Off ch=1 n=60 v=90
fOutEvents.addNote(10752*m, 0, 60, 90, 650*m);
}

~MidiSequencerPlugin()
{
fOutEvents.data.clear();
}

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

void activate()
{
}

void deactivate()
{
}

void process(float**, float**, const uint32_t frames, const uint32_t midiEventCount, const MidiEvent* const midiEvents)
{
const TimeInfo* const timePos = getTimeInfo();

if (fWantInEvents)
{
RawMidiEvent rawMidiEvent;

for (uint32_t i=0; i < midiEventCount; i++)
{
const MidiEvent* const midiEvent = &midiEvents[i];

rawMidiEvent.data[0] = midiEvent->data[0];
rawMidiEvent.data[1] = midiEvent->data[1];
rawMidiEvent.data[2] = midiEvent->data[2];
rawMidiEvent.time = timePos->frame + midiEvent->time;

fInEvents.appendRT(rawMidiEvent);
}
}

if (! fMutex.tryLock())
return;

if (fWantInEvents)
fInEvents.splice();

if (timePos->playing)
{
MidiEvent midiEvent;

for (auto it = fOutEvents.data.begin(); it.valid(); it.next())
{
RawMidiEvent* const rawMidiEvent(*it);

if (timePos->frame > rawMidiEvent->time || timePos->frame + frames <= rawMidiEvent->time)
continue;

midiEvent.port = 0;
midiEvent.time = rawMidiEvent->time-timePos->frame;
midiEvent.data[0] = rawMidiEvent->data[0];
midiEvent.data[1] = rawMidiEvent->data[1];
midiEvent.data[2] = rawMidiEvent->data[2];

writeMidiEvent(&midiEvent);
}
}

fMutex.unlock();
}

private:
CarlaMutex fMutex;
bool fWantInEvents;

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

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

~InRtEvents()
{
clear();
}

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

void clear()
{
data.clear();
dataPendingRT.clear();
}

void splice()
{
dataPendingRT.spliceAppend(data, true);
}

} fInEvents;

struct OutRtEvents {
NonRtList<RawMidiEvent*> data;

void addControl(uint32_t time, uint8_t channel, uint8_t control, uint8_t value)
{
RawMidiEvent* ctrlEvent(new RawMidiEvent);
ctrlEvent->data[0] = MIDI_STATUS_CONTROL_CHANGE | (channel & 0x0F);
ctrlEvent->data[1] = control;
ctrlEvent->data[2] = value;
ctrlEvent->time = time;

data.append(ctrlEvent);
}

void addProgram(uint32_t time, uint8_t channel, uint8_t bank, uint8_t program)
{
RawMidiEvent* bankEvent(new RawMidiEvent);
bankEvent->data[0] = MIDI_STATUS_CONTROL_CHANGE | (channel & 0x0F);
bankEvent->data[1] = MIDI_CONTROL_BANK_SELECT;
bankEvent->data[2] = bank;
bankEvent->time = time;

RawMidiEvent* programEvent(new RawMidiEvent);
programEvent->data[0] = MIDI_STATUS_PROGRAM_CHANGE | (channel & 0x0F);
programEvent->data[1] = program;
programEvent->data[2] = 0;
programEvent->time = time;

data.append(bankEvent);
data.append(programEvent);
}

void addNote(uint32_t time, uint8_t channel, uint8_t pitch, uint8_t velocity, uint32_t duration)
{
RawMidiEvent* noteOnEvent(new RawMidiEvent);
noteOnEvent->data[0] = MIDI_STATUS_NOTE_ON | (channel & 0x0F);
noteOnEvent->data[1] = pitch;
noteOnEvent->data[2] = velocity;
noteOnEvent->time = time;

RawMidiEvent* noteOffEvent(new RawMidiEvent);
noteOffEvent->data[0] = MIDI_STATUS_NOTE_OFF | (channel & 0x0F);
noteOffEvent->data[1] = pitch;
noteOffEvent->data[2] = velocity;
noteOffEvent->time = time+duration;

data.append(noteOnEvent);
data.append(noteOffEvent);
}

} fOutEvents;

PluginDescriptorClassEND(MidiSequencerPlugin)
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiSequencerPlugin)
};

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

static const PluginDescriptor midiSequencerDesc = {
/* category */ PLUGIN_CATEGORY_UTILITY,
/* hints */ PLUGIN_IS_RTSAFE/*|PLUGIN_HAS_GUI*/,
/* audioIns */ 0,
/* audioOuts */ 0,
/* midiIns */ 1,
/* midiOuts */ 1,
/* paramIns */ 0,
/* paramOuts */ 0,
/* name */ "MIDI Sequencer",
/* label */ "midiSequencer",
/* maker */ "falkTX",
/* copyright */ "GNU GPL v2+",
PluginDescriptorFILL(MidiSequencerPlugin)
};

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

void carla_register_native_plugin_midiSequencer()
{
carla_register_native_plugin(&midiSequencerDesc);
}

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

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

@@ -1924,6 +1924,7 @@ private:
{
#ifndef BUILD_BRIDGE
carla_register_native_plugin_bypass();
carla_register_native_plugin_midiSequencer();
carla_register_native_plugin_midiSplit();
carla_register_native_plugin_midiThrough();
carla_register_native_plugin_midiTranspose();


+ 5
- 0
source/bridges/CarlaBridgePlugin.cpp View File

@@ -332,6 +332,11 @@ protected:
if (value1 != 1 && ! isOscControlRegistered())
gCloseNow = true;
break;
default: // TODO
(void)value2;
(void)value3;
(void)valueStr;
break;
}
}



+ 1
- 1
source/bridges/qtcreator/carla-bridge-plugin.pro View File

@@ -120,4 +120,4 @@ LIBS = -ldl \
../../libs/lilv.a \
../../libs/rtmempool.a

QMAKE_CXXFLAGS *= -std=c++0x
QMAKE_CXXFLAGS *= -std=gnu++0x

+ 4
- 3
source/utils/CarlaJuceUtils.hpp View File

@@ -31,14 +31,15 @@
CARLA_LEAK_DETECTOR macro for a class.
*/
#define CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className) \
CARLA_DECLARE_NON_COPYABLE(className) \
private: \
CARLA_DECLARE_NON_COPYABLE(className) \
CARLA_LEAK_DETECTOR(className)

/** This macro can be added to class definitions to disable the use of new/delete to
allocate the object on the heap, forcing it to only be used as a stack or member variable.
*/
#define CARLA_PREVENT_HEAP_ALLOCATION \
private: \
#define CARLA_PREVENT_HEAP_ALLOCATION \
private: \
static void* operator new (size_t); \
static void operator delete (void*);



Loading…
Cancel
Save