Browse Source

Start fixing up midi pattern plugin, WIP

tags/v2.1-rc1
falkTX 5 years ago
parent
commit
b1a04d7f76
4 changed files with 134 additions and 118 deletions
  1. +34
    -52
      source/frontend/widgets/pianoroll.py
  2. +1
    -1
      source/native-plugins/midi-base.hpp
  3. +37
    -25
      source/native-plugins/midi-pattern.cpp
  4. +62
    -40
      source/native-plugins/resources/midipattern-ui

+ 34
- 52
source/frontend/widgets/pianoroll.py View File

@@ -332,7 +332,7 @@ class PianoRoll(QGraphicsScene):
self.quantize_val = quantize_val self.quantize_val = quantize_val


### dummy vars that will be changed ### dummy vars that will be changed
self.time_sig = 0
self.time_sig = (0,0)
self.measure_width = 0 self.measure_width = 0
self.num_measures = 0 self.num_measures = 0
self.max_note_length = 0 self.max_note_length = 0
@@ -343,8 +343,6 @@ class PianoRoll(QGraphicsScene):
self.header = None self.header = None
self.play_head = None self.play_head = None


self.setTimeSig(time_sig)
self.setMeasures(num_measures)
self.setGridDiv() self.setGridDiv()
self.default_length = 1. / self.grid_div self.default_length = 1. / self.grid_div


@@ -352,47 +350,38 @@ class PianoRoll(QGraphicsScene):
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Callbacks # Callbacks


def movePlayHead(self, transport_info):
# TODO: need conversion between frames and PPQ
x = 105. # works for 120bpm
total_duration = self.time_sig[0] * self.num_measures * x
pos = transport_info['frame'] / x
frac = (pos % total_duration) / total_duration
def movePlayHead(self, transportInfo):
ticksPerBeat = transportInfo['ticksPerBeat']
max_ticks = ticksPerBeat * self.time_sig[0] * self.num_measures
cur_tick = ticksPerBeat * self.time_sig[0] * transportInfo['bar'] + ticksPerBeat * transportInfo['beat'] + transportInfo['tick']
frac = (cur_tick % max_ticks) / max_ticks
self.play_head.setPos(QPointF(frac * self.grid_width, 0)) self.play_head.setPos(QPointF(frac * self.grid_width, 0))


def setTimeSig(self, time_sig): def setTimeSig(self, time_sig):
try:
new_time_sig = list(map(float, time_sig.split('/')))
if len(new_time_sig)==2:
self.time_sig = new_time_sig

self.measure_width = self.full_note_width * self.time_sig[0]/self.time_sig[1]
self.max_note_length = self.num_measures * self.time_sig[0]/self.time_sig[1]
self.grid_width = self.measure_width * self.num_measures
self.setGridDiv()
except ValueError:
pass
self.time_sig = time_sig
self.measure_width = self.full_note_width * self.time_sig[0]/self.time_sig[1]
self.max_note_length = self.num_measures * self.time_sig[0]/self.time_sig[1]
self.grid_width = self.measure_width * self.num_measures
self.setGridDiv()


def setMeasures(self, measures): def setMeasures(self, measures):
try:
self.num_measures = float(measures)
self.max_note_length = self.num_measures * self.time_sig[0]/self.time_sig[1]
self.grid_width = self.measure_width * self.num_measures
self.refreshScene()
except:
pass
#try:
self.num_measures = float(measures)
self.max_note_length = self.num_measures * self.time_sig[0]/self.time_sig[1]
self.grid_width = self.measure_width * self.num_measures
self.refreshScene()
#except:
#pass


def setDefaultLength(self, length): def setDefaultLength(self, length):
try:
v = list(map(float, length.split('/')))
if len(v) < 3:
self.default_length = \
v[0] if len(v)==1 else \
v[0] / v[1]
pos = self.enforce_bounds(self.mousePos)
if self.insert_mode: self.makeGhostNote(pos.x(), pos.y())
except ValueError:
pass
v = list(map(float, length.split('/')))
if len(v) < 3:
self.default_length = \
v[0] if len(v)==1 else \
v[0] / v[1]
pos = self.enforce_bounds(self.mousePos)
if self.insert_mode:
self.makeGhostNote(pos.x(), pos.y())


