Skip to content

Support of MaschineMk1 MIDI ports #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 131 additions & 9 deletions src/devices/ni/MaschineMK1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "devices/ni/MaschineMK1.h"

#include <thread>
#include <memory>
#include <RtMidi.h>

#include "cabl/comm/Driver.h"
#include "cabl/comm/Transfer.h"
Expand Down Expand Up @@ -161,6 +163,30 @@ enum class MaschineMK1::Button : uint8_t
MaschineMK1::MaschineMK1()
{
m_leds.resize(kMASMK1_ledsDataSize);

try
{
m_pVirtualMidiIn.reset(new RtMidiOut(RtMidi::UNSPECIFIED,"Maschine MK1"));
m_pVirtualMidiIn->openVirtualPort("Received MIDI IN");
}
catch (std::exception const & e)
{
M_LOG("[MaschineMK1] Could not init virtual MIDI IN port: " << e.what());
m_pVirtualMidiIn.reset();
}

try
{
m_pVirtualMidiOut.reset(new RtMidiIn(RtMidi::UNSPECIFIED,"Maschine MK1"));
m_pVirtualMidiOut->ignoreTypes(false,false,false); // sends everything.
m_pVirtualMidiOut->openVirtualPort("send MIDI OUT");
}
catch (std::exception const & e)
{
M_LOG("[MaschineMK1] Could not init virtual MIDI OUT port: " << e.what());
m_pVirtualMidiOut.reset();
}

}

//--------------------------------------------------------------------------------------------------
Expand All @@ -181,10 +207,7 @@ void MaschineMK1::setKeyLed(unsigned index_, const Color& color_)

void MaschineMK1::sendMidiMsg(tRawData midiMsg_)
{
uint8_t lengthH = (midiMsg_.size() >> 8) & 0xFF;
uint8_t lengthL = midiMsg_.size() & 0xFF;
writeToDeviceHandle(
Transfer({0x07, lengthH, lengthL}, midiMsg_.data(), midiMsg_.size()), kMASMK1_epOut);
m_MidiOutQueue.push_back(midiMsg_);
}

//--------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -226,14 +249,17 @@ bool MaschineMK1::tick()
{
success = sendLeds();
}
else if (state == 3)
{
success = writeMidiMsg();
}

if (!success)
{
std::string strStepName(state == 0 ? "sendFrame" : (state == 1 ? "read" : "sendLeds"));
M_LOG("[MaschineMK1] tick: error in step #" << state << " (" << strStepName << ")");
M_LOG("[MaschineMK1] tick: error in step #" << state);
}

if (++state >= 3)
if (++state > 3)
{
state = 0;
}
Expand Down Expand Up @@ -416,6 +442,45 @@ bool MaschineMK1::read()

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

bool MaschineMK1::getNextMidiOutMsg(tRawData & midiMsg_)
{
if (!m_MidiOutQueue.empty())
{
midiMsg_ = std::move(m_MidiOutQueue.front());
m_MidiOutQueue.pop_front();
return true;
}

if (m_pVirtualMidiOut)
{
m_pVirtualMidiOut->getMessage(&midiMsg_);
return !midiMsg_.empty();
}

return false;
}

bool MaschineMK1::writeMidiMsg()
{
static tRawData midiMsg_;

while (getNextMidiOutMsg(midiMsg_))
{
uint8_t lengthH = (midiMsg_.size() >> 8) & 0xFF;
uint8_t lengthL = midiMsg_.size() & 0xFF;
Transfer transfer({0x07, lengthH, lengthL}, midiMsg_.data(), midiMsg_.size());

if (!writeToDeviceHandle(transfer, kMASMK1_epOut))
{
M_LOG("[MaschineMK1] sendLeds: error writing midi message");
return false;
}
}
return true;
}

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

void MaschineMK1::processPads(const Transfer& input_)
{
for (int i = 1; i < kMASMK1_padDataSize - 1; i += 2)
Expand All @@ -442,6 +507,64 @@ void MaschineMK1::processPads(const Transfer& input_)
}
}
}
//
//--------------------------------------------------------------------------------------------------

bool popCompleteMidiMsg( std::deque<uint8_t> & midi_buffer, tRawData & out_msg )
{
while ( !midi_buffer.empty()
&& ( midi_buffer[0]&0x80 == 0 // Skipping until first command bit.
|| midi_buffer[0]&0xF0 == 0xF0 ) ) // Skipping non music commands.
{
midi_buffer.pop_front();
}

if (midi_buffer.empty())
{
return false;
}

uint8_t msg_type = midi_buffer[0];

uint8_t expected_size = 3;
if ( msg_type & 0xC0 // MidiMessage::Type::ProgramChange
|| msg_type & 0xD0 ) // MidiMessage::Type::ChannelPressure
{
expected_size = 2;
}

if (midi_buffer.size() < expected_size)
{
//Should wait for next chunk of message.
return false;
}

out_msg.clear();
for ( size_t i=0 ; i<expected_size ; ++i )
{
out_msg.push_back( midi_buffer.front() );
midi_buffer.pop_front();
}

return true;
}

void MaschineMK1::processMidiIn(const Transfer& input_)
{
for (size_t i=3; i<input_.size(); ++i)
{
m_MidiInBuffer.push_back( input_[i] );
}

tRawData msg;
while ( popCompleteMidiMsg(m_MidiInBuffer, msg) )
{
if (m_pVirtualMidiIn)
{
m_pVirtualMidiIn->sendMessage( &msg );
}
}
}

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

Expand Down Expand Up @@ -735,8 +858,7 @@ void MaschineMK1::cbRead(Transfer input_)
}
else if (input_[0] == 0x06)
{
M_LOG("[MaschineMK1] read: received MIDI message");
//!\todo Add MIDI in parsing
processMidiIn(input_);
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/devices/ni/MaschineMK1.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#pragma once

#include <bitset>
#include <deque>

#include "cabl/comm/Transfer.h"
#include "cabl/devices/Device.h"
Expand Down Expand Up @@ -77,9 +78,13 @@ class MaschineMK1 : public Device
bool sendLeds();
bool read();

bool getNextMidiOutMsg(tRawData & midiMsg_);
bool writeMidiMsg();

void processPads(const Transfer&);
void processButtons(const Transfer&);
void processEncoders(const Transfer&);
void processMidiIn(const Transfer&);

void setLedImpl(Led, const Color&);
Led led(Device::Button) const noexcept;
Expand All @@ -105,6 +110,12 @@ class MaschineMK1 : public Device
bool m_isDirtyLedGroup0{true};
bool m_isDirtyLedGroup1{true};
bool m_encodersInitialized{false};

std::deque<tRawData> m_MidiOutQueue;
std::deque<uint8_t> m_MidiInBuffer;

std::unique_ptr<RtMidiOut> m_pVirtualMidiIn;
std::unique_ptr<RtMidiIn> m_pVirtualMidiOut;
};

//--------------------------------------------------------------------------------------------------
Expand Down