diff --git a/src/minidexed.cpp b/src/minidexed.cpp
index 066ce05..4279444 100644
--- a/src/minidexed.cpp
+++ b/src/minidexed.cpp
@@ -57,6 +57,10 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
 		m_nVoiceBankID[i] = 0;
 		m_nPan[i] = 64;
 
+		m_nNoteLimitLow[i] = 0;
+		m_nNoteLimitHigh[i] = 127;
+		m_nNoteShift[i] = 0;
+
 		m_pTG[i] = new CDexedAdapter (CConfig::MaxNotes, pConfig->GetSampleRate ());
 		assert (m_pTG[i]);
 
@@ -148,6 +152,10 @@ bool CMiniDexed::Initialize (void)
 			SetVolume (m_PerformanceConfig.GetVolume (nTG), nTG);
 			SetPan (m_PerformanceConfig.GetPan (nTG), nTG);
 			SetMasterTune (m_PerformanceConfig.GetDetune (nTG), nTG);
+
+			m_nNoteLimitLow[nTG] = m_PerformanceConfig.GetNoteLimitLow (nTG);
+			m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG);
+			m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG);
 		}
 	}
 	else
@@ -386,14 +394,45 @@ void CMiniDexed::keyup (int16_t pitch, unsigned nTG)
 {
 	assert (nTG < CConfig::ToneGenerators);
 	assert (m_pTG[nTG]);
-	m_pTG[nTG]->keyup (pitch);
+
+	pitch = ApplyNoteLimits (pitch, nTG);
+	if (pitch >= 0)
+	{
+		m_pTG[nTG]->keyup (pitch);
+	}
 }
 
 void CMiniDexed::keydown (int16_t pitch, uint8_t velocity, unsigned nTG)
 {
 	assert (nTG < CConfig::ToneGenerators);
 	assert (m_pTG[nTG]);
-	m_pTG[nTG]->keydown (pitch, velocity);
+
+	pitch = ApplyNoteLimits (pitch, nTG);
+	if (pitch >= 0)
+	{
+		m_pTG[nTG]->keydown (pitch, velocity);
+	}
+}
+
+int16_t CMiniDexed::ApplyNoteLimits (int16_t pitch, unsigned nTG)
+{
+	assert (nTG < CConfig::ToneGenerators);
+
+	if (   pitch < (int16_t) m_nNoteLimitLow[nTG]
+	    || pitch > (int16_t) m_nNoteLimitHigh[nTG])
+	{
+		return -1;
+	}
+
+	pitch += m_nNoteShift[nTG];
+
+	if (   pitch < 0
+	    || pitch > 127)
+	{
+		return -1;
+	}
+
+	return pitch;
 }
 
 void CMiniDexed::setSustain(bool sustain, unsigned nTG)
diff --git a/src/minidexed.h b/src/minidexed.h
index d0f31de..7632544 100644
--- a/src/minidexed.h
+++ b/src/minidexed.h
@@ -76,6 +76,8 @@ public:
 	std::string GetVoiceName (unsigned nTG);
 
 private:
+	int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG);	// returns < 0 to ignore note
+
 	void ProcessSound (void);
 
 #ifdef ARM_ALLOW_MULTI_CORE
@@ -96,6 +98,10 @@ private:
 	unsigned m_nVoiceBankID[CConfig::ToneGenerators];
 	unsigned m_nPan[CConfig::ToneGenerators];
 
+	unsigned m_nNoteLimitLow[CConfig::ToneGenerators];
+	unsigned m_nNoteLimitHigh[CConfig::ToneGenerators];
+	int m_nNoteShift[CConfig::ToneGenerators];
+
 	CUserInterface m_UI;
 	CSysExFileLoader m_SysExFileLoader;
 	CPerformanceConfig m_PerformanceConfig;
diff --git a/src/performance.ini b/src/performance.ini
index 2e37a34..4b9fb0e 100644
--- a/src/performance.ini
+++ b/src/performance.ini
@@ -9,6 +9,9 @@
 #Volume#=100		# 0 .. 127
 #Pan#=64		# 0 .. 127
 #Detune#=0		# -99 .. 99
+#NoteLimitLow#=0	# 0 .. 127, C-2 .. G8
+#NoteLimitHigh#=127	# 0 .. 127, C-2 .. G8
+#NoteShift#=0		# -24 .. 24
 
 # TG1
 BankNumber1=0
@@ -17,6 +20,9 @@ MIDIChannel1=255
 Volume1=100
 Pan1=32
 Detune1=-11
+NoteLimitLow1=0
+NoteLimitHigh1=127
+NoteShift1=0
 
 # TG2
 BankNumber2=0
@@ -25,6 +31,9 @@ MIDIChannel2=255
 Volume2=100
 Pan2=96
 Detune2=11