def setGridDiv(self, div=None): def setGridDiv(self, div=None):
if not div: div = self.quantize_val if not div: div = self.quantize_val
@@ -409,16 +398,13 @@ class PianoRoll(QGraphicsScene):
pass pass


def setQuantize(self, value): def setQuantize(self, value):
try:
val = list(map(float, value.split('/')))
if len(val) == 1:
self.quantize(val[0])
self.quantize_val = value
elif len(val) == 2:
self.quantize(val[0] / val[1])
self.quantize_val = value
except ValueError:
pass
val = list(map(float, value.split('/')))
if len(val) == 1:
self.quantize(val[0])
self.quantize_val = value
elif len(val) == 2:
self.quantize(val[0] / val[1])
self.quantize_val = value


# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Event Callbacks # Event Callbacks
@@ -851,10 +837,9 @@ class ModeIndicator(QWidget):
self.mode = None self.mode = None


def paintEvent(self, event): def paintEvent(self, event):
painter = QPainter(self)
event.accept() event.accept()


painter.begin(self)
painter = QPainter(self)


painter.setPen(QPen(QColor(0, 0, 0, 0))) painter.setPen(QPen(QColor(0, 0, 0, 0)))
if self.mode == 'velocity_mode': if self.mode == 'velocity_mode':
@@ -865,9 +850,6 @@ class ModeIndicator(QWidget):
painter.setBrush(QColor(0, 0, 0, 0)) painter.setBrush(QColor(0, 0, 0, 0))
painter.drawRect(0, 0, 30, 20) painter.drawRect(0, 0, 30, 20)


# FIXME
painter.end()

def changeMode(self, new_mode): def changeMode(self, new_mode):
self.mode = new_mode self.mode = new_mode
self.update() self.update()


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

@@ -291,7 +291,7 @@ public:
if (fData.count() == 0) if (fData.count() == 0)
return nullptr; return nullptr;


char* const data((char*)std::calloc(1, fData.count()*maxMsgSize));
char* const data((char*)std::calloc(1, fData.count()*maxMsgSize+1));
CARLA_SAFE_ASSERT_RETURN(data != nullptr, nullptr); CARLA_SAFE_ASSERT_RETURN(data != nullptr, nullptr);


char* dataWrtn = data; char* dataWrtn = data;


+ 37
- 25
source/native-plugins/midi-pattern.cpp View File

@@ -20,6 +20,9 @@


#include "midi-base.hpp" #include "midi-base.hpp"


// matches UI side
#define TICKS_PER_BEAT 48

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


class MidiPatternPlugin : public NativePluginAndUiClass, class MidiPatternPlugin : public NativePluginAndUiClass,
@@ -52,7 +55,7 @@ public:
fParameters[kParameterDefLength] = 4.0f; fParameters[kParameterDefLength] = 4.0f;
fParameters[kParameterQuantize] = 4.0f; fParameters[kParameterQuantize] = 4.0f;


fMaxTicks = 48.0 * fTimeSigNum * 4 /* kParameterMeasures */ / 2; // FIXME: why / 2 ?
fMaxTicks = TICKS_PER_BEAT * fTimeSigNum * 4 /* kParameterMeasures */;
} }


protected: protected:
@@ -202,7 +205,7 @@ protected:
fTimeSigNum = 1; fTimeSigNum = 1;
// fall through // fall through
case kParameterMeasures: case kParameterMeasures:
fMaxTicks = 48.0 * fTimeSigNum * static_cast<double>(fParameters[kParameterMeasures]) /2; // FIXME: why /2 ?
fMaxTicks = TICKS_PER_BEAT * fTimeSigNum * static_cast<double>(fParameters[kParameterMeasures]);
break; break;
} }
} }
@@ -210,7 +213,8 @@ protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Plugin process calls // Plugin process calls


