winamp/Src/external_dependencies/openmpt-trunk/mptrack/MIDIMapping.cpp
2024-09-24 14:54:57 +02:00

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 &paramindex, uint16 &paramval)
{
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