+NoteLimitLow2=0
+NoteLimitHigh2=127
+NoteShift2=0
 
 # TG3
 BankNumber3=0
@@ -33,6 +42,9 @@ MIDIChannel3=255
 Volume3=100
 Pan3=48
 Detune3=-7
+NoteLimitLow3=0
+NoteLimitHigh3=127
+NoteShift3=0
 
 # TG4
 BankNumber4=0
@@ -41,6 +53,9 @@ MIDIChannel4=255
 Volume4=100
 Pan4=80
 Detune4=7
+NoteLimitLow4=0
+NoteLimitHigh4=127
+NoteShift4=0
 
 # TG5
 BankNumber5=0
@@ -49,6 +64,9 @@ MIDIChannel5=0
 Volume5=100
 Pan5=64
 Detune5=0
+NoteLimitLow5=0
+NoteLimitHigh5=127
+NoteShift5=0
 
 # TG6
 BankNumber6=0
@@ -57,6 +75,9 @@ MIDIChannel6=0
 Volume6=100
 Pan6=64
 Detune6=0
+NoteLimitLow6=0
+NoteLimitHigh6=127
+NoteShift6=0
 
 # TG7
 BankNumber7=0
@@ -65,6 +86,9 @@ MIDIChannel7=0
 Volume7=100
 Pan7=64
 Detune7=0
+NoteLimitLow7=0
+NoteLimitHigh7=127
+NoteShift7=0
 
 # TG8
 BankNumber8=0
@@ -73,3 +97,6 @@ MIDIChannel8=0
 Volume8=100
 Pan8=64
 Detune8=0
+NoteLimitLow8=0
+NoteLimitHigh8=127
+NoteShift8=0
diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp
index 4d35398..f03443a 100644
--- a/src/performanceconfig.cpp
+++ b/src/performanceconfig.cpp
@@ -80,6 +80,15 @@ bool CPerformanceConfig::Load (void)
 
 		PropertyName.Format ("Detune%u", nTG+1);
 		m_nDetune[nTG] = m_Properties.GetSignedNumber (PropertyName, 0);
+
+		PropertyName.Format ("NoteLimitLow%u", nTG+1);
+		m_nNoteLimitLow[nTG] = m_Properties.GetNumber (PropertyName, 0);
+
+		PropertyName.Format ("NoteLimitHigh%u", nTG+1);
+		m_nNoteLimitHigh[nTG] = m_Properties.GetNumber (PropertyName, 127);
+
+		PropertyName.Format ("NoteShift%u", nTG+1);
+		m_nNoteShift[nTG] = m_Properties.GetSignedNumber (PropertyName, 0);
 	}
 
 	return bResult;
@@ -120,3 +129,21 @@ int CPerformanceConfig::GetDetune (unsigned nTG) const
 	assert (nTG < CConfig::ToneGenerators);
 	return m_nDetune[nTG];
 }
+
+unsigned CPerformanceConfig::GetNoteLimitLow (unsigned nTG) const
+{
+	assert (nTG < CConfig::ToneGenerators);
+	return m_nNoteLimitLow[nTG];
+}
+
+unsigned CPerformanceConfig::GetNoteLimitHigh (unsigned nTG) const
+{
+	assert (nTG < CConfig::ToneGenerators);
+	return m_nNoteLimitHigh[nTG];
+}
+
+int CPerformanceConfig::GetNoteShift (unsigned nTG) const
+{
+	assert (nTG < CConfig::ToneGenerators);
+	return m_nNoteShift[nTG];
+}
diff --git a/src/performanceconfig.h b/src/performanceconfig.h
index b6ebb78..41b0649 100644
--- a/src/performanceconfig.h
+++ b/src/performanceconfig.h
@@ -42,6 +42,9 @@ public:
 	unsigned GetVolume (unsigned nTG) const;		// 0 .. 127
 	unsigned GetPan (unsigned nTG) const;			// 0 .. 127
 	int GetDetune (unsigned nTG) const;			// -99 .. 99
+	unsigned GetNoteLimitLow (unsigned nTG) const;		// 0 .. 127
+	unsigned GetNoteLimitHigh (unsigned nTG) const;		// 0 .. 127
+	int GetNoteShift (unsigned nTG) const;			// -24 .. 24
 
 private:
 	CPropertiesFatFsFile m_Properties;
@@ -52,6 +55,9 @@ private:
 	unsigned m_nVolume[CConfig::ToneGenerators];
 	unsigned m_nPan[CConfig::ToneGenerators];
 	int m_nDetune[CConfig::ToneGenerators];
+	unsigned m_nNoteLimitLow[CConfig::ToneGenerators];
+	unsigned m_nNoteLimitHigh[CConfig::ToneGenerators];
+	int m_nNoteShift[CConfig::ToneGenerators];
 };
 
 #endif