void process(const float**, float**, const uint32_t frames, const NativeMidiEvent*, uint32_t) override
void process(const float**, float**, const uint32_t frames,
const NativeMidiEvent* /*midiEvents*/, uint32_t /*midiEventCount*/) override
{ {
if (const NativeTimeInfo* const timeInfo = getTimeInfo()) if (const NativeTimeInfo* const timeInfo = getTimeInfo())
fTimeInfo = *timeInfo; fTimeInfo = *timeInfo;
@@ -247,12 +251,20 @@ protected:
if (! fTimeInfo.bbt.valid) if (! fTimeInfo.bbt.valid)
fTimeInfo.bbt.beatsPerMinute = 120.0; fTimeInfo.bbt.beatsPerMinute = 120.0;


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


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


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

/*
for (uint32_t i=0; i<midiEventCount; ++i)
{
uint32_t pos = static_cast<uint32_t>(std::fmod(fTicksPerFrame * static_cast<double>(fTimeInfo.frame + midiEvents[i].time), fMaxTicks));
fMidiOut.addRaw(pos, midiEvents[i].data, midiEvents[i].size);
}
*/


for (; playPos < endPos; playPos += fMaxTicks) for (; playPos < endPos; playPos += fMaxTicks)
{ {
@@ -290,13 +302,12 @@ protected:
if (isPipeRunning()) if (isPipeRunning())
{ {
char strBuf[0xff+1]; char strBuf[0xff+1];
strBuf[0xff] = '\0';
carla_zeroChars(strBuf, 0xff+1);


const double beatsPerBar = fTimeInfo.bbt.valid ? static_cast<double>(fTimeInfo.bbt.beatsPerBar) : 4.0;
const double beatsPerBar = fTimeSigNum;
const double beatsPerMinute = fTimeInfo.bbt.valid ? fTimeInfo.bbt.beatsPerMinute : 120.0; const double beatsPerMinute = fTimeInfo.bbt.valid ? fTimeInfo.bbt.beatsPerMinute : 120.0;
const float beatType = fTimeInfo.bbt.valid ? fTimeInfo.bbt.beatType : 4.0f;


const double ticksPerBeat = 48.0;
const double ticksPerBeat = TICKS_PER_BEAT;
const double ticksPerFrame = ticksPerBeat / (60.0 / beatsPerMinute * getSampleRate()); const double ticksPerFrame = ticksPerBeat / (60.0 / beatsPerMinute * getSampleRate());
const double fullTicks = static_cast<double>(ticksPerFrame * static_cast<long double>(fTimeInfo.frame)); const double fullTicks = static_cast<double>(ticksPerFrame * static_cast<long double>(fTimeInfo.frame));
const double fullBeats = fullTicks / ticksPerBeat; const double fullBeats = fullTicks / ticksPerBeat;
@@ -307,24 +318,17 @@ protected:


const CarlaMutexLocker cml(getPipeLock()); const CarlaMutexLocker cml(getPipeLock());


if (! writeAndFixMessage("transport"))
return;
if (! writeMessage(fTimeInfo.playing ? "true\n" : "false\n"))
return;
CARLA_SAFE_ASSERT_RETURN(writeMessage("transport\n"),);


std::sprintf(strBuf, P_UINT64 ":%i:%i:%i\n", fTimeInfo.frame, bar, beat, tick);
if (! writeMessage(strBuf))
return;
std::snprintf(strBuf, 0xff, "%i:" P_UINT64 ":%i:%i:%i\n", int(fTimeInfo.playing), fTimeInfo.frame, bar, beat, tick);
CARLA_SAFE_ASSERT_RETURN(writeMessage(strBuf),);


{ {
const CarlaScopedLocale csl; const CarlaScopedLocale csl;
std::sprintf(strBuf, "%f:%f:%f\n",
static_cast<double>(beatsPerMinute),
static_cast<double>(beatsPerBar),
static_cast<double>(beatType));
std::snprintf(strBuf, 0xff, "%f\n", beatsPerMinute);
} }
if (! writeMessage(strBuf))
return;

CARLA_SAFE_ASSERT_RETURN(writeMessage(strBuf),);


flushMessages(); flushMessages();
} }
@@ -402,7 +406,7 @@ protected:
data[i] = dvalue; data[i] = dvalue;
} }


fMidiOut.addRaw(time, data, size);
fMidiOut.addRaw(time /* * TICKS_PER_BEAT */, data, size);


return true; return true;
} }
@@ -424,7 +428,7 @@ protected:
data[i] = dvalue; data[i] = dvalue;
} }


