MIDIMapping.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * MIDIMapping.cpp
  3. * ---------------
  4. * Purpose: MIDI Mapping management classes
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "Moddoc.h"
  11. #include "MIDIMapping.h"
  12. #include "../common/FileReader.h"
  13. #include "../soundlib/MIDIEvents.h"
  14. #include "../soundlib/plugins/PlugInterface.h"
  15. #include "mpt/io/io.hpp"
  16. #include "mpt/io/io_stdstream.hpp"
  17. OPENMPT_NAMESPACE_BEGIN
  18. size_t CMIDIMapper::Serialize(std::ostream *file) const
  19. {
  20. //Bytes: 1 Flags, 2 key, 1 plugindex, 1,2,4,8 plug/etc.
  21. size_t size = 0;
  22. for(const auto &d : m_Directives)
  23. {
  24. uint16 temp16 = (d.GetChnEvent() << 1) + (d.GetController() << 9);
  25. if(d.GetAnyChannel()) temp16 |= 1;
  26. uint32 temp32 = d.GetParamIndex();
  27. uint8 temp8 = d.IsActive(); //bit 0
  28. if(d.GetCaptureMIDI()) temp8 |= (1 << 1); //bit 1
  29. //bits 2-4: Mapping type: 0 for plug param control.
  30. //bit 5:
  31. if(d.GetAllowPatternEdit()) temp8 |= (1 << 5);
  32. //bits 6-7: Size: 5, 6, 8, 12
  33. uint8 parambytes = 4;
  34. if(temp32 <= uint16_max)
  35. {
  36. if(temp32 <= uint8_max) parambytes = 1;
  37. else {parambytes = 2; temp8 |= (1 << 6);}
  38. }
  39. else temp8 |= (2 << 6);
  40. if(file)
  41. {
  42. std::ostream & f = *file;
  43. mpt::IO::WriteIntLE<uint8>(f, temp8);
  44. mpt::IO::WriteIntLE<uint16>(f, temp16);
  45. mpt::IO::WriteIntLE<uint8>(f, d.GetPlugIndex());
  46. mpt::IO::WritePartial<uint32le>(f, mpt::as_le(temp32), parambytes);
  47. }
  48. size += sizeof(temp8) + sizeof(temp16) + sizeof(temp8) + parambytes;
  49. }
  50. return size;
  51. }
  52. bool CMIDIMapper::Deserialize(FileReader &file)
  53. {
  54. m_Directives.clear();
  55. while(file.CanRead(1))
  56. {
  57. uint8 i8 = file.ReadUint8();
  58. uint8 psize = 0;
  59. // Determine size of this event (depends on size of plugin parameter index)
  60. switch(i8 >> 6)
  61. {
  62. case 0: psize = 4; break;
  63. case 1: psize = 5; break;
  64. case 2: psize = 7; break;
  65. case 3: default: psize = 11; break;
  66. }
  67. if(!file.CanRead(psize)) return false;
  68. if(((i8 >> 2) & 7) != 0) { file.Skip(psize); continue;} //Skipping unrecognised mapping types.
  69. CMIDIMappingDirective s;
  70. s.SetActive((i8 & 1) != 0);
  71. s.SetCaptureMIDI((i8 & (1 << 1)) != 0);
  72. s.SetAllowPatternEdit((i8 & (1 << 5)) != 0);
  73. uint16 i16 = file.ReadUint16LE(); //Channel, event, MIDIbyte1.
  74. i8 = file.ReadUint8(); //Plugindex
  75. uint32le i32;
  76. file.ReadStructPartial(i32, psize - 3);
  77. s.SetChannel(((i16 & 1) != 0) ? 0 : 1 + ((i16 >> 1) & 0xF));
  78. s.SetEvent(static_cast<uint8>((i16 >> 5) & 0xF));
  79. s.SetController(i16 >> 9);
  80. s.SetPlugIndex(i8);
  81. s.SetParamIndex(i32);
  82. AddDirective(s);
  83. }
  84. return true;
  85. }
  86. bool CMIDIMapper::OnMIDImsg(const DWORD midimsg, PLUGINDEX &mappedIndex, PlugParamIndex &paramindex, uint16 &paramval)
  87. {
  88. const MIDIEvents::EventType eventType = MIDIEvents::GetTypeFromEvent(midimsg);
  89. const uint8 controller = MIDIEvents::GetDataByte1FromEvent(midimsg);
  90. const uint8 channel = MIDIEvents::GetChannelFromEvent(midimsg) & 0x7F;
  91. const uint8 controllerVal = MIDIEvents::GetDataByte2FromEvent(midimsg) & 0x7F;
  92. for(const auto &d : m_Directives)
  93. {
  94. if(!d.IsActive()) continue;
  95. if(d.GetEvent() != eventType) continue;
  96. if(eventType == MIDIEvents::evControllerChange
  97. && d.GetController() != controller
  98. && (d.GetController() >= 32 || d.GetController() + 32 != controller))
  99. continue;
  100. if(!d.GetAnyChannel() && channel + 1 != d.GetChannel()) continue;
  101. const PLUGINDEX plugindex = d.GetPlugIndex();
  102. const uint32 param = d.GetParamIndex();
  103. uint16 val = (d.GetEvent() == MIDIEvents::evChannelAftertouch ? controller : controllerVal) << 7;
  104. if(eventType == MIDIEvents::evControllerChange)
  105. {
  106. // Fine (0...31) / Coarse (32...63) controller pairs - Fine should be sent first.
  107. if(controller == m_lastCC + 32 && m_lastCC < 32)
  108. {
  109. val = (val >> 7) | m_lastCCvalue;
  110. }
  111. m_lastCC = controller;
  112. m_lastCCvalue = val;
  113. }
  114. if(d.GetAllowPatternEdit())
  115. {
  116. mappedIndex = plugindex;
  117. paramindex = param;
  118. paramval = val;
  119. }
  120. if(plugindex > 0 && plugindex <= MAX_MIXPLUGINS)
  121. {
  122. #ifndef NO_PLUGINS
  123. IMixPlugin *pPlug = m_rSndFile.m_MixPlugins[plugindex - 1].pMixPlugin;
  124. if(!pPlug) continue;
  125. pPlug->SetParameter(param, val / 16383.0f);
  126. if(m_rSndFile.GetpModDoc() != nullptr)
  127. m_rSndFile.GetpModDoc()->SetModified();
  128. #endif // NO_PLUGINS
  129. }
  130. if(d.GetCaptureMIDI())
  131. {
  132. return true;
  133. }
  134. }
  135. return false;
  136. }
  137. void CMIDIMapper::Swap(const size_t a, const size_t b)
  138. {
  139. if(a < m_Directives.size() && b < m_Directives.size())
  140. {
  141. std::swap(m_Directives[a], m_Directives[b]);
  142. Sort();
  143. }
  144. }
  145. OPENMPT_NAMESPACE_END