173 lines
4.5 KiB
C++
173 lines
4.5 KiB
C++
/*
|
|
* MIDIMapping.cpp
|
|
* ---------------
|
|
* Purpose: MIDI Mapping management classes
|
|
* Notes : (currently none)
|
|
* Authors: OpenMPT Devs
|
|
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
|
*/
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "Moddoc.h"
|
|
#include "MIDIMapping.h"
|
|
#include "../common/FileReader.h"
|
|
#include "../soundlib/MIDIEvents.h"
|
|
#include "../soundlib/plugins/PlugInterface.h"
|
|
#include "mpt/io/io.hpp"
|
|
#include "mpt/io/io_stdstream.hpp"
|
|
|
|
|
|
OPENMPT_NAMESPACE_BEGIN
|
|
|
|
|
|
size_t CMIDIMapper::Serialize(std::ostream *file) const
|
|
{
|
|
//Bytes: 1 Flags, 2 key, 1 plugindex, 1,2,4,8 plug/etc.
|
|
size_t size = 0;
|
|
for(const auto &d : m_Directives)
|
|
{
|
|
uint16 temp16 = (d.GetChnEvent() << 1) + (d.GetController() << 9);
|
|
if(d.GetAnyChannel()) temp16 |= 1;
|
|
uint32 temp32 = d.GetParamIndex();
|
|
|
|
uint8 temp8 = d.IsActive(); //bit 0
|
|
if(d.GetCaptureMIDI()) temp8 |= (1 << 1); //bit 1
|
|
//bits 2-4: Mapping type: 0 for plug param control.
|
|
//bit 5:
|
|
if(d.GetAllowPatternEdit()) temp8 |= (1 << 5);
|
|
//bits 6-7: Size: 5, 6, 8, 12
|
|
|
|
uint8 parambytes = 4;
|
|
if(temp32 <= uint16_max)
|
|
{
|
|
if(temp32 <= uint8_max) parambytes = 1;
|
|
else {parambytes = 2; temp8 |= (1 << 6);}
|
|
}
|
|
else temp8 |= (2 << 6);
|
|
|
|
if(file)
|
|
{
|
|
std::ostream & f = *file;
|
|
mpt::IO::WriteIntLE<uint8>(f, temp8);
|
|
mpt::IO::WriteIntLE<uint16>(f, temp16);
|
|
mpt::IO::WriteIntLE<uint8>(f, d.GetPlugIndex());
|
|
mpt::IO::WritePartial<uint32le>(f, mpt::as_le(temp32), parambytes);
|
|
}
|
|
size += sizeof(temp8) + sizeof(temp16) + sizeof(temp8) + parambytes;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
|
|
bool CMIDIMapper::Deserialize(FileReader &file)
|
|
{
|
|
m_Directives.clear();
|
|
while(file.CanRead(1))
|
|
{
|
|
uint8 i8 = file.ReadUint8();
|
|
uint8 psize = 0;
|
|
// Determine size of this event (depends on size of plugin parameter index)
|
|
switch(i8 >> 6)
|
|
{
|
|
case 0: psize = 4; break;
|
|
case 1: psize = 5; break;
|
|
case 2: psize = 7; break;
|
|
case 3: default: psize = 11; break;
|
|
}
|
|
|
|
if(!file.CanRead(psize)) return false;
|
|
if(((i8 >> 2) & 7) != 0) { file.Skip(psize); continue;} //Skipping unrecognised mapping types.
|
|
|
|
CMIDIMappingDirective s;
|
|
s.SetActive((i8 & 1) != 0);
|
|
s.SetCaptureMIDI((i8 & (1 << 1)) != 0);
|
|
s.SetAllowPatternEdit((i8 & (1 << 5)) != 0);
|
|
uint16 i16 = file.ReadUint16LE(); //Channel, event, MIDIbyte1.
|
|
i8 = file.ReadUint8(); //Plugindex
|
|
uint32le i32;
|
|
file.ReadStructPartial(i32, psize - 3);
|
|
|
|
s.SetChannel(((i16 & 1) != 0) ? 0 : 1 + ((i16 >> 1) & 0xF));
|
|
s.SetEvent(static_cast<uint8>((i16 >> 5) & 0xF));
|
|
s.SetController(i16 >> 9);
|
|
s.SetPlugIndex(i8);
|
|
s.SetParamIndex(i32);
|
|
AddDirective(s);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CMIDIMapper::OnMIDImsg(const DWORD midimsg, PLUGINDEX &mappedIndex, PlugParamIndex ¶mindex, uint16 ¶mval)
|
|
{
|
|
const MIDIEvents::EventType eventType = MIDIEvents::GetTypeFromEvent(midimsg);
|
|
const uint8 controller = MIDIEvents::GetDataByte1FromEvent(midimsg);
|
|
const uint8 channel = MIDIEvents::GetChannelFromEvent(midimsg) & 0x7F;
|
|
const uint8 controllerVal = MIDIEvents::GetDataByte2FromEvent(midimsg) & 0x7F;
|
|
|
|
for(const auto &d : m_Directives)
|
|
{
|
|
if(!d.IsActive()) continue;
|
|
if(d.GetEvent() != eventType) continue;
|
|
if(eventType == MIDIEvents::evControllerChange
|
|
&& d.GetController() != controller
|
|
&& (d.GetController() >= 32 || d.GetController() + 32 != controller))
|
|
continue;
|
|
if(!d.GetAnyChannel() && channel + 1 != d.GetChannel()) continue;
|
|
|
|
const PLUGINDEX plugindex = d.GetPlugIndex();
|
|
const uint32 param = d.GetParamIndex();
|
|
uint16 val = (d.GetEvent() == MIDIEvents::evChannelAftertouch ? controller : controllerVal) << 7;
|
|
|
|
if(eventType == MIDIEvents::evControllerChange)
|
|
{
|
|
// Fine (0...31) / Coarse (32...63) controller pairs - Fine should be sent first.
|
|
if(controller == m_lastCC + 32 && m_lastCC < 32)
|
|
{
|
|
val = (val >> 7) | m_lastCCvalue;
|
|
}
|
|
m_lastCC = controller;
|
|
m_lastCCvalue = val;
|
|
}
|
|
|
|
if(d.GetAllowPatternEdit())
|
|
{
|
|
mappedIndex = plugindex;
|
|
paramindex = param;
|
|
paramval = val;
|
|
}
|
|
|
|
if(plugindex > 0 && plugindex <= MAX_MIXPLUGINS)
|
|
{
|
|
#ifndef NO_PLUGINS
|
|
IMixPlugin *pPlug = m_rSndFile.m_MixPlugins[plugindex - 1].pMixPlugin;
|
|
if(!pPlug) continue;
|
|
pPlug->SetParameter(param, val / 16383.0f);
|
|
if(m_rSndFile.GetpModDoc() != nullptr)
|
|
m_rSndFile.GetpModDoc()->SetModified();
|
|
#endif // NO_PLUGINS
|
|
}
|
|
if(d.GetCaptureMIDI())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void CMIDIMapper::Swap(const size_t a, const size_t b)
|
|
{
|
|
if(a < m_Directives.size() && b < m_Directives.size())
|
|
{
|
|
std::swap(m_Directives[a], m_Directives[b]);
|
|
Sort();
|
|
}
|
|
}
|
|
|
|
|
|
OPENMPT_NAMESPACE_END
|