fMidiOut.removeRaw(time, data, size);
fMidiOut.removeRaw(time /* * TICKS_PER_BEAT */, data, size);


return true; return true;
} }
@@ -450,13 +454,21 @@ private:
void _sendEventsToUI() const noexcept void _sendEventsToUI() const noexcept
{ {
char strBuf[0xff+1]; char strBuf[0xff+1];
strBuf[0xff] = '\0';
carla_zeroChars(strBuf, 0xff);


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


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


writeMessage("parameters\n", 11);
std::snprintf(strBuf, 0xff, "%i:%i:%i:%i\n",
static_cast<int>(fParameters[kParameterTimeSig]),
static_cast<int>(fParameters[kParameterMeasures]),
static_cast<int>(fParameters[kParameterDefLength]),
static_cast<int>(fParameters[kParameterQuantize]));
writeMessage(strBuf);

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


+ 62
- 40
source/native-plugins/resources/midipattern-ui View File

@@ -42,7 +42,7 @@ from externalui import ExternalUI
# ------------------------------------------------------------------------------------------------------------ # ------------------------------------------------------------------------------------------------------------


class MidiPatternW(ExternalUI, QMainWindow): class MidiPatternW(ExternalUI, QMainWindow):
PPQ = 48.0
TICKS_PER_BEAT = 48


def __init__(self): def __init__(self):
ExternalUI.__init__(self) ExternalUI.__init__(self)
@@ -54,6 +54,7 @@ class MidiPatternW(ExternalUI, QMainWindow):
# to be filled with note-on events, while waiting for their matching note-off # to be filled with note-on events, while waiting for their matching note-off
self.fPendingNoteOns = [] # (channel, note, velocity, time) self.fPendingNoteOns = [] # (channel, note, velocity, time)


self.fTimeSignature = (4,4)
self.fTransportInfo = { self.fTransportInfo = {
"playing": False, "playing": False,
"frame": 0, "frame": 0,
@@ -61,8 +62,6 @@ class MidiPatternW(ExternalUI, QMainWindow):
"beat": 0, "beat": 0,
"tick": 0, "tick": 0,
"bpm": 120.0, "bpm": 120.0,
"sigNum": 4.0,
"sigDenom": 4.0
} }


self.ui.act_edit_insert.triggered.connect(self.slot_editInsertMode) self.ui.act_edit_insert.triggered.connect(self.slot_editInsertMode)
@@ -79,7 +78,7 @@ class MidiPatternW(ExternalUI, QMainWindow):
self.ui.defaultLengthBox.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.quantizeBox.currentIndexChanged[int].connect(self.slot_paramChanged)


self.ui.timeSigBox.currentIndexChanged[str].connect(self.ui.piano.setTimeSig)
self.ui.timeSigBox.currentIndexChanged[str].connect(self.slot_setTimeSignature)
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)
self.ui.quantizeBox.currentIndexChanged[str].connect(self.ui.piano.setGridDiv) self.ui.quantizeBox.currentIndexChanged[str].connect(self.ui.piano.setGridDiv)
@@ -132,6 +131,18 @@ class MidiPatternW(ExternalUI, QMainWindow):


self.sendControl(param, index) self.sendControl(param, index)


def slot_setTimeSignature(self, sigtext):
try:
timesig = tuple(map(float, sigtext.split('/')))
except ValueError:
pass

if len(timesig) != 2:
return

self.fTimeSignature = timesig
self.ui.piano.setTimeSig(timesig)

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


@@ -139,13 +150,28 @@ class MidiPatternW(ExternalUI, QMainWindow):
value = int(value) value = int(value)


if index == 0: # TimeSig if index == 0: # TimeSig
self.ui.timeSigBox.blockSignals(True)
self.ui.timeSigBox.setCurrentIndex(value) self.ui.timeSigBox.setCurrentIndex(value)
self.slot_setTimeSignature(self.ui.timeSigBox.currentText())
self.ui.timeSigBox.blockSignals(False)

elif index == 1: # Measures elif index == 1: # Measures
self.ui.measureBox.blockSignals(True)
self.ui.measureBox.setCurrentIndex(value-1) self.ui.measureBox.setCurrentIndex(value-1)
self.ui.piano.setMeasures(self.ui.measureBox.currentText())
self.ui.measureBox.blockSignals(False)

elif index == 2: # DefLength elif index == 2: # DefLength
self.ui.defaultLengthBox.blockSignals(True)
self.ui.defaultLengthBox.setCurrentIndex(value) self.ui.defaultLengthBox.setCurrentIndex(value)
self.ui.piano.setDefaultLength(self.ui.defaultLengthBox.currentText())
self.ui.defaultLengthBox.blockSignals(False)

elif index == 3: # Quantize elif index == 3: # Quantize
self.ui.quantizeBox.blockSignals(True)
self.ui.quantizeBox.setCurrentIndex(value) self.ui.quantizeBox.setCurrentIndex(value)
self.ui.piano.setQuantize(self.ui.quantizeBox.currentText())
self.ui.quantizeBox.blockSignals(False)


def dspStateChanged(self, key, value): def dspStateChanged(self, key, value):
pass pass
@@ -193,21 +219,21 @@ class MidiPatternW(ExternalUI, QMainWindow):
# Custom callback # Custom callback


def updateMeasureBox(self, index): def updateMeasureBox(self, index):
self.measureBox.setCurrentIndex(index-1)
self.ui.measureBox.setCurrentIndex(index-1)


def sendMsg(self, data): def sendMsg(self, data):
msg = data[0] msg = data[0]
if msg == "midievent-remove":
if msg == "midievent-add":
note, start, length, vel = data[1:5] note, start, length, vel = data[1:5]
note_start = start * 60. / self.fTransportInfo["bpm"] * 4. / self.fTransportInfo["sigDenom"] * self.PPQ
note_stop = note_start + length * 60. / self.fTransportInfo["bpm"] * 4. * self.fTransportInfo["sigNum"] / self.fTransportInfo["sigDenom"] * self.PPQ
note_start = start * 60. / self.fTransportInfo["bpm"] * self.TICKS_PER_BEAT
note_stop = note_start + length * 60. / self.fTransportInfo["bpm"] * 4. * self.fTimeSignature[0] / self.fTimeSignature[1] * self.TICKS_PER_BEAT
self.send([msg, note_start, 3, MIDI_STATUS_NOTE_ON, note, vel]) self.send([msg, note_start, 3, MIDI_STATUS_NOTE_ON, note, vel])
self.send([msg, note_stop, 3, MIDI_STATUS_NOTE_OFF, note, vel]) self.send([msg, note_stop, 3, MIDI_STATUS_NOTE_OFF, note, vel])


elif msg == "midievent-add":
elif msg == "midievent-remove":
note, start, length, vel = data[1:5] note, start, length, vel = data[1:5]
note_start = start * 60. / self.fTransportInfo["bpm"] * self.PPQ
note_stop = note_start + length * 60. / self.fTransportInfo["bpm"] * 4. * self.fTransportInfo["sigNum"] / self.fTransportInfo["sigDenom"] * self.PPQ
note_start = start * 60. / self.fTransportInfo["bpm"] * self.TICKS_PER_BEAT # 4. / self.fTransportInfo["sigDenom"] * self.TICKS_PER_BEAT
note_stop = note_start + length * 60. / self.fTransportInfo["bpm"] * 4. * self.fTimeSignature[0] / self.fTimeSignature[1] * self.TICKS_PER_BEAT
self.send([msg, note_start, 3, MIDI_STATUS_NOTE_ON, note, vel]) self.send([msg, note_start, 3, MIDI_STATUS_NOTE_ON, note, vel])
self.send([msg, note_stop, 3, MIDI_STATUS_NOTE_OFF, note, vel]) self.send([msg, note_stop, 3, MIDI_STATUS_NOTE_OFF, note, vel])


@@ -222,20 +248,14 @@ class MidiPatternW(ExternalUI, QMainWindow):
# adds single midi event # adds single midi event
time = int(self.readlineblock()) time = int(self.readlineblock())
size = int(self.readlineblock()) size = int(self.readlineblock())
data = []

for x in range(size):
data.append(int(self.readlineblock()))
data = tuple(int(self.readlineblock()) for x in range(size))


self.handleMidiEvent(time, size, data) self.handleMidiEvent(time, size, data)


elif msg == "transport": elif msg == "transport":
playing = bool(self.readlineblock() == "true")
frame, bar, beat, tick = [int(i) for i in self.readlineblock().split(":")]
bpm, sigNum, sigDenom = [float(i) for i in self.readlineblock().split(":")]

if beat != self.fTransportInfo["beat"]:
print(beat)
playing, frame, bar, beat, tick = tuple(int(i) for i in self.readlineblock().split(":"))
bpm = float(self.readlineblock())
playing = bool(int(playing))


old_frame = self.fTransportInfo['frame'] old_frame = self.fTransportInfo['frame']


@@ -246,13 +266,19 @@ class MidiPatternW(ExternalUI, QMainWindow):
"beat": beat, "beat": beat,
"tick": tick, "tick": tick,
"bpm": bpm, "bpm": bpm,
"sigNum": sigNum,
"sigDenom": sigDenom
"ticksPerBeat": self.TICKS_PER_BEAT,
} }


