Browse Source

More work for midi-pattern; Looping kinda works

tags/1.9.7
falkTX 9 years ago
parent
commit
1b11b486e8
5 changed files with 231 additions and 44 deletions
  1. +7
    -11
      resources/ui/midipattern.ui
  2. +1
    -0
      source/includes/CarlaNative.h
  3. +2
    -2
      source/native-plugins/_data.cpp
  4. +188
    -6
      source/native-plugins/midi-pattern.cpp
  5. +33
    -25
      source/native-plugins/resources/midipattern-ui

+ 7
- 11
resources/ui/midipattern.ui View File

@@ -49,7 +49,7 @@
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>3</number>
<number>0</number>
</property> </property>
<item> <item>
<property name="text"> <property name="text">
@@ -81,11 +81,6 @@
<string>6/4</string> <string>6/4</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string>12/8</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item> <item>
@@ -199,11 +194,6 @@
<string>16</string> <string>16</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string>17</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item> <item>
@@ -231,6 +221,9 @@
</item> </item>
<item> <item>
<widget class="QComboBox" name="defaultLengthBox"> <widget class="QComboBox" name="defaultLengthBox">
<property name="currentIndex">
<number>4</number>
</property>
<item> <item>
<property name="text"> <property name="text">
<string>1/16</string> <string>1/16</string>
@@ -308,6 +301,9 @@
</item> </item>
<item> <item>
<widget class="QComboBox" name="quantizeBox"> <widget class="QComboBox" name="quantizeBox">
<property name="currentIndex">
<number>4</number>
</property>
<item> <item>
<property name="text"> <property name="text">
<string>1/16</string> <string>1/16</string>


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

@@ -67,6 +67,7 @@ typedef enum {
} NativePluginHints; } NativePluginHints;


