Fixes for SYSEX channel messages / Added master volume method (also for SYSEX) (#249)

* Fix for using the right MIDI channel for SYSEX.
Fix for SYSEX MIDI dump output.

* Small fixes for recognizing MIDI channel in SYSEX.
Disabled printing of MIDI data in incoming serial data.
Added some mor debug output.

* Reenabled showing incomfing MIDI data when MIDI-DUmp is enabled.
Fix for using MIDI channel for SYSEX.

* Several fixes for SYSEX handling.

* Code for sending a voice dump via MIDI started.

* Fix for sending SYSEX voice dump to all interfaces.

* Sending voice data via SYSEX when voice is changed.
Adding master volume and changing master volume when SYSEX master volume is triggered.

* Forgot to initialize nMasterVolume - just added it.

* Merge.

* Added a SpinLock around MIDI message processing.

* Added notesOff() when changing algorithm parameter (can be extended later for other parameters).

Co-authored-by: Holger Wirtz <wirtz@parasitstudio.de>
pull/228/head
Holger 2 years ago committed by GitHub
parent 2f044b6fcb
commit c00ed09398
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 106
      src/mididevice.cpp
  2. 9
      src/mididevice.h
  3. 144
      src/minidexed.cpp
  4. 5
      src/minidexed.h
  5. 16
      src/serialmididevice.cpp

@ -114,24 +114,37 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
switch(pMessage[0]) switch(pMessage[0])
{ {
case MIDI_SYSTEM_EXCLUSIVE_BEGIN: case MIDI_SYSTEM_EXCLUSIVE_BEGIN:
printf("SysEx data length: [%d]\n",uint16_t(nLength)); printf("MIDI%u: SysEx data length: [%d]:",nCable, uint16_t(nLength));
printf("SysEx data:\n");
for (uint16_t i = 0; i < nLength; i++) for (uint16_t i = 0; i < nLength; i++)
{ {
if((i % 8) == 0) if((i % 16) == 0)
printf("%04d:",i); printf("\n%04d:",i);
printf(" 0x%02x",pMessage[i]); printf(" 0x%02x",pMessage[i]);
if((i % 8) == 0)
printf("\n");
} }
printf("\n");
break; break;
default: default:
printf("Unhandled MIDI event type %0x02x\n",pMessage[0]); printf("MIDI%u: Unhandled MIDI event type %0x02x\n",nCable,pMessage[0]);
} }
break; break;
} }
} }
// Only for debugging:
/*
if(pMessage[0]==MIDI_SYSTEM_EXCLUSIVE_BEGIN)
{
printf("MIDI%u: SysEx data length: [%d]:",nCable, uint16_t(nLength));
for (uint16_t i = 0; i < nLength; i++)
{
if((i % 16) == 0)
printf("\n%04d:",i);
printf(" 0x%02x",pMessage[i]);
}
printf("\n");
}
*/
// Handle MIDI Thru // Handle MIDI Thru
if (m_DeviceName.compare (m_pConfig->GetMIDIThruIn ()) == 0) if (m_DeviceName.compare (m_pConfig->GetMIDIThruIn ()) == 0)
{ {
@ -150,6 +163,8 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
return; return;
} }
m_MIDISpinLock.Acquire ();
u8 ucStatus = pMessage[0]; u8 ucStatus = pMessage[0];
u8 ucChannel = ucStatus & 0x0F; u8 ucChannel = ucStatus & 0x0F;
u8 ucType = ucStatus >> 4; u8 ucType = ucStatus >> 4;
@ -157,17 +172,24 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
// GLOBAL MIDI SYSEX // GLOBAL MIDI SYSEX
if (pMessage[0] == MIDI_SYSTEM_EXCLUSIVE_BEGIN && pMessage[3] == 0x04 && pMessage[4] == 0x01 && pMessage[nLength-1] == MIDI_SYSTEM_EXCLUSIVE_END) // MASTER VOLUME if (pMessage[0] == MIDI_SYSTEM_EXCLUSIVE_BEGIN && pMessage[3] == 0x04 && pMessage[4] == 0x01 && pMessage[nLength-1] == MIDI_SYSTEM_EXCLUSIVE_END) // MASTER VOLUME
{ {
float32_t nMasterVolume=(pMessage[5] & (pMessage[6]<<7))/(1<<14); float32_t nMasterVolume=((pMessage[5] & 0x7c) & ((pMessage[6] & 0x7c) <<7))/(1<<14);
LOGNOTE("Master volume: %f",nMasterVolume); LOGNOTE("Master volume: %f",nMasterVolume);
// TODO: Handle global master volume m_pSynthesizer->setMasterVolume(nMasterVolume);
} }
else else
{ {
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{ {
// MIDI SYSEX per MIDI channel if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN)
if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN && m_ChannelMap[nTG] == pMessage[2] & 0x07) {
HandleSystemExclusive(pMessage, nLength, nTG); // MIDI SYSEX per MIDI channel
uint8_t ucSysExChannel = (pMessage[2] & 0x07);
if (m_ChannelMap[nTG] == ucSysExChannel || m_ChannelMap[nTG] == OmniMode)
{
LOGNOTE("MIDI-SYSEX: channel: %u, len: %u, TG: %u",m_ChannelMap[nTG],nLength,nTG);
HandleSystemExclusive(pMessage, nLength, nCable, nTG);
}
}
else else
{ {
if ( m_ChannelMap[nTG] == ucChannel if ( m_ChannelMap[nTG] == ucChannel
@ -293,6 +315,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
} }
} }
} }
m_MIDISpinLock.Release ();
} }
void CMIDIDevice::AddDevice (const char *pDeviceName) void CMIDIDevice::AddDevice (const char *pDeviceName)
@ -306,7 +329,7 @@ void CMIDIDevice::AddDevice (const char *pDeviceName)
s_DeviceMap.insert (std::pair<std::string, CMIDIDevice *> (pDeviceName, this)); s_DeviceMap.insert (std::pair<std::string, CMIDIDevice *> (pDeviceName, this));
} }
void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const uint8_t nTG) void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG)
{ {
int16_t sysex_return; int16_t sysex_return;
@ -319,33 +342,33 @@ void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nL
LOGERR("SysEx end status byte not detected."); LOGERR("SysEx end status byte not detected.");
break; break;
case -2: case -2:
LOGERR("E: SysEx vendor not Yamaha."); LOGERR("SysEx vendor not Yamaha.");
break; break;
case -3: case -3:
LOGERR("E: Unknown SysEx parameter change."); LOGERR("Unknown SysEx parameter change.");
break; break;
case -4: case -4:
LOGERR(" Unknown SysEx voice or function."); LOGERR("Unknown SysEx voice or function.");
break; break;
case -5: case -5:
LOGERR("E: Not a SysEx voice bulk upload."); LOGERR("Not a SysEx voice bulk upload.");
break; break;
case -6: case -6:
LOGERR("E: Wrong length for SysEx voice bulk upload (not 155)."); LOGERR("Wrong length for SysEx voice bulk upload (not 155).");
break; break;
case -7: case -7:
LOGERR("E: Checksum error for one voice."); LOGERR("Checksum error for one voice.");
break; break;
case -8: case -8:
LOGERR("E: Not a SysEx bank bulk upload."); LOGERR("Not a SysEx bank bulk upload.");
break; break;
case -9: case -9:
LOGERR("E: Wrong length for SysEx bank bulk upload (not 4096)."); LOGERR("Wrong length for SysEx bank bulk upload (not 4096).");
case -10: case -10:
LOGERR("E: Checksum error for bank."); LOGERR("Checksum error for bank.");
break; break;
case -11: case -11:
LOGERR("E: Unknown SysEx message."); LOGERR("Unknown SysEx message.");
break; break;
case 64: case 64:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
@ -407,7 +430,6 @@ void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nL
// load sysex-data into voice memory // load sysex-data into voice memory
LOGDBG("One Voice bulk upload"); LOGDBG("One Voice bulk upload");
m_pSynthesizer->loadVoiceParameters(pMessage,nTG); m_pSynthesizer->loadVoiceParameters(pMessage,nTG);
break; break;
case 200: case 200:
LOGDBG("Bank bulk upload."); LOGDBG("Bank bulk upload.");
@ -415,9 +437,41 @@ void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nL
LOGNOTE("Currently code for storing a bulk bank upload is missing!"); LOGNOTE("Currently code for storing a bulk bank upload is missing!");
break; break;
default: default:
LOGDBG("SysEx voice parameter change: %d value: %d",pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5]); if(sysex_return >= 300 && sysex_return < 500)
m_pSynthesizer->setVoiceDataElement(pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5],nTG); {
LOGDBG("SysEx voice parameter change: Parameter %d value: %d",pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5]);
m_pSynthesizer->setVoiceDataElement(pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5],nTG);
switch(pMessage[4] + ((pMessage[3] & 0x03) * 128))
{
case 134:
m_pSynthesizer->notesOff(0,nTG);
break;
}
}
else if(sysex_return >= 500 && sysex_return < 600)
{
LOGDBG("SysEx send voice %u request",sysex_return-500);
SendSystemExclusiveVoice(sysex_return-500, nCable, nTG);
}
break; break;
} }
} }
void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable, uint8_t nTG)
{
uint8_t voicedump[163];
LOGDBG("Sending SysEx voice %u ",nVoice);
// Get voice sysex dump from TG
m_pSynthesizer->getSysExVoiceDump(voicedump, nTG);
TDeviceMap::const_iterator Iterator;
// send voice dump to all MIDI interfaces
for(Iterator = s_DeviceMap.begin(); Iterator != s_DeviceMap.end(); ++Iterator)
{
Iterator->second->Send (voicedump, sizeof(voicedump)*sizeof(uint8_t), nCable);
LOGNOTE("Send SYSEX voice dump to \"%s\"\n",Iterator->first);
}
}