if old_frame != frame: if old_frame != frame:
self.ui.piano.movePlayHead(self.fTransportInfo) self.ui.piano.movePlayHead(self.fTransportInfo)


elif msg == "parameters":
timesig, measures, deflength, quantize = tuple(int(i) for i in self.readlineblock().split(":"))
self.dspParameterChanged(0, timesig)
self.dspParameterChanged(1, measures)
self.dspParameterChanged(2, deflength)
self.dspParameterChanged(3, quantize)

else: else:
ExternalUI.msgCallback(self, msg) ExternalUI.msgCallback(self, msg)


@@ -260,16 +286,11 @@ class MidiPatternW(ExternalUI, QMainWindow):
# Internal stuff # Internal stuff


def handleMidiEvent(self, time, size, data): def handleMidiEvent(self, time, size, data):
#print("Got MIDI Event on UI", time, size, data)

# NOTE: for now time comes in frames, which might not be desirable
# we'll convert it to a smaller value for now (seconds)
# later on we can have time as PPQ or similar

time /= self.PPQ
#print("handleMidiEvent", time, size, data)


status = MIDI_GET_STATUS_FROM_DATA(data) status = MIDI_GET_STATUS_FROM_DATA(data)
channel = MIDI_GET_CHANNEL_FROM_DATA(data) channel = MIDI_GET_CHANNEL_FROM_DATA(data)