typedef enum { typedef enum {
NATIVE_PLUGIN_SUPPORTS_NOTHING = 0,
NATIVE_PLUGIN_SUPPORTS_PROGRAM_CHANGES = 1 << 0, /** handles MIDI programs internally instead of host-exposed/exported */ NATIVE_PLUGIN_SUPPORTS_PROGRAM_CHANGES = 1 << 0, /** handles MIDI programs internally instead of host-exposed/exported */
NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES = 1 << 1, NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES = 1 << 1,
NATIVE_PLUGIN_SUPPORTS_CHANNEL_PRESSURE = 1 << 2, NATIVE_PLUGIN_SUPPORTS_CHANNEL_PRESSURE = 1 << 2,


+ 2
- 2
source/native-plugins/_data.cpp View File

@@ -212,12 +212,12 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = {
|NATIVE_PLUGIN_HAS_UI |NATIVE_PLUGIN_HAS_UI
|NATIVE_PLUGIN_USES_STATE |NATIVE_PLUGIN_USES_STATE
|NATIVE_PLUGIN_USES_TIME), |NATIVE_PLUGIN_USES_TIME),
/* supports */ NATIVE_PLUGIN_SUPPORTS_EVERYTHING,
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING,
/* audioIns */ 0, /* audioIns */ 0,
/* audioOuts */ 0, /* audioOuts */ 0,
/* midiIns */ 0, /* midiIns */ 0,
/* midiOuts */ 1, /* midiOuts */ 1,
/* paramIns */ 0,
/* paramIns */ 4,
/* paramOuts */ 0, /* paramOuts */ 0,
/* name */ "MIDI Pattern", /* name */ "MIDI Pattern",
/* label */ "midipattern", /* label */ "midipattern",


+ 188
- 6
source/native-plugins/midi-pattern.cpp View File

@@ -27,21 +27,182 @@ class MidiPatternPlugin : public NativePluginAndUiClass,
{ {
public: public:
enum Parameters { enum Parameters {
kParameterCount = 0
kParameterTimeSig = 0,
kParameterMeasures,
kParameterDefLength,
kParameterQuantize,
kParameterCount
}; };


MidiPatternPlugin(const NativeHostDescriptor* const host) MidiPatternPlugin(const NativeHostDescriptor* const host)
: NativePluginAndUiClass(host, "midipattern-ui"), : NativePluginAndUiClass(host, "midipattern-ui"),
fNeedsAllNotesOff(false), fNeedsAllNotesOff(false),
fWasPlayingBefore(false), fWasPlayingBefore(false),
fTimeSigNum(4),
fTicksPerFrame(0.0), fTicksPerFrame(0.0),
fMaxTicks(0.0),
fMidiOut(this), fMidiOut(this),
fTimeInfo() fTimeInfo()
{ {
carla_zeroStruct(fTimeInfo); carla_zeroStruct(fTimeInfo);

// set default param values
fParameters[kParameterTimeSig] = 3.0f;
fParameters[kParameterMeasures] = 4.0f;
fParameters[kParameterDefLength] = 4.0f;
fParameters[kParameterQuantize] = 4.0f;
} }


protected: protected:
// -------------------------------------------------------------------
// Plugin parameter calls

uint32_t getParameterCount() const override
{
return kParameterCount;
}

const NativeParameter* getParameterInfo(const uint32_t index) const override
{
CARLA_SAFE_ASSERT_RETURN(index < kParameterCount, nullptr);

static NativeParameter param;
static NativeParameterScalePoint scalePoints[10];

int hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMABLE|NATIVE_PARAMETER_IS_INTEGER;

switch (index)
{
case 0:
hints |= NATIVE_PARAMETER_USES_SCALEPOINTS;
param.name = "Time Signature";
param.ranges.def = 3.0f;
param.ranges.min = 0.0f;
param.ranges.max = 5.0f;
scalePoints[0].value = 0.0f;
scalePoints[0].label = "1/4";
scalePoints[1].value = 1.0f;
scalePoints[1].label = "2/4";
scalePoints[2].value = 2.0f;
scalePoints[2].label = "3/4";
scalePoints[3].value = 3.0f;
scalePoints[3].label = "4/4";
scalePoints[4].value = 4.0f;
scalePoints[4].label = "5/4";
scalePoints[5].value = 5.0f;
scalePoints[5].label = "6/4";
param.scalePointCount = 6;
param.scalePoints = scalePoints;
break;
case 1:
param.name = "Measures";
param.ranges.def = 4.0f;
param.ranges.min = 1.0f;
param.ranges.max = 16.0f;
break;
case 2:
hints |= NATIVE_PARAMETER_USES_SCALEPOINTS;
param.name = "Default Length";
param.ranges.def = 4.0f;
param.ranges.min = 0.0f;
param.ranges.max = 9.0f;
scalePoints[0].value = 0.0f;
scalePoints[0].label = "1/16";
scalePoints[1].value = 1.0f;
scalePoints[1].label = "1/15";
scalePoints[2].value = 2.0f;
scalePoints[2].label = "1/12";
scalePoints[3].value = 3.0f;
scalePoints[3].label = "1/9";
scalePoints[4].value = 4.0f;
scalePoints[4].label = "1/8";
scalePoints[5].value = 5.0f;
scalePoints[5].label = "1/6";
scalePoints[6].value = 6.0f;
scalePoints[6].label = "1/4";
scalePoints[7].value = 7.0f;
scalePoints[7].label = "1/3";
scalePoints[8].value = 8.0f;
scalePoints[8].label = "1/2";
scalePoints[9].value = 9.0f;
scalePoints[9].label = "1";
param.scalePointCount = 10;
param.scalePoints = scalePoints;
break;
case 3:
hints |= NATIVE_PARAMETER_USES_SCALEPOINTS;
param.name = "Quantize";
param.ranges.def = 4.0f;
param.ranges.min = 0.0f;
param.ranges.max = 9.0f;
scalePoints[0].value = 0.0f;
scalePoints[0].label = "1/16";
scalePoints[1].value = 1.0f;
scalePoints[1].label = "1/15";
scalePoints[2].value = 2.0f;
scalePoints[2].label = "1/12";
scalePoints[3].value = 3.0f;
scalePoints[3].label = "1/9";
scalePoints[4].value = 4.0f;
scalePoints[4].label = "1/8";
scalePoints[5].value = 5.0f;
scalePoints[5].label = "1/6";
scalePoints[6].value = 6.0f;
scalePoints[6].label = "1/4";
scalePoints[7].value = 7.0f;
scalePoints[7].label = "1/3";
scalePoints[8].value = 8.0f;
scalePoints[8].label = "1/2";
scalePoints[9].value = 9.0f;
scalePoints[9].label = "1";
param.scalePointCount = 10;
param.scalePoints = scalePoints;
break;
}

param.hints = static_cast<NativeParameterHints>(hints);

return &param;
}

float getParameterValue(const uint32_t index) const override
{
CARLA_SAFE_ASSERT_RETURN(index < kParameterCount, 0.0f);

return fParameters[index];
}

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

void setParameterValue(const uint32_t index, const float value) override
{
CARLA_SAFE_ASSERT_RETURN(index < kParameterCount,);

fParameters[index] = value;

switch (index)
{
case kParameterTimeSig:
/**/ if (value > 4.5f)
fTimeSigNum = 6;
else if (value > 3.5f)
fTimeSigNum = 5;
else if (value > 2.5f)
fTimeSigNum = 4;
else if (value > 2.5f)
fTimeSigNum = 3;
else if (value > 1.5f)
fTimeSigNum = 2;
else
fTimeSigNum = 1;
// nobreak
case kParameterMeasures:
fMaxTicks = 48.0*fTimeSigNum*fParameters[kParameterMeasures] /2; // FIXME: why /2 ?
break;
}
}

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


@@ -84,8 +245,25 @@ protected:


fTicksPerFrame = 48.0 / (60.0 / fTimeInfo.bbt.beatsPerMinute * getSampleRate()); fTicksPerFrame = 48.0 / (60.0 / fTimeInfo.bbt.beatsPerMinute * getSampleRate());


fMidiOut.play(fTicksPerFrame*static_cast<long double>(fTimeInfo.frame),
fTicksPerFrame*static_cast<double>(frames));
/* */ double playPos = fTicksPerFrame*static_cast<double>(fTimeInfo.frame);
const double endPos = playPos + fTicksPerFrame*static_cast<double>(frames);

const double loopedEndPos = std::fmod(endPos, fMaxTicks);

for (; playPos < endPos; playPos += fMaxTicks)
{
const double loopedPlayPos = std::fmod(playPos, fMaxTicks);

if (loopedEndPos >= loopedPlayPos)
{
fMidiOut.play(loopedPlayPos, loopedEndPos-loopedPlayPos);
}
else
{
fMidiOut.play(loopedPlayPos, fMaxTicks-loopedPlayPos);
fMidiOut.play(0.0, loopedEndPos);
}
}
} }
} }


