diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 6ed1513..ca76f8a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -11,7 +11,7 @@ on:
 jobs:
   Build:
 
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
 
     steps:
     - uses: actions/checkout@v2
diff --git a/src/mididevice.cpp b/src/mididevice.cpp
index fefe9fc..90fefbd 100644
--- a/src/mididevice.cpp
+++ b/src/mididevice.cpp
@@ -2,7 +2,7 @@
 // mididevice.cpp
 //
 // MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi
-// Copyright (C) 2022  The MiniDexed Team
+// Copyright (C) 2022-25  The MiniDexed Team
 //
 // Original author of this class:
 //	R. Stange <rsta2@o2online.de>
@@ -51,6 +51,10 @@ LOGMODULE ("mididevice");
 	#define MIDI_CC_DETUNE_LEVEL		94
 	#define MIDI_CC_ALL_SOUND_OFF		120
 	#define MIDI_CC_ALL_NOTES_OFF		123
+	#define MIDI_CC_OMNI_MODE_OFF		124
+	#define MIDI_CC_OMNI_MODE_ON		125
+	#define MIDI_CC_MONO_MODE_ON		126
+	#define MIDI_CC_POLY_MODE_ON		127
 #define MIDI_PROGRAM_CHANGE	0b1100
 #define MIDI_PITCH_BEND		0b1110
 
@@ -84,6 +88,7 @@ CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInter
 	for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++)
 	{
 		m_ChannelMap[nTG] = Disabled;
+		m_PreviousChannelMap[nTG] = Disabled; // Initialize previous channel map
 	}
 
 	m_nMIDISystemCCVol = m_pConfig->GetMIDISystemCCVol();
@@ -132,6 +137,12 @@ CMIDIDevice::~CMIDIDevice (void)
 void CMIDIDevice::SetChannel (u8 ucChannel, unsigned nTG)
 {
 	assert (nTG < CConfig::AllToneGenerators);
+	
+	// When changing to OMNI mode, store the previous channel
+	if (ucChannel == OmniMode && m_ChannelMap[nTG] != OmniMode) {
+		m_PreviousChannelMap[nTG] = m_ChannelMap[nTG];
+	}
+	
 	m_ChannelMap[nTG] = ucChannel;
 }
 
@@ -265,6 +276,59 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
 	}
 	else
 	{
+		// Handle Voice Dump Request SysEx (Format 0)
+		if (nLength == 5 &&
+			pMessage[0] == MIDI_SYSTEM_EXCLUSIVE_BEGIN &&
+			pMessage[1] == 0x43 &&  // Yamaha manufacturer ID
+			(pMessage[2] & 0xF0) == 0x20 && // Status byte with channel (0x2n)
+			pMessage[3] == 0x00 &&  // Format 0 (single voice)
+			pMessage[4] == MIDI_SYSTEM_EXCLUSIVE_END) {
+			uint8_t channel = pMessage[2] & 0x0F;
+			LOGDBG("Voice Dump Request (Format 0) received for channel %d", channel);
+			
+			// Find TG matching this channel
+			bool found = false;
+			for (unsigned nTG = 0; nTG < m_pConfig->GetToneGenerators(); nTG++) {
+				if (m_ChannelMap[nTG] == channel || m_ChannelMap[nTG] == OmniMode) {
+					SendSystemExclusiveVoice(0, nCable, nTG);
+					found = true;
+					// Don't break here to allow multiple TGs on same channel to respond
+				}
+			}
+			
+			if (!found) {
+				// If no specific TG is found for this channel, respond with TG 0
+				SendSystemExclusiveVoice(0, nCable, 0);
+			}
+			return;
+		}
+
+		// Operator enable/disable SysEx handling - Format F0 43 11 g=0 h=1 1B p F7
+		// Where 1B (27) is parameter for operator on/off
+		// And p is a bitmask for operators (bit 0=OP6, bit 1=OP5, bit 2=OP4, bit 3=OP3, bit 4=OP2, bit 5=OP1)
+		if (nLength == 7 &&
+			pMessage[0] == MIDI_SYSTEM_EXCLUSIVE_BEGIN &&
+			pMessage[1] == 0x43 && // Yamaha manufacturer ID
+			pMessage[2] == 0x11 && // Sub-status byte (parameter change)
+			pMessage[3] == 0x01 && // Format byte (h=1, g=0)
+			pMessage[4] == 0x1B && // Parameter 27 (0x1B) - operator on/off
+			pMessage[5] <= 0x3F && // Value (6-bit mask, 0x00-0x3F valid range)
+			pMessage[6] == MIDI_SYSTEM_EXCLUSIVE_END) {
+			
+			uint8_t operatorMask = pMessage[5];
+			LOGDBG("Operator On/Off SysEx received: Mask 0x%02X", operatorMask);
+
+			// Apply to MIDI channel-specific TGs
+			uint8_t channel = 0; // Default to first channel if not specified
+			
+			// Find TGs to apply this to (apply to all TGs if from UI)
+			for (unsigned nTG = 0; nTG < m_pConfig->GetToneGenerators(); nTG++) {
+				// Set the operator mask directly (no toggling)
+				m_pSynthesizer->setOperatorMask(operatorMask, nTG);
+			}
+			return;
+		}
+
 		// Perform any MiniDexed level MIDI handling before specific Tone Generators
 		unsigned nPerfCh = m_pSynthesizer->GetPerformanceSelectChannel();
 		switch (ucType)
@@ -476,6 +540,35 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
 							}
 							break;
 
