Skip to content

Commit 49a024d

Browse files
committed
- MIDI clip editor (aka. piano-roll): Transport/Step/Note/Backward,
Formard, now plays the step-selected notes, provided send/Preview is on and playback is not rolling. (REFACTORED)
1 parent bdd9c94 commit 49a024d

12 files changed

+360
-435
lines changed

src/qtractorMidiEditorForm.cpp

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565
#include <QLabel>
6666
#include <QUrl>
6767

68+
#include <QTimer>
69+
6870
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
6971
#define horizontalAdvance width
7072
#endif
@@ -2157,8 +2159,6 @@ void qtractorMidiEditorForm::transportStepNoteBackward (void)
21572159

21582160
const bool bSendNotes
21592161
= m_pMidiEditor->isSendNotesEx();
2160-
const unsigned long iMaxDuration
2161-
= pSession->ticksPerBeat();
21622162

21632163
unsigned long iPlayHead = pSession->playHead();
21642164
qtractorMidiSequence *pSeq = m_pMidiEditor->sequence();
@@ -2193,8 +2193,9 @@ void qtractorMidiEditorForm::transportStepNoteBackward (void)
21932193
if (pEvent->type() == eventType) {
21942194
m_pMidiEditor->selectEvent(pEvent);
21952195
if (bSendNotes && eventType == qtractorMidiEvent::NOTEON) {
2196-
sendNoteEx(pEvent->note(), pEvent->velocity(),
2197-
qMax(pEvent->duration(), iMaxDuration));
2196+
sendNoteEx(pEvent->note(),
2197+
pEvent->velocity(),
2198+
pEvent->duration());
21982199
}
21992200
}
22002201
pEvent = pEvent->prev();
@@ -2220,8 +2221,6 @@ void qtractorMidiEditorForm::transportStepNoteForward (void)
22202221

22212222
const bool bSendNotes
22222223
= m_pMidiEditor->isSendNotesEx();
2223-
const unsigned long iMaxDuration
2224-
= pSession->ticksPerBeat();
22252224

22262225
unsigned long iPlayHead = pSession->playHead();
22272226
qtractorMidiSequence *pSeq = m_pMidiEditor->sequence();
@@ -2253,8 +2252,9 @@ void qtractorMidiEditorForm::transportStepNoteForward (void)
22532252
if (pEvent->type() == eventType) {
22542253
m_pMidiEditor->selectEvent(pEvent);
22552254
if (bSendNotes && eventType == qtractorMidiEvent::NOTEON) {
2256-
sendNoteEx(pEvent->note(), pEvent->velocity(),
2257-
qMax(pEvent->duration(), iMaxDuration));
2255+
sendNoteEx(pEvent->note(),
2256+
pEvent->velocity(),
2257+
pEvent->duration());
22582258
}
22592259
}
22602260
pEvent = pEvent->next();
@@ -2328,20 +2328,27 @@ void qtractorMidiEditorForm::sendNote ( int iNote, int iVelocity, bool bForce )
23282328
void qtractorMidiEditorForm::sendNoteEx (
23292329
int iNote, int iVelocity, unsigned long iDuration )
23302330
{
2331-
qtractorMidiClip *pMidiClip = m_pMidiEditor->midiClip();
2332-
if (pMidiClip == nullptr)
2333-
return;
2334-
2335-
qtractorTrack *pTrack = pMidiClip->track();
2336-
if (pTrack == nullptr)
2337-
return;
2338-
2339-
qtractorMidiBus *pMidiBus
2340-
= static_cast<qtractorMidiBus *> (pTrack->outputBus());
2341-
if (pMidiBus == nullptr)
2331+
qtractorSession *pSession = qtractorSession::getInstance();
2332+
if (pSession == nullptr)
23422333
return;
23432334

2344-
pMidiBus->sendNoteEx(pTrack, iNote, iVelocity, iDuration);
2335+
const unsigned int srate = pSession->sampleRate();
2336+
if (srate > 0) {
2337+
// Direct note-on...
2338+
sendNote(iNote, iVelocity, false);
2339+
// Schedule note-off...
2340+
const unsigned long f1 = pSession->playHead();
2341+
qtractorTimeScale::Cursor cursor(pSession->timeScale());
2342+
qtractorTimeScale::Node *pNode = cursor.seekFrame(f1);
2343+
const unsigned long iMaxDuration
2344+
= pSession->ticksPerBeat() * pNode->beatsPerBar2();
2345+
const unsigned long t1 = pNode->tickFromFrame(f1);
2346+
const unsigned long t2 = t1 + qMin(iDuration, iMaxDuration);
2347+
pNode = cursor.seekTick(t2);
2348+
const unsigned long f2 = pNode->frameFromTick(t2);
2349+
const unsigned int msecs = (1000 * (f2 - f1)) / srate;
2350+
QTimer::singleShot(msecs, [=]{ sendNote(iNote, 0, false); });
2351+
}
23452352
}
23462353