@ -27,6 +27,7 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <circle/types.h> #include <circle/types.h>
#include <circle/spinlock.h>
class CMiniDexed; class CMiniDexed;
@ -49,14 +50,12 @@ public:
u8 GetChannel (unsigned nTG) const; u8 GetChannel (unsigned nTG) const;
virtual void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) {} virtual void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) {}
virtual void SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable, uint8_t nTG);
protected: protected:
void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0); void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0);
void AddDevice (const char *pDeviceName); void AddDevice (const char *pDeviceName);
void HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG);
void HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const uint8_t nTG);
private: private:
CMiniDexed *m_pSynthesizer; CMiniDexed *m_pSynthesizer;
CConfig *m_pConfig; CConfig *m_pConfig;
@ -67,6 +66,8 @@ private:
typedef std::unordered_map<std::string, CMIDIDevice *> TDeviceMap; typedef std::unordered_map<std::string, CMIDIDevice *> TDeviceMap;
static TDeviceMap s_DeviceMap; static TDeviceMap s_DeviceMap;
CSpinLock m_MIDISpinLock;
}; };
#endif #endif

@ -125,6 +125,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
} }
#endif #endif
setMasterVolume(1.0);
// BEGIN setup tg_mixer // BEGIN setup tg_mixer
tg_mixer = new AudioStereoMixer<CConfig::ToneGenerators>(pConfig->GetChunkSize()/2); tg_mixer = new AudioStereoMixer<CConfig::ToneGenerators>(pConfig->GetChunkSize()/2);
// END setup tgmixer // END setup tgmixer
@ -371,6 +373,7 @@ void CMiniDexed::ProgramChange (unsigned nProgram, unsigned nTG)
assert (m_pTG[nTG]); assert (m_pTG[nTG]);
m_pTG[nTG]->loadVoiceParameters (Buffer); m_pTG[nTG]->loadVoiceParameters (Buffer);
m_SerialMIDI.SendSystemExclusiveVoice(nProgram,0,nTG);
m_UI.ParameterChanged (); m_UI.ParameterChanged ();
} }
@ -875,56 +878,70 @@ void CMiniDexed::ProcessSound (void)
} }
// BEGIN TG mixing // BEGIN TG mixing
for (uint8_t i = 0; i < CConfig::ToneGenerators; i++) float32_t tmp_float[nFrames*2];
{ int16_t tmp_int[nFrames*2];
tg_mixer->doAddMix(i,m_OutputLevel[i]);
reverb_send_mixer->doAddMix(i,m_OutputLevel[i]);
}
// END TG mixing
// BEGIN create SampleBuffer for holding audio data
float32_t SampleBuffer[2][nFrames];
// END create SampleBuffer for holding audio data
// get the mix of all TGs
tg_mixer->getMix(SampleBuffer[indexL], SampleBuffer[indexR]);
// BEGIN adding reverb if(nMasterVolume > 0.0)
if (m_nParameter[ParameterReverbEnable])
{ {
float32_t ReverbBuffer[2][nFrames]; for (uint8_t i = 0; i < CConfig::ToneGenerators; i++)
float32_t ReverbSendBuffer[2][nFrames]; {
tg_mixer->doAddMix(i,m_OutputLevel[i]);
arm_fill_f32(0.0f, ReverbBuffer[indexL], nFrames); reverb_send_mixer->doAddMix(i,m_OutputLevel[i]);
arm_fill_f32(0.0f, ReverbBuffer[indexR], nFrames); }
arm_fill_f32(0.0f, ReverbSendBuffer[indexR], nFrames); // END TG mixing
arm_fill_f32(0.0f, ReverbSendBuffer[indexL], nFrames);
// BEGIN create SampleBuffer for holding audio data
m_ReverbSpinLock.Acquire (); float32_t SampleBuffer[2][nFrames];
// END create SampleBuffer for holding audio data
reverb_send_mixer->getMix(ReverbSendBuffer[indexL], ReverbSendBuffer[indexR]);
reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames);
// scale down and add left reverb buffer by reverb level // get the mix of all TGs
arm_scale_f32(ReverbBuffer[indexL], reverb->get_level(), ReverbBuffer[indexL], nFrames); tg_mixer->getMix(SampleBuffer[indexL], SampleBuffer[indexR]);
arm_add_f32(SampleBuffer[indexL], ReverbBuffer[indexL], SampleBuffer[indexL], nFrames);
// scale down and add right reverb buffer by reverb level
arm_scale_f32(ReverbBuffer[indexR], reverb->get_level(), ReverbBuffer[indexR], nFrames);
arm_add_f32(SampleBuffer[indexR], ReverbBuffer[indexR], SampleBuffer[indexR], nFrames);
m_ReverbSpinLock.Release (); // BEGIN adding reverb
} if (m_nParameter[ParameterReverbEnable])
// END adding reverb {
float32_t ReverbBuffer[2][nFrames];
float32_t ReverbSendBuffer[2][nFrames];
// Convert dual float array (left, right) to single int16 array (left/right) arm_fill_f32(0.0f, ReverbBuffer[indexL], nFrames);
float32_t tmp_float[nFrames*2]; arm_fill_f32(0.0f, ReverbBuffer[indexR], nFrames);
int16_t tmp_int[nFrames*2]; arm_fill_f32(0.0f, ReverbSendBuffer[indexR], nFrames);
for(uint16_t i=0; i<nFrames;i++) arm_fill_f32(0.0f, ReverbSendBuffer[indexL], nFrames);
{
tmp_float[i*2]=SampleBuffer[indexL][i]; m_ReverbSpinLock.Acquire ();
tmp_float[(i*2)+1]=SampleBuffer[indexR][i];
reverb_send_mixer->getMix(ReverbSendBuffer[indexL], ReverbSendBuffer[indexR]);
reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames);
// scale down and add left reverb buffer by reverb level
arm_scale_f32(ReverbBuffer[indexL], reverb->get_level(), ReverbBuffer[indexL], nFrames);
arm_add_f32(SampleBuffer[indexL], ReverbBuffer[indexL], SampleBuffer[indexL], nFrames);
// scale down and add right reverb buffer by reverb level
arm_scale_f32(ReverbBuffer[indexR], reverb->get_level(), ReverbBuffer[indexR], nFrames);
arm_add_f32(SampleBuffer[indexR], ReverbBuffer[indexR], SampleBuffer[indexR], nFrames);
m_ReverbSpinLock.Release ();
}
// END adding reverb
// Convert dual float array (left, right) to single int16 array (left/right)
for(uint16_t i=0; i<nFrames;i++)
{
if(nMasterVolume >0.0 && nMasterVolume <1.0)
{
tmp_float[i*2]=SampleBuffer[indexL][i] * nMasterVolume;
tmp_float[(i*2)+1]=SampleBuffer[indexR][i] * nMasterVolume;
}
else if(nMasterVolume == 1.0)
{
tmp_float[i*2]=SampleBuffer[indexL][i];
tmp_float[(i*2)+1]=SampleBuffer[indexR][i];
}
}
arm_float_to_q15(tmp_float,tmp_int,nFrames*2);
} }
arm_float_to_q15(tmp_float,tmp_int,nFrames*2); else
arm_fill_q15(0, tmp_int, nFrames * 2);
if (m_pSoundDevice->Write (tmp_int, sizeof(tmp_int)) != (int) sizeof(tmp_int)) if (m_pSoundDevice->Write (tmp_int, sizeof(tmp_int)) != (int) sizeof(tmp_int))
{ {
@ -1168,5 +1185,44 @@ void CMiniDexed::setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG)
int16_t CMiniDexed::checkSystemExclusive(const uint8_t* pMessage,const uint16_t nLength, uint8_t nTG) int16_t CMiniDexed::checkSystemExclusive(const uint8_t* pMessage,const uint16_t nLength, uint8_t nTG)
{ {
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
return(m_pTG[nTG]->checkSystemExclusive(pMessage, nLength)); return(m_pTG[nTG]->checkSystemExclusive(pMessage, nLength));
} }
void CMiniDexed::getSysExVoiceDump(uint8_t* dest, uint8_t nTG)
{
uint8_t checksum = 0;
uint8_t data[155];
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->getVoiceData(data);
dest[0] = 0xF0; // SysEx start
dest[1] = 0x43; // ID=Yamaha
dest[2] = GetTGParameter(TGParameterMIDIChannel, nTG); // Sub-status and MIDI channel
dest[3] = 0x00; // Format number (0=1 voice)
dest[4] = 0x01; // Byte count MSB
dest[5] = 0x1B; // Byte count LSB
for (uint8_t n = 0; n < 155; n++)
{
checksum -= data[n];
dest[6 + n] = data[n];
}
dest[161] = checksum & 0x7f; // Checksum
dest[162] = 0xF7; // SysEx end
}
void CMiniDexed::setMasterVolume (float32_t vol)
{
if(vol < 0.0)
vol = 0.0;
else if(vol > 1.0)
vol = 1.0;
nMasterVolume=vol;
}

@ -100,6 +100,7 @@ public:
void setAftertouchTarget(uint8_t target, uint8_t nTG); void setAftertouchTarget(uint8_t target, uint8_t nTG);
void loadVoiceParameters(const uint8_t* data, uint8_t nTG); void loadVoiceParameters(const uint8_t* data, uint8_t nTG);
void setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG); void setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG);
void getSysExVoiceDump(uint8_t* dest, uint8_t nTG);
int16_t checkSystemExclusive(const uint8_t* pMessage, const uint16_t nLength, uint8_t nTG); int16_t checkSystemExclusive(const uint8_t* pMessage, const uint16_t nLength, uint8_t nTG);
@ -151,6 +152,8 @@ public:
bool SavePerformance (void); bool SavePerformance (void);
bool DoSavePerformance (void); bool DoSavePerformance (void);
void setMasterVolume (float32_t vol);
private: private:
int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note
uint8_t m_uchOPMask[CConfig::ToneGenerators]; uint8_t m_uchOPMask[CConfig::ToneGenerators];
@ -195,6 +198,8 @@ private:
unsigned m_nReverbSend[CConfig::ToneGenerators]; unsigned m_nReverbSend[CConfig::ToneGenerators];
float32_t nMasterVolume;
CUserInterface m_UI; CUserInterface m_UI;
CSysExFileLoader m_SysExFileLoader; CSysExFileLoader m_SysExFileLoader;
CPerformanceConfig m_PerformanceConfig; CPerformanceConfig m_PerformanceConfig;