+						case MIDI_CC_OMNI_MODE_OFF:
+							// Sets to "Omni Off" mode
+							if (m_ChannelMap[nTG] == OmniMode) {
+								// Restore the previous channel if available, otherwise use current channel
+								u8 channelToRestore = (m_PreviousChannelMap[nTG] != Disabled) ? 
+									m_PreviousChannelMap[nTG] : ucChannel;
+								m_pSynthesizer->SetMIDIChannel(channelToRestore, nTG);
+								LOGDBG("Omni Mode Off: TG %d restored to MIDI channel %d", nTG, channelToRestore+1);
+							}
+							break;
+						
+						case MIDI_CC_OMNI_MODE_ON:
+							// Sets to "Omni On" mode
+							m_pSynthesizer->SetMIDIChannel(OmniMode, nTG);
+							LOGDBG("Omni Mode On: TG %d set to OMNI", nTG);
+							break;
+
+						case MIDI_CC_MONO_MODE_ON:
+							// Sets monophonic mode
+							m_pSynthesizer->setMonoMode(1, nTG);
+							LOGDBG("Mono Mode On: TG %d set to MONO", nTG);
+							break;
+
+						case MIDI_CC_POLY_MODE_ON:
+							// Sets polyphonic mode
+							m_pSynthesizer->setMonoMode(0, nTG);
+							LOGDBG("Poly Mode On: TG %d set to POLY", nTG);
+							break;
+
 						default:
 							// Check for system-level, cross-TG MIDI Controls, but only do it once.
 							// Also, if successfully handled, then no need to process other TGs,
@@ -720,4 +813,4 @@ void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable
     Iterator->second->Send (voicedump, sizeof(voicedump)*sizeof(uint8_t));
     // LOGDBG("Send SYSEX voice dump %u to \"%s\"",nVoice,Iterator->first.c_str());
   }
-} 
+}
diff --git a/src/mididevice.h b/src/mididevice.h
index a8eae40..94b789b 100644
--- a/src/mididevice.h
+++ b/src/mididevice.h
@@ -70,6 +70,7 @@ private:
 	CUserInterface *m_pUI;
 
 	u8 m_ChannelMap[CConfig::AllToneGenerators];
+	u8 m_PreviousChannelMap[CConfig::AllToneGenerators]; // Store previous channels for OMNI OFF restore
 	
 	unsigned m_nMIDISystemCCVol;
 	unsigned m_nMIDISystemCCPan;
diff --git a/src/minidexed.cpp b/src/minidexed.cpp
index 4d9a53c..72edb6f 100644
--- a/src/minidexed.cpp
+++ b/src/minidexed.cpp
@@ -2,7 +2,7 @@
 // minidexed.cpp
 //
 // MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi
-// Copyright (C) 2022  The MiniDexed Team
+// Copyright (C) 2022-25  The MiniDexed Team
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -1672,7 +1672,7 @@ void CMiniDexed::setBreathControllerTarget(uint8_t target, uint8_t nTG)
 
 	assert (m_pTG[nTG]);
 
-	m_nBreathControlTarget[nTG]=target;
+	m_nBreathControlTarget[nTG] = target;
 
 	m_pTG[nTG]->setBreathControllerTarget(constrain(target, 0, 7));
 	m_pTG[nTG]->ControllersRefresh();
@@ -2184,3 +2184,29 @@ unsigned CMiniDexed::getModController (unsigned controller, unsigned parameter,
 	}
 	
 }
+
+void CMiniDexed::setOperatorMask(uint8_t operatorMask, unsigned nTG) {
+    if (nTG >= CConfig::AllToneGenerators) {
+        LOGERR("Invalid tone generator: TG=%u", nTG);
+        return;
+    }
+
+    // According to Yamaha DX7/TX SysEx format:
+    // Bit 0 = OP6, Bit 1 = OP5, Bit 2 = OP4, Bit 3 = OP3, Bit 4 = OP2, Bit 5 = OP1
+    // For MiniDexed: Bit 0 = OP1, Bit 1 = OP2, etc. - need to reverse the bit order to match
+    
+    uint8_t reversedMask = 0;
+    for (int i = 0; i < 6; i++) {
+        if (operatorMask & (1 << i)) {
+            reversedMask |= (1 << (5 - i));
+        }
+    }
+    
+    m_uchOPMask[nTG] = reversedMask;
+    LOGDBG("Set operator mask for TG %u: Yamaha=0x%02X, Reversed=0x%02X", nTG, operatorMask, reversedMask);
+
+    // Apply the updated operator mask to the tone generator
+    if (nTG < m_nToneGenerators) {
+        m_pTG[nTG]->setOPAll(m_uchOPMask[nTG]);
+    }
+}
diff --git a/src/minidexed.h b/src/minidexed.h
index 6a7ef81..695a6ea 100644
--- a/src/minidexed.h
+++ b/src/minidexed.h
@@ -2,7 +2,7 @@
 // minidexed.h
 //
 // MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi
-// Copyright (C) 2022  The MiniDexed Team
+// Copyright (C) 2022-25  The MiniDexed Team
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -229,6 +229,8 @@ public:
 
 	void setMasterVolume (float32_t vol);
 
+	void setOperatorMask(uint8_t operatorMask, unsigned nTG); // Set operators enabled/disabled from bitmask
+
 private:
 	int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG);	// returns < 0 to ignore note
 	uint8_t m_uchOPMask[CConfig::AllToneGenerators];