23472354

src/qtractorMidiEngine.cpp

Lines changed: 0 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4782,84 +4782,6 @@ void qtractorMidiBus::sendNote (
47824782
}
47834783

47844784

4785-
// Scheduled MIDI note helper.
4786-
void qtractorMidiBus::sendNoteEx (
4787-
qtractorTrack *pTrack, int iNote, int iVelocity, unsigned long iDuration ) const
4788-
{
4789-
qtractorSession *pSession = pTrack->session();
4790-
if (pSession == nullptr)
4791-
return;
4792-
4793-
// We always need our MIDI engine reference...
4794-
qtractorMidiEngine *pMidiEngine
4795-
= static_cast<qtractorMidiEngine *> (engine());
4796-
if (pMidiEngine == nullptr)
4797-
return;
4798-
4799-
// Don't do anything else if engine
4800-
// has not been activated...
4801-
snd_seq_t *pAlsaSeq = pMidiEngine->alsaSeq();
4802-
if (pAlsaSeq == nullptr)
4803-
return;
4804-
4805-
const unsigned short iChannel = pTrack->midiChannel();
4806-
4807-
#ifdef CONFIG_DEBUG_0
4808-
qDebug("qtractorMidiBus[%p]::sendNoteEx(%d, %d, %d, %lu)",
4809-
this, iChannel, iNote, iVelocity, iDuration);
4810-
#endif
4811-
4812-
// Initialize sequencer event...
4813-
snd_seq_event_t ev;
4814-
snd_seq_ev_clear(&ev);
4815-
4816-
// Addressing...
4817-
snd_seq_ev_set_source(&ev, m_iAlsaPort);
4818-
snd_seq_ev_set_subs(&ev);
4819-
4820-
// The event will be direct...
4821-
const unsigned long tick
4822-
= pSession->timep(pMidiEngine->queueTime());
4823-
snd_seq_ev_set_dest(&ev,
4824-
pMidiEngine->alsaClient(), m_iAlsaPort);
4825-
snd_seq_ev_schedule_tick(&ev,
4826-
pMidiEngine->alsaQueue(), 0, tick);
4827-
4828-
// Set event parameters...
4829-
ev.type = SND_SEQ_EVENT_NOTE;
4830-
ev.data.note.channel = iChannel;
4831-
ev.data.note.note = iNote;
4832-
ev.data.note.velocity = iVelocity;
4833-
ev.data.note.duration = iDuration;
4834-
snd_seq_event_output(pAlsaSeq, &ev);
4835-
4836-
// Do it for the MIDI plugins too...
4837-
const unsigned long t1 = pSession->playHead();
4838-
qtractorTimeScale::Cursor cursor(pSession->timeScale());
4839-
qtractorTimeScale::Node *pNode = cursor.seekFrame(t1);
4840-
const unsigned long iTime = pNode->tickFromFrame(t1);
4841-
const unsigned long iTimeOff = iTime + (iDuration - 1);
4842-
pNode = cursor.seekTick(iTimeOff);
4843-
const unsigned long t2 = pNode->frameFromTick(iTimeOff);
4844-
if ((pTrack->pluginList())->midiManager())
4845-
(pTrack->pluginList())->midiManager()->queued(&ev, t1, t2);
4846-
if (pluginList_out() && pluginList_out()->midiManager())
4847-
(pluginList_out()->midiManager())->queued(&ev, t1, t2);
4848-
4849-
pMidiEngine->flush();
4850-
4851-
// Bus/track output monitoring...
4852-
// Bus output monitoring...
4853-
if (m_pOMidiMonitor)
4854-
m_pOMidiMonitor->enqueue(qtractorMidiEvent::NOTEON, iVelocity);
4855-
// Track output monitoring...
4856-
qtractorMidiMonitor *pMidiMonitor
4857-
= static_cast<qtractorMidiMonitor *> (pTrack->monitor());
4858-
if (pMidiMonitor)
4859-
pMidiMonitor->enqueue(qtractorMidiEvent::NOTEON, iVelocity);
4860-
}
4861-
4862-
48634785
// Direct SysEx helpers.
48644786
void qtractorMidiBus::sendSysex (
48654787
unsigned char *pSysex, unsigned int iSysex ) const

src/qtractorMidiEngine.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -538,10 +538,6 @@ class qtractorMidiBus : public qtractorBus
538538
void sendNote(qtractorTrack *pTrack,
539539
int iNote, int iVelocity, bool bForce) const;
540540

541-
// Schedule MIDI note helper.
542-
void sendNoteEx(qtractorTrack *pTrack,
543-
int iNote, int iVelocity, unsigned long iDuration) const;
544-
545541
// Direct SysEx helpers.
546542
void sendSysex(unsigned char *pSysex, unsigned int iSysex) const;
547543
void sendSysexList() const;

0 commit comments

Comments
 (0)