if status == MIDI_STATUS_NOTE_ON: if status == MIDI_STATUS_NOTE_ON:
note = data[1] note = data[1]
velo = data[2] velo = data[2]
@@ -279,27 +300,28 @@ class MidiPatternW(ExternalUI, QMainWindow):


elif status == MIDI_STATUS_NOTE_OFF: elif status == MIDI_STATUS_NOTE_OFF:
note = data[1] note = data[1]
velo = data[2]


# find previous note-on that matches this note and channel # find previous note-on that matches this note and channel
for noteOnMsg in self.fPendingNoteOns: for noteOnMsg in self.fPendingNoteOns:
channel_, note_, velo_, time_ = noteOnMsg
on_channel, on_note, on_velo, on_time = noteOnMsg


if channel_ != channel:
if on_channel != channel:
continue continue
if note_ != note:
if on_note != note:
continue continue


# found it # found it
#print("{} {} {} {}\n".format(note, time_, time-time_, velo_))
start = time_ / 60. * self.fTransportInfo["bpm"] / 4. * self.fTransportInfo["sigDenom"]
length = (time - time_) / 60. * self.fTransportInfo["bpm"] / 4. / self.fTransportInfo["sigNum"] * self.fTransportInfo["sigDenom"]
self.ui.piano.drawNote(note, start, length, velo_)

# remove from list
self.fPendingNoteOns.remove(noteOnMsg) self.fPendingNoteOns.remove(noteOnMsg)
break break


else:
return

self.ui.piano.drawNote(note,
on_time/self.TICKS_PER_BEAT,
(time-on_time)/self.TICKS_PER_BEAT/self.fTimeSignature[0], on_velo)


#--------------- main ------------------ #--------------- main ------------------
if __name__ == '__main__': if __name__ == '__main__':
import resources_rc import resources_rc


Loading…
Cancel
Save