@@ -170,8 +348,8 @@ protected:
midiEvent.data[3] = event->data[3]; midiEvent.data[3] = event->data[3];
midiEvent.size = event->size; midiEvent.size = event->size;


carla_stdout("Playing at %i :: %03X:%03i:%03i",
midiEvent.time, midiEvent.data[0], midiEvent.data[1], midiEvent.data[2]);
carla_stdout("Playing at %f :: %03X:%03i:%03i",
float(double(midiEvent.time)*fTicksPerFrame), midiEvent.data[0], midiEvent.data[1], midiEvent.data[2]);


NativePluginAndUiClass::writeMidiEvent(&midiEvent); NativePluginAndUiClass::writeMidiEvent(&midiEvent);
} }
@@ -243,12 +421,16 @@ protected:
private: private:
bool fNeedsAllNotesOff; bool fNeedsAllNotesOff;
bool fWasPlayingBefore; bool fWasPlayingBefore;
int fTimeSigNum;


double fTicksPerFrame; double fTicksPerFrame;
double fMaxTicks;


MidiPattern fMidiOut; MidiPattern fMidiOut;
NativeTimeInfo fTimeInfo; NativeTimeInfo fTimeInfo;


float fParameters[kParameterCount];

void _sendEventsToUI() const noexcept void _sendEventsToUI() const noexcept
{ {
char strBuf[0xff+1]; char strBuf[0xff+1];
@@ -292,7 +474,7 @@ static const NativePluginDescriptor midipatternDesc = {
|NATIVE_PLUGIN_HAS_UI |NATIVE_PLUGIN_HAS_UI
|NATIVE_PLUGIN_USES_STATE |NATIVE_PLUGIN_USES_STATE
|NATIVE_PLUGIN_USES_TIME), |NATIVE_PLUGIN_USES_TIME),
/* supports */ NATIVE_PLUGIN_SUPPORTS_EVERYTHING,
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING,
/* audioIns */ 0, /* audioIns */ 0,
/* audioOuts */ 0, /* audioOuts */ 0,
/* midiIns */ 0, /* midiIns */ 0,


+ 33
- 25
source/native-plugins/resources/midipattern-ui View File

@@ -83,6 +83,11 @@ class MidiPatternW(ExternalUI, QMainWindow):
self.ui.piano.modeupdate.connect(self.ui.modeIndicator.changeMode) self.ui.piano.modeupdate.connect(self.ui.modeIndicator.changeMode)
self.ui.piano.modeupdate.connect(self.slot_modeChanged) self.ui.piano.modeupdate.connect(self.slot_modeChanged)


self.ui.timeSigBox.currentIndexChanged[int].connect(self.slot_paramChanged)
self.ui.measureBox.currentIndexChanged[int].connect(self.slot_paramChanged)
self.ui.defaultLengthBox.currentIndexChanged[int].connect(self.slot_paramChanged)
self.ui.quantizeBox.currentIndexChanged[int].connect(self.slot_paramChanged)

self.ui.timeSigBox.currentIndexChanged[str].connect(self.ui.piano.setTimeSig) self.ui.timeSigBox.currentIndexChanged[str].connect(self.ui.piano.setTimeSig)
self.ui.measureBox.currentIndexChanged[str].connect(self.ui.piano.setMeasures) self.ui.measureBox.currentIndexChanged[str].connect(self.ui.piano.setMeasures)
self.ui.defaultLengthBox.currentIndexChanged[str].connect(self.ui.piano.setDefaultLength) self.ui.defaultLengthBox.currentIndexChanged[str].connect(self.ui.piano.setDefaultLength)
@@ -119,11 +124,37 @@ class MidiPatternW(ExternalUI, QMainWindow):
self.ui.act_edit_insert.setChecked(False) self.ui.act_edit_insert.setChecked(False)
self.ui.act_edit_velocity.setChecked(False) self.ui.act_edit_velocity.setChecked(False)


def slot_paramChanged(self, index):
sender = self.sender()

if sender == self.ui.timeSigBox:
param = 0
elif sender == self.ui.measureBox:
param = 1
index += 1
elif sender == self.ui.defaultLengthBox:
param = 2
elif sender == self.ui.quantizeBox:
param = 3
else:
return

self.sendControl(param, index)

# ------------------------------------------------------------------- # -------------------------------------------------------------------
# DSP Callbacks # DSP Callbacks


def dspParameterChanged(self, index, value): def dspParameterChanged(self, index, value):
pass
value = int(value)

if index == 0: # TimeSig
self.ui.timeSigBox.setCurrentIndex(value)
elif index == 1: # Measures
self.ui.measureBox.setCurrentIndex(value-1)
elif index == 2: # DefLength
self.ui.defaultLengthBox.setCurrentIndex(value)
elif index == 3: # Quantize
self.ui.quantizeBox.setCurrentIndex(value)


def dspStateChanged(self, key, value): def dspStateChanged(self, key, value):
pass pass
@@ -190,12 +221,6 @@ class MidiPatternW(ExternalUI, QMainWindow):
self.send([msg, note_stop, 3, MIDI_STATUS_NOTE_OFF, note, vel]) self.send([msg, note_stop, 3, MIDI_STATUS_NOTE_OFF, note, vel])


def msgCallback(self, msg): def msgCallback(self, msg):
#try:
self.msgCallback2(msg)
#except:
#print("Custom msgCallback error, skipped for", msg)

def msgCallback2(self, msg):
msg = charPtrToString(msg) msg = charPtrToString(msg)


if msg == "midi-clear-all": if msg == "midi-clear-all":
@@ -237,25 +262,8 @@ class MidiPatternW(ExternalUI, QMainWindow):
if old_frame != frame: if old_frame != frame:
self.ui.piano.movePlayHead(self.fTransportInfo) self.ui.piano.movePlayHead(self.fTransportInfo)


elif msg == "show":
self.uiShow()

elif msg == "focus":
self.uiFocus()

elif msg == "hide":
self.uiHide()

elif msg == "quit":
self.fQuitReceived = True
self.uiQuit()

elif msg == "uiTitle":
uiTitle = self.readlineblock()
self.uiTitleChanged(uiTitle)

else: else:
print("unknown message: \"" + msg + "\"")
ExternalUI.msgCallback(self, msg)


# ------------------------------------------------------------------- # -------------------------------------------------------------------
# Internal stuff # Internal stuff


Loading…
Cancel
Save