@ -20,10 +20,14 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
#include <circle/logger.h>
#include <cstring> #include <cstring>
#include "serialmididevice.h" #include "serialmididevice.h"
#include <assert.h> #include <assert.h>
LOGMODULE("serialmididevice");
CSerialMIDIDevice::CSerialMIDIDevice (CMiniDexed *pSynthesizer, CInterruptSystem *pInterrupt, CSerialMIDIDevice::CSerialMIDIDevice (CMiniDexed *pSynthesizer, CInterruptSystem *pInterrupt,
CConfig *pConfig) CConfig *pConfig)
: CMIDIDevice (pSynthesizer, pConfig), : CMIDIDevice (pSynthesizer, pConfig),
@ -58,23 +62,20 @@ void CSerialMIDIDevice::Process (void)
if (nResult <= 0) if (nResult <= 0)
{ {
if(nResult!=0) if(nResult!=0)
printf("Serial-Read: %d\n",nResult); LOGERR("Serial.Read() error: %d\n",nResult);
return; return;
} }
if (m_pConfig->GetMIDIDumpEnabled ()) if (m_pConfig->GetMIDIDumpEnabled ())
{ {
printf("Incoming MIDI data:\n"); printf("Incoming MIDI data:");
for (uint16_t i = 0; i < nResult; i++) for (uint16_t i = 0; i < nResult; i++)
{ {
if((i % 8) == 0) if((i % 8) == 0)
printf("%04d:",i); printf("\n%04d:",i);
printf(" 0x%02x",Buffer[i]); printf(" 0x%02x",Buffer[i]);
if((i > 1 ) && (i % 8) == 0)
printf("\n");
} }
if((nResult % 8) != 0) printf("\n");
printf("\n");
} }
// Process MIDI messages // Process MIDI messages
@ -157,6 +158,7 @@ void CSerialMIDIDevice::Process (void)
} }
} }
} }
void CSerialMIDIDevice::Send (const u8 *pMessage, size_t nLength, unsigned nCable) void CSerialMIDIDevice::Send (const u8 *pMessage, size_t nLength, unsigned nCable)
{ {
m_SendBuffer.Write (pMessage, nLength); m_SendBuffer.Write (pMessage, nLength);

Loading…
Cancel
Save