shithub: pt2-clone

Download patch

ref: 63402619f6de96adeb1a45dff7a558d745448a1c
parent: 118366b1d4c94e68bc8a6e4f10bf543bdd321e0d
author: Olav Sørensen <[email protected]>
date: Mon Jan 6 14:51:15 EST 2020

Pushed v1.02 code

- The paulaSetLength() function now takes length in words, not bytes.
  This doesn't really change anything, but it's more correct.
- Fixed a very minor bug with VOL up/down button in Edit Op.
- Fixed a bug where the scopes could show the wrong volume for the
  tunetone waveform (sampler screen).
- Some code cleanup

--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,4 @@
 .DS_Store
 vs2019_project/pt2-clone/Release/pt2-clone.vcxproj.FileListAbsolute.txt
 vs2019_project/pt2-clone/x64/Debug/pt2-clone.vcxproj.FileListAbsolute.txt
+*.opendb
--- a/src/pt2_audio.c
+++ b/src/pt2_audio.c
@@ -276,7 +276,7 @@
 		{
 			s = &modEntry->samples[editor.currSample];
 			paulaSetData(i, ch->n_start + s->loopStart);
-			paulaSetLength(i, s->loopLength);
+			paulaSetLength(i, s->loopLength / 2);
 		}
 	}
 }
@@ -349,7 +349,7 @@
 
 	length = v->newLength;
 	if (length < 2)
-		length = 2;
+		length = 2; // for safety
 
 	v->dPhase = 0.0;
 	v->pos = 0;
@@ -397,15 +397,15 @@
 
 	if (period == 0)
 	{
-		v->dDelta = 0.0;
+		v->dDelta = 0.0; // confirmed behavior on real Amiga
 		setScopeDelta(ch, 0);
 		return;
 	}
 
-	// confirmed behavior on real Amiga
 	if (period < 113)
-		period = 113;
+		period = 113; // confirmed behavior on real Amiga
 
+	// if the new period was the same as the previous period, use cached deltas
 	if (period == oldPeriod)
 	{
 		v->dDelta = oldVoiceDelta;
@@ -415,6 +415,7 @@
 	{
 		oldPeriod = period;
 
+		// if we are rendering pattern to sample (PAT2SMP), use different frequencies
 		if (editor.isSMPRendering)
 			dPeriodToDeltaDiv = editor.pat2SmpHQ ? (PAULA_PAL_CLK / 28836.0) : (PAULA_PAL_CLK / 22168.0);
 		else
@@ -424,9 +425,8 @@
 		oldVoiceDelta = v->dDelta;
 
 		// set scope rate
-
 #if SCOPE_HZ != 64
-#error Scope Hz is not 64 (2^n), change rate calc. to use doubles+round in pt_scope.c
+#error Scope Hz is not 64 (2^n), change rate calc. to use doubles+round in pt2_scope.c
 #endif
 		oldScopeDelta = (PAULA_PAL_CLK * (65536UL / SCOPE_HZ)) / period;
 		setScopeDelta(ch, oldScopeDelta);
@@ -439,20 +439,25 @@
 
 void paulaSetVolume(uint8_t ch, uint16_t vol)
 {
-	vol &= 127;
+	vol &= 127; // confirmed behavior on real Amiga
+
 	if (vol > 64)
-		vol = 64;
+		vol = 64; // confirmed behavior on real Amiga
 
 	paula[ch].dVolume = vol * (1.0 / 64.0);
 }
 
-// our Paula simulation takes sample lengths in bytes instead of words
-void paulaSetLength(uint8_t ch, uint32_t len)
+void paulaSetLength(uint8_t ch, uint16_t len)
 {
-	if (len < 2)
-		len = 2; // needed safety for mixer and scopes
+	if (len == 0)
+	{
+		len = 65535;
+		/* confirmed behavior on real Amiga (also needed for safety)
+		 * And yes, we have room for this, it will never overflow! */
+	}
 
-	scopeExt[ch].newLength = paula[ch].newLength = len;
+	// our mixer works with bytes, not words. Multiply by two
+	scopeExt[ch].newLength = paula[ch].newLength = len * 2;
 }
 
 void paulaSetData(uint8_t ch, const int8_t *src)
--- a/src/pt2_audio.h
+++ b/src/pt2_audio.h
@@ -29,7 +29,7 @@
 void paulaStartDMA(uint8_t ch);
 void paulaSetPeriod(uint8_t ch, uint16_t period);
 void paulaSetVolume(uint8_t ch, uint16_t vol);
-void paulaSetLength(uint8_t ch, uint32_t len);
+void paulaSetLength(uint8_t ch, uint16_t len);
 void paulaSetData(uint8_t ch, const int8_t *src);
 void lockAudio(void);
 void unlockAudio(void);
--- a/src/pt2_edit.c
+++ b/src/pt2_edit.c
@@ -691,7 +691,7 @@
 		if (handleSpecialKeys(scancode))
 		{
 			if (editor.currMode != MODE_RECORD)
-				modSetPos(DONT_SET_ORDER, (modEntry->currRow + editor.editMoveAdd) & 63);
+				modSetPos(DONT_SET_ORDER, (modEntry->currRow + editor.editMoveAdd) & 0x3F);
 
 			return;
 		}
@@ -830,11 +830,11 @@
 				if (input.keyb.shiftPressed || input.keyb.leftAltPressed)
 				{
 					note->command = 0;
-					note->param   = 0;
+					note->param = 0;
 				}
 
 				if (editor.currMode != MODE_RECORD)
-					modSetPos(DONT_SET_ORDER, (modEntry->currRow + editor.editMoveAdd) & 63);
+					modSetPos(DONT_SET_ORDER, (modEntry->currRow + editor.editMoveAdd) & 0x3F);
 
 				updateWindowTitle(MOD_IS_MODIFIED);
 			}
@@ -854,51 +854,51 @@
 {
 	note_t *patt, *note, *prevNote;
 
-	if (input.keyb.leftAltPressed)
-	{
-		patt = modEntry->patterns[modEntry->currPattern];
-		note = &patt[(modEntry->currRow * AMIGA_VOICES) + editor.cursor.channel];
-		prevNote = &patt[(((modEntry->currRow - 1) & 0x3F) * AMIGA_VOICES) + editor.cursor.channel];
+	if (!input.keyb.leftAltPressed)
+		return false;
 
-		if (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0)
-		{
-			// insert stored effect (buffer[0..8])
-			note->command = editor.effectMacros[scancode - SDL_SCANCODE_1] >> 8;
-			note->param = editor.effectMacros[scancode - SDL_SCANCODE_1] & 0xFF;
+	patt = modEntry->patterns[modEntry->currPattern];
+	note = &patt[(modEntry->currRow * AMIGA_VOICES) + editor.cursor.channel];
+	prevNote = &patt[(((modEntry->currRow - 1) & 0x3F) * AMIGA_VOICES) + editor.cursor.channel];
 
-			updateWindowTitle(MOD_IS_MODIFIED);
-			return true;
-		}
+	if (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0)
+	{
+		// insert stored effect (buffer[0..8])
+		note->command = editor.effectMacros[scancode - SDL_SCANCODE_1] >> 8;
+		note->param = editor.effectMacros[scancode - SDL_SCANCODE_1] & 0xFF;
 
-		// copy command+effect from above into current command+effect
-		if (scancode == SDL_SCANCODE_BACKSLASH)
-		{
-			note->command = prevNote->command;
-			note->param   = prevNote->param;
+		updateWindowTitle(MOD_IS_MODIFIED);
+		return true;
+	}
 
-			updateWindowTitle(MOD_IS_MODIFIED);
-			return true;
-		}
+	// copy command+effect from above into current command+effect
+	if (scancode == SDL_SCANCODE_BACKSLASH)
+	{
+		note->command = prevNote->command;
+		note->param = prevNote->param;
 
-		// copy command+(effect + 1) from above into current command+effect
-		if (scancode == SDL_SCANCODE_EQUALS)
-		{
-			note->command = prevNote->command;
-			note->param = prevNote->param + 1; // wraps 0x00..0xFF
+		updateWindowTitle(MOD_IS_MODIFIED);
+		return true;
+	}
 
-			updateWindowTitle(MOD_IS_MODIFIED);
-			return true;
-		}
+	// copy command+(effect + 1) from above into current command+effect
+	if (scancode == SDL_SCANCODE_EQUALS)
+	{
+		note->command = prevNote->command;
+		note->param = prevNote->param + 1; // wraps 0x00..0xFF
 
-		// copy command+(effect - 1) from above into current command+effect
-		if (scancode == SDL_SCANCODE_MINUS)
-		{
-			note->command = prevNote->command;
-			note->param = prevNote->param - 1; // wraps 0x00..0xFF
+		updateWindowTitle(MOD_IS_MODIFIED);
+		return true;
+	}
 
-			updateWindowTitle(MOD_IS_MODIFIED);
-			return true;
-		}
+	// copy command+(effect - 1) from above into current command+effect
+	if (scancode == SDL_SCANCODE_MINUS)
+	{
+		note->command = prevNote->command;
+		note->param = prevNote->param - 1; // wraps 0x00..0xFF
+
+		updateWindowTitle(MOD_IS_MODIFIED);
+		return true;
 	}
 
 	return false;
@@ -939,12 +939,12 @@
 			chn->n_volume = s->volume;
 			chn->n_period = tempPeriod;
 			chn->n_start = &modEntry->sampleData[s->offset];
-			chn->n_length = (s->loopStart > 0) ? (s->loopStart + s->loopLength) : s->length;
+			chn->n_length = (s->loopStart > 0) ? (uint32_t)(s->loopStart + s->loopLength) / 2 : s->length / 2;
 			chn->n_loopstart = &modEntry->sampleData[s->offset + s->loopStart];
-			chn->n_replen = s->loopLength;
+			chn->n_replen = s->loopLength / 2;
 
-			if (chn->n_length < 2)
-				chn->n_length = 2;
+			if (chn->n_length == 0)
+				chn->n_length = 1;
 
 			paulaSetVolume(ch, chn->n_volume);
 			paulaSetPeriod(ch, chn->n_period);
@@ -995,7 +995,7 @@
 	{
 		// delete note and sample if illegal note (= -2, -1 = ignore) key was entered
 
-		if (normalMode || (!normalMode && editor.pNoteFlag == 2))
+		if (normalMode || editor.pNoteFlag == 2)
 		{
 			if (!editor.ui.samplerScreenShown && (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD))
 			{
--- a/src/pt2_header.h
+++ b/src/pt2_header.h
@@ -13,7 +13,7 @@
 #include <stdint.h>
 #include "pt2_unicode.h"
 
-#define PROG_VER_STR "1.01"
+#define PROG_VER_STR "1.02"
 
 #ifdef _WIN32
 #define DIR_DELIMITER '\\'
--- a/src/pt2_keyboard.c
+++ b/src/pt2_keyboard.c
@@ -489,11 +489,8 @@
 		{
 			if (input.keyb.leftAltPressed)
 			{
-				if (handleSpecialKeys(scancode))
-				{
-					if (editor.currMode != MODE_RECORD)
-						modSetPos(DONT_SET_ORDER, (modEntry->currRow + editor.editMoveAdd) & 63);
-				}
+				if (handleSpecialKeys(scancode) && editor.currMode != MODE_RECORD)
+					modSetPos(DONT_SET_ORDER, (modEntry->currRow + editor.editMoveAdd) & 0x3F);
 			}
 			else
 			{
@@ -591,7 +588,7 @@
 			else
 			{
 				editor.ui.askScreenShown = true;
-				editor.ui.askScreenType  = ASK_QUIT;
+				editor.ui.askScreenType = ASK_QUIT;
 
 				pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
 				setStatusMessage("REALLY QUIT ?", NO_CARRY);
@@ -638,9 +635,12 @@
 			{
 				if (editor.currMode == MODE_IDLE || editor.currMode == MODE_EDIT)
 				{
-					     if (modEntry->currRow == 63) modSetPos(DONT_SET_ORDER, modEntry->currRow - 15);
-					else if (modEntry->currRow == 15) modSetPos(DONT_SET_ORDER, 0); // 15-16 would turn into -1, which is "DON'T SET ROW" flag
-					else modSetPos(DONT_SET_ORDER, modEntry->currRow - 16);
+					if (modEntry->currRow == 63)
+						modSetPos(DONT_SET_ORDER, modEntry->currRow - 15);
+					else if (modEntry->currRow == 15)
+						modSetPos(DONT_SET_ORDER, 0); // 15-16 would turn into -1, which is "DON'T SET ROW" flag
+					else
+						modSetPos(DONT_SET_ORDER, modEntry->currRow - 16);
 				}
 			}
 
@@ -668,7 +668,7 @@
 			{
 				if (editor.diskop.numEntries > DISKOP_LINES)
 				{
-					editor.diskop.scrollOffset += DISKOP_LINES - 1;
+					editor.diskop.scrollOffset += DISKOP_LINES-1;
 					if (editor.diskop.scrollOffset > editor.diskop.numEntries-DISKOP_LINES)
 						editor.diskop.scrollOffset = editor.diskop.numEntries-DISKOP_LINES;
 
@@ -1040,7 +1040,6 @@
 					for (i = 0; i < MOD_ROWS; i++)
 					{
 						noteDst = &modEntry->patterns[modEntry->currPattern][(i * AMIGA_VOICES) + editor.cursor.channel];
-
 						noteDst->command = noteSrc->command;
 						noteDst->param = noteSrc->param;
 
@@ -1888,8 +1887,7 @@
 				if (editor.diskop.numEntries > DISKOP_LINES)
 				{
 					editor.diskop.scrollOffset++;
-
-					if (input.mouse.rightButtonPressed) // PT quirk: right mouse button speeds up even on keyb UP/DOWN
+					if (input.mouse.rightButtonPressed) // PT quirk: right mouse button speeds up scrolling even on keyb UP/DOWN
 						editor.diskop.scrollOffset += 3;
 
 					if (editor.diskop.scrollOffset > editor.diskop.numEntries-DISKOP_LINES)
@@ -1939,8 +1937,7 @@
 			if (editor.ui.diskOpScreenShown)
 			{
 				editor.diskop.scrollOffset--;
-
-				if (input.mouse.rightButtonPressed) // PT quirk: right mouse button speeds up even on keyb UP/DOWN
+				if (input.mouse.rightButtonPressed) // PT quirk: right mouse button speeds up scrolling even on keyb UP/DOWN
 					editor.diskop.scrollOffset -= 3;
 
 				if (editor.diskop.scrollOffset < 0)
@@ -2128,7 +2125,6 @@
 			else if (input.keyb.leftAltPressed)
 			{
 				s = &modEntry->samples[editor.currSample];
-
 				if (s->length == 0)
 				{
 					displayErrorMsg("SAMPLE IS EMPTY");
@@ -2167,7 +2163,7 @@
 					return;
 				}
 
-				editor.blockMarkFlag   = false;
+				editor.blockMarkFlag = false;
 				editor.blockBufferFlag = true;
 
 				for (i = 0; i < MOD_ROWS; i++)
@@ -2224,7 +2220,6 @@
 						{
 							pointerSetPreviousMode();
 							setPrevStatusMessage();
-
 							displayMainScreen();
 						}
 						else
@@ -2495,7 +2490,6 @@
 				for (i = 0; i < MOD_ROWS; i++)
 				{
 					noteSrc = &modEntry->patterns[modEntry->currPattern][(i * AMIGA_VOICES) + editor.cursor.channel];
-
 					if (noteSrc->sample == editor.currSample+1)
 					{
 						noteSrc->period = 0;
@@ -2519,7 +2513,6 @@
 					while (i >= 0)
 					{
 						noteDst = &modEntry->patterns[modEntry->currPattern][(i * AMIGA_VOICES) + editor.cursor.channel];
-
 						noteDst->period = 0;
 						noteDst->sample = 0;
 						noteDst->command = 0;
@@ -2534,7 +2527,6 @@
 					while (i < MOD_ROWS)
 					{
 						noteDst = &modEntry->patterns[modEntry->currPattern][(i * AMIGA_VOICES) + editor.cursor.channel];
-
 						noteDst->period = 0;
 						noteDst->sample = 0;
 						noteDst->command = 0;
@@ -2869,7 +2861,6 @@
 			else if (input.keyb.leftCtrlPressed)
 			{
 				// Polyphonize Block
-
 				if (!editor.blockBufferFlag)
 				{
 					displayErrorMsg("BUFFER IS EMPTY !");
@@ -2884,7 +2875,6 @@
 				while (true)
 				{
 					noteDst = &patt[(j * AMIGA_VOICES) + editor.cursor.channel];
-
 					if (editor.blockBuffer[i].period == 0 && editor.blockBuffer[i].sample == 0)
 					{
 						noteDst->command = editor.blockBuffer[i].command;
@@ -2961,7 +2951,6 @@
 				for (i = editor.buffFromPos; i <= editor.buffToPos; i++)
 				{
 					noteDst = &modEntry->patterns[modEntry->currPattern][(i * AMIGA_VOICES) + editor.cursor.channel];
-
 					noteDst->period = 0;
 					noteDst->sample = 0;
 					noteDst->command = 0;
@@ -3069,7 +3058,6 @@
 					for (i = 0; i < AMIGA_VOICES; i++)
 					{
 						ch = &modEntry->channels[i];
-
 						ch->n_wavecontrol = 0;
 						ch->n_glissfunk = 0;
 						ch->n_finetune = 0;
@@ -3101,7 +3089,7 @@
 {
 	int8_t pos = ((editor.cursor.pos + 5) / 6) - 1;
 
-	editor.cursor.pos  = (pos < 0) ? (3 * 6) : (pos * 6);
+	editor.cursor.pos = (pos < 0) ? (3 * 6) : (pos * 6);
 	editor.cursor.mode = CURSOR_NOTE;
 
 	     if (editor.cursor.pos <  6) editor.cursor.channel = 0;
@@ -3170,7 +3158,7 @@
 		return;
 	}
 
-	switch (scancode) // only some buttons repeat
+	switch (scancode) // only some buttons have repeat
 	{
 		case SDL_SCANCODE_PAGEUP:
 		{
@@ -3189,7 +3177,7 @@
 				{
 					if (editor.ui.diskOpScreenShown)
 					{
-						editor.diskop.scrollOffset -= DISKOP_LINES - 1;
+						editor.diskop.scrollOffset -= DISKOP_LINES-1;
 						if (editor.diskop.scrollOffset < 0)
 							editor.diskop.scrollOffset = 0;
 
@@ -3196,14 +3184,14 @@
 						editor.ui.updateDiskOpFileList = true;
 					}
 				}
-				else
+				else if (editor.currMode == MODE_IDLE || editor.currMode == MODE_EDIT)
 				{
-					if ((editor.currMode == MODE_IDLE) || (editor.currMode == MODE_EDIT))
-					{
-						     if (modEntry->currRow == 63) modSetPos(DONT_SET_ORDER, modEntry->currRow - 15);
-						else if (modEntry->currRow == 15) modSetPos(DONT_SET_ORDER, 0); // 15-16 would turn into -1, which is "DON'T SET ROW" flag
-						else modSetPos(DONT_SET_ORDER, modEntry->currRow - 16);
-					}
+					if (modEntry->currRow == 63)
+						modSetPos(DONT_SET_ORDER, modEntry->currRow - 15);
+					else if (modEntry->currRow == 15)
+						modSetPos(DONT_SET_ORDER, 0); // 15-16 would turn into -1, which is "DON'T SET ROW" flag
+					else
+						modSetPos(DONT_SET_ORDER, modEntry->currRow - 16);
 				}
 			}
 		}
@@ -3226,7 +3214,7 @@
 				{
 					if (editor.diskop.numEntries > DISKOP_LINES)
 					{
-						editor.diskop.scrollOffset += DISKOP_LINES - 1;
+						editor.diskop.scrollOffset += DISKOP_LINES-1;
 						if (editor.diskop.scrollOffset > editor.diskop.numEntries-DISKOP_LINES)
 							editor.diskop.scrollOffset = editor.diskop.numEntries-DISKOP_LINES;
 
@@ -3233,10 +3221,9 @@
 						editor.ui.updateDiskOpFileList = true;
 					}
 				}
-				else
+				else if (editor.currMode == MODE_IDLE || editor.currMode == MODE_EDIT)
 				{
-					if (editor.currMode == MODE_IDLE || editor.currMode == MODE_EDIT)
-						modSetPos(DONT_SET_ORDER, modEntry->currRow + 16);
+					modSetPos(DONT_SET_ORDER, modEntry->currRow + 16);
 				}
 			}
 		}
@@ -3351,7 +3338,7 @@
 					input.keyb.repeatCounter = 0;
 
 					editor.diskop.scrollOffset--;
-					if (input.mouse.rightButtonPressed) // PT quirk: right mouse button speeds up even on keyb UP/DOWN
+					if (input.mouse.rightButtonPressed) // PT quirk: right mouse button speeds up scrolling even on keyb UP/DOWN
 						editor.diskop.scrollOffset -= 3;
 
 					if (editor.diskop.scrollOffset < 0)
@@ -3377,10 +3364,11 @@
 				if (editor.currMode != MODE_PLAY && editor.currMode != MODE_RECORD)
 				{
 					repeatNum = 6;
+					if (input.keyb.leftAltPressed)
+						repeatNum = 1;
+					else if (input.keyb.shiftPressed)
+						repeatNum = 3;
 
-					     if (input.keyb.leftAltPressed) repeatNum = 1;
-					else if (input.keyb.shiftPressed)repeatNum = 3;
-
 					if (input.keyb.repeatCounter >= repeatNum)
 					{
 						input.keyb.repeatCounter = 0;
@@ -3402,8 +3390,7 @@
 					if (editor.diskop.numEntries > DISKOP_LINES)
 					{
 						editor.diskop.scrollOffset++;
-
-						if (input.mouse.rightButtonPressed) // PT quirk: right mouse button speeds up even on keyb UP/DOWN
+						if (input.mouse.rightButtonPressed) // PT quirk: right mouse button speeds up scrolling even on keyb UP/DOWN
 							editor.diskop.scrollOffset += 3;
 
 						if (editor.diskop.scrollOffset > editor.diskop.numEntries-DISKOP_LINES)
@@ -3431,13 +3418,14 @@
 			}
 			else if (!editor.ui.samplerScreenShown)
 			{
-				if ((editor.currMode != MODE_PLAY) && (editor.currMode != MODE_RECORD))
+				if (editor.currMode != MODE_PLAY && editor.currMode != MODE_RECORD)
 				{
 					repeatNum = 6;
+					if (input.keyb.leftAltPressed)
+						repeatNum = 1;
+					else if (input.keyb.shiftPressed)
+						repeatNum = 3;
 
-					     if (input.keyb.leftAltPressed) repeatNum = 1;
-					else if (input.keyb.shiftPressed) repeatNum = 3;
-
 					if (input.keyb.repeatCounter >= repeatNum)
 					{
 						input.keyb.repeatCounter = 0;
@@ -3531,8 +3519,10 @@
 			return false;
 		}
 
-		     if (scancode == SDL_SCANCODE_F1) editor.keyOctave = OCTAVE_LOW;
-		else if (scancode == SDL_SCANCODE_F2) editor.keyOctave = OCTAVE_HIGH;
+		if (scancode == SDL_SCANCODE_F1)
+			editor.keyOctave = OCTAVE_LOW;
+		else if (scancode == SDL_SCANCODE_F2)
+			editor.keyOctave = OCTAVE_HIGH;
 
 		rawKey = keyToNote(scancode);
 		if (rawKey >= 0)
@@ -3579,8 +3569,10 @@
 			return false;
 		}
 
-		     if (scancode == SDL_SCANCODE_F1) editor.keyOctave = OCTAVE_LOW;
-		else if (scancode == SDL_SCANCODE_F2) editor.keyOctave = OCTAVE_HIGH;
+		if (scancode == SDL_SCANCODE_F1)
+			editor.keyOctave = OCTAVE_LOW;
+		else if (scancode == SDL_SCANCODE_F2)
+			editor.keyOctave = OCTAVE_HIGH;
 
 		rawKey = keyToNote(scancode);
 		if (rawKey >= 0)
@@ -3606,8 +3598,10 @@
 			return false;
 		}
 
-		     if (scancode == SDL_SCANCODE_F1) editor.keyOctave = OCTAVE_LOW;
-		else if (scancode == SDL_SCANCODE_F2) editor.keyOctave = OCTAVE_HIGH;
+		if (scancode == SDL_SCANCODE_F1)
+			editor.keyOctave = OCTAVE_LOW;
+		else if (scancode == SDL_SCANCODE_F2)
+			editor.keyOctave = OCTAVE_HIGH;
 
 		rawKey = keyToNote(scancode);
 		if (rawKey >= 0)
@@ -3798,7 +3792,6 @@
 					editor.ui.askScreenShown = false;
 					editor.ui.answerNo = false;
 					editor.ui.answerYes = true;
-
 					editor.pat2SmpHQ = false;
 					handleAskYes();
 					// pointer/status is updated by the 'yes handler'
@@ -3967,33 +3960,30 @@
 
 				textMarkerMoveRight();
 			}
-			else
+			else if ((textChar >= '0' && textChar <= '9') || (textChar >= 'A' && textChar <= 'F'))
 			{
-				if ((textChar >= '0' && textChar <= '9') || (textChar >= 'A' && textChar <= 'F'))
+				if (editor.ui.dstPos == 14) // hack for sample mix text
 				{
-					if (editor.ui.dstPos == 14) // hack for sample mix text
-					{
-						*editor.ui.editPos = textChar;
-					}
-					else
-					{
-						*editor.ui.editPos++ = textChar;
-						textMarkerMoveRight();
+					*editor.ui.editPos = textChar;
+				}
+				else
+				{
+					*editor.ui.editPos++ = textChar;
+					textMarkerMoveRight();
 
-						if (editor.ui.dstPos == 9) // hack for sample mix text
+					if (editor.ui.dstPos == 9) // hack for sample mix text
+					{
+						for (i = 0; i < 4; i++)
 						{
-							for (i = 0; i < 4; i++)
-							{
-								editor.ui.editPos++;
-								textMarkerMoveRight();
-							}
-						}
-						else if (editor.ui.dstPos == 6) // hack for sample mix text
-						{
 							editor.ui.editPos++;
 							textMarkerMoveRight();
 						}
 					}
+					else if (editor.ui.dstPos == 6) // hack for sample mix text
+					{
+						editor.ui.editPos++;
+						textMarkerMoveRight();
+					}
 				}
 			}
 		}
@@ -4049,8 +4039,10 @@
 		{
 			if ((textChar >= '0' && textChar <= '9') || (textChar >= 'A' && textChar <= 'F'))
 			{
-				     if (textChar <= '9') textChar -= '0';
-				else if (textChar <= 'F') textChar -= ('A' - 10);
+				if (textChar <= '9')
+					textChar -= '0';
+				else if (textChar <= 'F')
+					textChar -= 'A'-10;
 
 				if (editor.ui.numBits == 16)
 				{
@@ -4127,7 +4119,6 @@
 			if (editor.ui.editTextFlag)
 			{
 				textCharPrevious();
-
 				if (!input.keyb.repeatKey)
 					input.keyb.delayCounter = 0;
 
@@ -4147,7 +4138,6 @@
 			if (editor.ui.editTextFlag)
 			{
 				textCharNext();
-
 				if (!input.keyb.repeatKey)
 					input.keyb.delayCounter = 0;
 
@@ -4184,7 +4174,7 @@
 					input.keyb.delayCounter = 0;
 
 				input.keyb.repeatKey = true;
-				input.keyb.delayKey  = false;
+				input.keyb.delayKey = false;
 
 				updateTextObject(editor.ui.editObject);
 			}
@@ -4209,7 +4199,7 @@
 						*readTmp++ = readTmpNext;
 					}
 
-					// hack to prevent cloning last character if the song/sample name has one character too much
+					// kludge to prevent cloning last character if the song/sample name has one character too much
 					if (editor.ui.editObject == PTB_SONGNAME || editor.ui.editObject == PTB_SAMPLENAME)
 						*editor.ui.textEndPtr = '\0';
 
--- a/src/pt2_modloader.c
+++ b/src/pt2_modloader.c
@@ -687,7 +687,7 @@
 	for (i = 0; i < MOD_SAMPLES; i++)
 		newModule->samples[i].offset = MAX_SAMPLE_LEN * i;
 
-	newModule->sampleData = (int8_t *)calloc(MOD_SAMPLES + 1, MAX_SAMPLE_LEN); // +1 sample slot for overflow safety (scopes etc)
+	newModule->sampleData = (int8_t *)calloc(MOD_SAMPLES + 2, MAX_SAMPLE_LEN); // +2 sample slots for overflow safety (Paula and scopes)
 	if (newModule->sampleData == NULL)
 	{
 		statusOutOfMemory();
@@ -1359,7 +1359,7 @@
 			goto oom;
 	}
 
-	newMod->sampleData = (int8_t *)calloc(MOD_SAMPLES + 1, MAX_SAMPLE_LEN); // +1 sample slot for overflow safety (scopes etc)
+	newMod->sampleData = (int8_t *)calloc(MOD_SAMPLES + 2, MAX_SAMPLE_LEN); // +2 sample slots for overflow safety (Paula and scopes)
 	if (newMod->sampleData == NULL)
 		goto oom;
 
--- a/src/pt2_modplayer.c
+++ b/src/pt2_modplayer.c
@@ -634,16 +634,16 @@
 	if ((ch->n_cmd & 0xFF) > 0)
 		ch->n_sampleoffset = ch->n_cmd & 0xFF;
 
-	newOffset = ch->n_sampleoffset << 8;
+	newOffset = ch->n_sampleoffset << 7;
 
-	if (newOffset < ch->n_length)
+	if ((int16_t)newOffset < (int16_t)ch->n_length)
 	{
 		ch->n_length -= newOffset;
-		ch->n_start += newOffset;
+		ch->n_start += newOffset*2;
 	}
 	else
 	{
-		ch->n_length = 2;
+		ch->n_length = 1;
 	}
 }
 
@@ -782,8 +782,8 @@
 		if (ch->n_start == NULL)
 		{
 			ch->n_loopstart = NULL;
-			paulaSetLength(ch->n_chanindex, 2);
-			ch->n_replen = 2;
+			paulaSetLength(ch->n_chanindex, 1);
+			ch->n_replen = 1;
 		}
 
 		paulaSetPeriod(ch->n_chanindex, ch->n_period);
@@ -830,7 +830,7 @@
 	ch->n_note = note.period;
 	ch->n_cmd = (note.command << 8) | note.param;
 
-	if ((note.sample >= 1) && (note.sample <= 31)) // SAFETY BUG FIX: don't handle sample-numbers >31
+	if (note.sample >= 1 && note.sample <= 31) // SAFETY BUG FIX: don't handle sample-numbers >31
 	{
 		ch->n_samplenum = note.sample - 1;
 		s = &modEntry->samples[ch->n_samplenum];
@@ -838,14 +838,14 @@
 		ch->n_start = &modEntry->sampleData[s->offset];
 		ch->n_finetune = s->fineTune;
 		ch->n_volume = s->volume;
-		ch->n_length = s->length;
-		ch->n_replen = s->loopLength;
+		ch->n_length = s->length / 2;
+		ch->n_replen = s->loopLength / 2;
 
 		if (s->loopStart > 0)
 		{
 			ch->n_loopstart = ch->n_start + s->loopStart;
 			ch->n_wavestart = ch->n_loopstart;
-			ch->n_length = s->loopStart + ch->n_replen;
+			ch->n_length = (s->loopStart / 2) + ch->n_replen;
 		}
 		else
 		{
--- a/src/pt2_mouse.c
+++ b/src/pt2_mouse.c
@@ -199,6 +199,7 @@
 					if (srcPix != PAL_COLORKEY)
 					{
 						uint32_t pixel = colorkey; // make compiler happy
+
 						     if (srcPix == PAL_MOUSE_1) pixel = color1;
 						else if (srcPix == PAL_MOUSE_2) pixel = color2;
 						else if (srcPix == PAL_MOUSE_3) pixel = color3;
@@ -348,7 +349,6 @@
 			case PTB_PATTERND:
 			{
 				editor.ui.updateSongSize = true;
-
 				if (editor.ui.posEdScreenShown)
 					editor.ui.updatePosEd = true;
 			}
@@ -410,7 +410,7 @@
 		return;
 	}
 
-	if (input.mouse.lastGUIButton != checkGUIButtons()) // XXX: This can potentially do a ton of iterations, bad design!
+	if (input.mouse.lastGUIButton != checkGUIButtons()) // FIXME: This can potentially do a ton of iterations, bad design!
 	{
 		// only repeat the button that was first clicked (e.g. if you hold and move mouse to another button)
 		input.mouse.repeatCounter = 0;
@@ -539,8 +539,8 @@
 	{
 		if (fast)
 		{
-			if (editor.samplePos <= 0xFFFF-544)
-				editor.samplePos += 544; // 50Hz/60Hz scaled value
+			if (editor.samplePos <= 0xFFFF-64)
+				editor.samplePos += 64;
 			else
 				editor.samplePos = 0xFFFF;
 		}
@@ -556,8 +556,8 @@
 	{
 		if (fast)
 		{
-			if (editor.samplePos <= 0xFFFF-37)
-				editor.samplePos += 37; // 50Hz/60Hz scaled value
+			if (editor.samplePos <= 0xFFFF-64)
+				editor.samplePos += 64;
 			else
 				editor.samplePos = 0xFFFF;
 		}
@@ -582,8 +582,8 @@
 	{
 		if (fast)
 		{
-			if (editor.samplePos > 544)
-				editor.samplePos -= 544; // 50Hz/60Hz scaled value
+			if (editor.samplePos > 64)
+				editor.samplePos -= 64;
 			else
 				editor.samplePos = 0;
 		}
@@ -599,8 +599,8 @@
 	{
 		if (fast)
 		{
-			if (editor.samplePos > 37)
-				editor.samplePos -= 37; // 50Hz/60Hz scaled value
+			if (editor.samplePos > 64)
+				editor.samplePos -= 64;
 			else
 				editor.samplePos = 0;
 		}
@@ -652,6 +652,8 @@
 	{
 		if (editor.sampleVol <= 999-10)
 			editor.sampleVol += 10;
+		else
+			editor.sampleVol = 999;
 	}
 	else
 	{
@@ -668,6 +670,8 @@
 	{
 		if (editor.sampleVol >= 10)
 			editor.sampleVol -= 10;
+		else
+			editor.sampleVol = 0;
 	}
 	else
 	{
@@ -704,9 +708,9 @@
 
 void sampleFineTuneUpButton(void)
 {
-	int8_t finetune = modEntry->samples[editor.currSample].fineTune & 0x0F;
+	int8_t finetune = modEntry->samples[editor.currSample].fineTune & 0xF;
 	if (finetune != 7)
-		modEntry->samples[editor.currSample].fineTune = (finetune + 1) & 0x0F;
+		modEntry->samples[editor.currSample].fineTune = (finetune + 1) & 0xF;
 
 	if (input.mouse.rightButtonPressed)
 		modEntry->samples[editor.currSample].fineTune = 0;
@@ -717,9 +721,9 @@
 
 void sampleFineTuneDownButton(void)
 {
-	int8_t finetune = modEntry->samples[editor.currSample].fineTune & 0x0F;
+	int8_t finetune = modEntry->samples[editor.currSample].fineTune & 0xF;
 	if (finetune != 8)
-		modEntry->samples[editor.currSample].fineTune = (finetune - 1) & 0x0F;
+		modEntry->samples[editor.currSample].fineTune = (finetune - 1) & 0xF;
 
 	if (input.mouse.rightButtonPressed)
 		modEntry->samples[editor.currSample].fineTune = 0;
@@ -1284,7 +1288,6 @@
 			return;
 		}
 
-
 		if (input.mouse.x >= 174 && input.mouse.x <= 207)
 		{
 			// FROM NUM
@@ -1437,7 +1440,7 @@
 				sampleData = &modEntry->sampleData[s->offset];
 				if (editor.markStartOfs != -1)
 				{
-					sampleData  += editor.markStartOfs;
+					sampleData += editor.markStartOfs;
 					sampleLength = editor.markEndOfs - editor.markStartOfs;
 				}
 				else
@@ -1445,19 +1448,24 @@
 					sampleLength = s->length;
 				}
 
-				sampleIndex = 0;
-				while (sampleIndex < sampleLength)
+				if (sampleLength > 0)
 				{
-					dSmp = (sampleIndex * editor.vol2) / (double)sampleLength;
-					dSmp += ((sampleLength - sampleIndex) * editor.vol1) / (double)sampleLength;
-					dSmp *= (double)(*sampleData);
-					dSmp /= 100.0;
+					double dSampleLengthMul = 1.0 / sampleLength;
 
-					smp32 = (int32_t)dSmp;
-					CLAMP8(smp32);
+					sampleIndex = 0;
+					while (sampleIndex < sampleLength)
+					{
+						dSmp = (sampleIndex * editor.vol2) * dSampleLengthMul;
+						dSmp += ((sampleLength - sampleIndex) * editor.vol1) * dSampleLengthMul;
+						dSmp *= *sampleData;
+						dSmp *= (1.0 / 100.0);
 
-					*sampleData++ = (int8_t)smp32;
-					sampleIndex++;
+						smp32 = (int32_t)dSmp;
+						CLAMP8(smp32);
+
+						*sampleData++ = (int8_t)smp32;
+						sampleIndex++;
+					}
 				}
 
 				fixSampleBeep(s);
@@ -1861,11 +1869,8 @@
 
 static bool withinButtonRect(const guiButton_t *b)
 {
-	if (input.mouse.x >= b->x1 && input.mouse.x <= b->x2 &&
-	    input.mouse.y >= b->y1 && input.mouse.y <= b->y2)
-	{
+	if (input.mouse.x >= b->x1 && input.mouse.x <= b->x2 && input.mouse.y >= b->y1 && input.mouse.y <= b->y2)
 		return true;
-	}
 
 	return false;
 }
@@ -1961,7 +1966,7 @@
 			tmp16 = input.mouse.y - editor.ui.lineCurY;
 			if (tmp16 <= 2 && tmp16 >= -9)
 			{
-				tmp16 = ((input.mouse.x - editor.ui.lineCurX) + 4) >> 3;
+				tmp16 = (uint16_t)((input.mouse.x - editor.ui.lineCurX) + 4) >> 3;
 				while (tmp16 != 0) // 0 = pos we want
 				{
 					if (tmp16 > 0)
@@ -2019,8 +2024,10 @@
 				}
 				else
 				{
-					     if (editor.ui.editObject == PTB_SONGNAME) editor.ui.updateSongName = true;
-					else if (editor.ui.editObject == PTB_SAMPLENAME) editor.ui.updateCurrSampleName = true;
+					if (editor.ui.editObject == PTB_SONGNAME)
+						editor.ui.updateSongName = true;
+					else if (editor.ui.editObject == PTB_SAMPLENAME)
+						editor.ui.updateCurrSampleName = true;
 
 					exitGetTextLine(EDIT_TEXT_UPDATE);
 				}
@@ -2045,26 +2052,19 @@
 				editor.ui.updateDiskOpFileList = true;
 			}
 		}
-		else if (editor.ui.posEdScreenShown)
+		else if (editor.ui.posEdScreenShown && modEntry->currOrder > 0)
 		{
-			if (modEntry->currOrder > 0)
-				modSetPos(modEntry->currOrder - 1, DONT_SET_ROW);
+			modSetPos(modEntry->currOrder - 1, DONT_SET_ROW);
 		}
 	}
-	else
+	else if (editor.ui.samplerScreenShown)
 	{
-		// lower part of screen
-		if (editor.ui.samplerScreenShown)
-		{
-			samplerZoomInMouseWheel();
-		}
-		else
-		{
-			// pattern data
-			if (!editor.songPlaying && modEntry->currRow > 0)
-				modSetPos(DONT_SET_ORDER, modEntry->currRow - 1);
-		}
+		samplerZoomInMouseWheel(); // lower part of screen
 	}
+	else if (!editor.songPlaying && modEntry->currRow > 0)
+	{
+		modSetPos(DONT_SET_ORDER, modEntry->currRow - 1); // pattern data
+	}
 }
 
 void mouseWheelDownHandler(void)
@@ -2075,7 +2075,6 @@
 	if (input.mouse.y < 121)
 	{
 		// upper part of screen
-
 		if (editor.ui.diskOpScreenShown)
 		{
 			if (editor.diskop.numEntries > DISKOP_LINES && editor.diskop.scrollOffset < editor.diskop.numEntries-DISKOP_LINES)
@@ -2084,26 +2083,19 @@
 				editor.ui.updateDiskOpFileList = true;
 			}
 		}
-		else if (editor.ui.posEdScreenShown)
+		else if (editor.ui.posEdScreenShown && modEntry->currOrder < modEntry->head.orderCount-1)
 		{
-			if (modEntry->currOrder < (modEntry->head.orderCount - 1))
-				modSetPos(modEntry->currOrder + 1, DONT_SET_ROW);
+			modSetPos(modEntry->currOrder + 1, DONT_SET_ROW);
 		}
 	}
-	else
+	else if (editor.ui.samplerScreenShown)
 	{
-		// lower part of screen
-		if (editor.ui.samplerScreenShown)
-		{
-			samplerZoomOutMouseWheel();
-		}
-		else
-		{
-			// pattern data
-			if (!editor.songPlaying && modEntry->currRow < MOD_ROWS)
-				modSetPos(DONT_SET_ORDER, modEntry->currRow + 1);
-		}
+		samplerZoomOutMouseWheel(); // lower part of screen
 	}
+	else if (!editor.songPlaying && modEntry->currRow < MOD_ROWS)
+	{
+		modSetPos(DONT_SET_ORDER, modEntry->currRow + 1); // pattern data
+	}
 }
 
 bool handleRightMouseButton(void)
@@ -2228,7 +2220,7 @@
 				{
 					// YES button
 					editor.ui.askScreenShown = false;
-					editor.ui.answerNo  = false;
+					editor.ui.answerNo = false;
 					editor.ui.answerYes = true;
 					handleAskYes();
 				}
@@ -2236,7 +2228,7 @@
 				{
 					// NO button
 					editor.ui.askScreenShown = false;
-					editor.ui.answerNo  = true;
+					editor.ui.answerNo = true;
 					editor.ui.answerYes = false;
 					handleAskNo();
 				}
@@ -2308,8 +2300,8 @@
 			editor.errorMsgCounter = 0;
 
 			// don't reset status text/mouse color during certain modes
-			if (!editor.ui.askScreenShown      && !editor.ui.clearScreenShown    &&
-				!editor.ui.pat2SmpDialogShown  && !editor.ui.changingChordNote   &&
+			if (!editor.ui.askScreenShown && !editor.ui.clearScreenShown &&
+				!editor.ui.pat2SmpDialogShown && !editor.ui.changingChordNote &&
 				!editor.ui.changingDrumPadNote && !editor.ui.changingSmpResample &&
 				!editor.swapChannelFlag)
 			{
@@ -2318,7 +2310,7 @@
 			}
 
 			editor.errorMsgActive = false;
-			editor.errorMsgBlock  = false;
+			editor.errorMsgBlock = false;
 
 			diskOpShowSelectText();
 		}
@@ -2328,8 +2320,7 @@
 static bool handleGUIButtons(int32_t button) // are you prepared to enter the jungle?
 {
 	char pat2SmpText[24];
-	int8_t *ptr8_1, *ptr8_2, *ptr8_3, *ptr8_4;
-	int8_t tmpSmp, modTmp, modDat;
+	int8_t *ptr8_1, *ptr8_2, *ptr8_3, *ptr8_4, tmpSmp, modTmp, modDat;
 	uint8_t i;
 	int16_t tmp16;
 	int32_t smp32, j, modPos, oldVal, tmp32;
@@ -2978,10 +2969,12 @@
 				break;
 			}
 
+			double dSamplePosMul = 1.0 / editor.samplePos;
+
 			ptr8_1 = &modEntry->sampleData[s->offset];
 			for (j = 0; j < editor.samplePos; j++)
 			{
-				dSmp = ((*ptr8_1) * j) / (double)editor.samplePos;
+				dSmp = ((*ptr8_1) * j) * dSamplePosMul;
 				smp32 = (int32_t)dSmp;
 				CLAMP8(smp32);
 				*ptr8_1++ = (int8_t)smp32;
@@ -3005,21 +2998,22 @@
 				break;
 			}
 
-			if (editor.samplePos >= (s->length - 1))
+			if (editor.samplePos >= s->length-1)
 			{
 				displayErrorMsg("INVALID POS !");
 				break;
 			}
 
+			tmp32 = (s->length - 1) - editor.samplePos;
+			if (tmp32 == 0)
+				tmp32 = 1;
+
+			double dSampleMul = 1.0 / tmp32;
+
 			ptr8_1 = &modEntry->sampleData[s->offset+s->length-1];
 			for (j = editor.samplePos; j < s->length; j++)
 			{
-				dSmp = (*ptr8_1) * (j - editor.samplePos);
-
-				tmp32 = (s->length - 1) - editor.samplePos;
-				if (tmp32 > 0)
-					dSmp /= (double)tmp32;
-
+				dSmp = ((*ptr8_1) * (j - editor.samplePos)) * dSampleMul;
 				smp32 = (int32_t)dSmp;
 				CLAMP8(smp32);
 				*ptr8_1-- = (int8_t)smp32;
@@ -3098,11 +3092,13 @@
 			if (editor.sampleVol != 100)
 			{
 				ptr8_1 = &modEntry->sampleData[modEntry->samples[editor.currSample].offset];
+				double dSampleMul = editor.sampleVol / 100.0;
+
 				for (j = 0; j < s->length; j++)
 				{
-					tmp16 = (int16_t)roundf(((*ptr8_1) * editor.sampleVol) / 100.0f);
+					tmp16 = (int16_t)(ptr8_1[j] * dSampleMul);
 					CLAMP8(tmp16);
-					*ptr8_1++ = (int8_t)tmp16;
+					ptr8_1[j] = (int8_t)tmp16;
 				}
 
 				fixSampleBeep(s);
@@ -3457,15 +3453,13 @@
 		case PTB_ABOUT:
 		{
 			editor.ui.aboutScreenShown ^= 1;
+
 			if (editor.ui.aboutScreenShown)
-			{
 				renderAboutScreen();
-			}
-			else
-			{
-				     if (editor.ui.visualizerMode == VISUAL_QUADRASCOPE) renderQuadrascopeBg();
-				else if (editor.ui.visualizerMode == VISUAL_SPECTRUM) renderSpectrumAnalyzerBg();
-			}
+			else if (editor.ui.visualizerMode == VISUAL_QUADRASCOPE)
+				renderQuadrascopeBg();
+			else if (editor.ui.visualizerMode == VISUAL_SPECTRUM)
+				renderSpectrumAnalyzerBg();
 		}
 		break;
 
@@ -3794,16 +3788,11 @@
 		case PTB_EDITOP:
 		{
 			if (editor.ui.editOpScreen == 3) // chord screen
-			{
 				editor.ui.editOpScreen = 0;
-			}
+			else if (editor.ui.editOpScreenShown)
+				editor.ui.editOpScreen = (editor.ui.editOpScreen + 1) % 3;
 			else
-			{
-				if (editor.ui.editOpScreenShown)
-					editor.ui.editOpScreen = (editor.ui.editOpScreen + 1) % 3;
-				else
-					editor.ui.editOpScreenShown = true;
-			}
+				editor.ui.editOpScreenShown = true;
 
 			renderEditOpScreen();
 		}
@@ -4499,7 +4488,7 @@
 
 		case PTB_FTUNEU:
 		{
-			if ((modEntry->samples[editor.currSample].fineTune & 0x0F) != 7)
+			if ((modEntry->samples[editor.currSample].fineTune & 0xF) != 7)
 			{
 				sampleFineTuneUpButton();
 				updateWindowTitle(MOD_IS_MODIFIED);
@@ -4509,7 +4498,7 @@
 
 		case PTB_FTUNED:
 		{
-			if ((modEntry->samples[editor.currSample].fineTune & 0x0F) != 8)
+			if ((modEntry->samples[editor.currSample].fineTune & 0xF) != 8)
 			{
 				sampleFineTuneDownButton();
 				updateWindowTitle(MOD_IS_MODIFIED);
--- a/src/pt2_sampler.c
+++ b/src/pt2_sampler.c
@@ -32,10 +32,10 @@
 
 static const int8_t tuneToneData[32] = // Tuning Tone (Sine Wave)
 {
-	  0,  25,  49,  71,  91, 106, 118, 126,
-	127, 126, 118, 106,  91,  71,  49,  25,
-	  0, -25, -49, -71, -91,-106,-118,-126,
-   -127,-126,-118,-106, -91, -71, -49, -25
+	   0,  25,  49,  71,  91, 106, 118, 126,
+	 127, 126, 118, 106,  91,  71,  49,  25,
+	   0, -25, -49, -71, -91,-106,-118,-126,
+	-127,-126,-118,-106, -91, -71, -49, -25
 };
 
 extern uint32_t *pixelBuffer; // pt_main.c
@@ -253,7 +253,7 @@
 {
 	int8_t smp, smpMin, smpMax;
 
-	smpMin =  127;
+	smpMin = 127;
 	smpMax = -128;
 
 	for (int32_t i = 0; i < numBytes; i++)
@@ -400,14 +400,14 @@
 
 void displaySample(void)
 {
-	if (editor.ui.samplerScreenShown)
-	{
-		renderSampleData();
-		if (editor.markStartOfs != -1)
-			invertRange();
+	if (!editor.ui.samplerScreenShown)
+		return;
 
-		editor.ui.update9xxPos = true;
-	}
+	renderSampleData();
+	if (editor.markStartOfs != -1)
+		invertRange();
+
+	editor.ui.update9xxPos = true;
 }
 
 void redrawSample(void)
@@ -414,41 +414,41 @@
 {
 	moduleSample_t *s;
 
-	if (editor.ui.samplerScreenShown)
+	if (!editor.ui.samplerScreenShown)
+		return;
+
+	assert(editor.currSample >= 0 && editor.currSample <= 30);
+	if (editor.currSample >= 0 && editor.currSample <= 30)
 	{
-		assert(editor.currSample >= 0 && editor.currSample <= 30);
-		if (editor.currSample >= 0 && editor.currSample <= 30)
-		{
-			editor.markStartOfs = -1;
+		editor.markStartOfs = -1;
 
-			editor.sampler.samOffset = 0;
-			updateSamOffset();
+		editor.sampler.samOffset = 0;
+		updateSamOffset();
 
-			s = &modEntry->samples[editor.currSample];
-			if (s->length > 0)
-			{
-				editor.sampler.samStart = &modEntry->sampleData[s->offset];
-				editor.sampler.samDisplay = s->length;
-				editor.sampler.samLength = s->length;
-			}
-			else
-			{
-				// "blank sample" template
-				editor.sampler.samStart = editor.sampler.blankSample;
-				editor.sampler.samLength = SAMPLE_AREA_WIDTH;
-				editor.sampler.samDisplay = SAMPLE_AREA_WIDTH;
-			}
+		s = &modEntry->samples[editor.currSample];
+		if (s->length > 0)
+		{
+			editor.sampler.samStart = &modEntry->sampleData[s->offset];
+			editor.sampler.samDisplay = s->length;
+			editor.sampler.samLength = s->length;
+		}
+		else
+		{
+			// "blank sample" template
+			editor.sampler.samStart = editor.sampler.blankSample;
+			editor.sampler.samLength = SAMPLE_AREA_WIDTH;
+			editor.sampler.samDisplay = SAMPLE_AREA_WIDTH;
+		}
 
-			renderSampleData();
-			updateSamplePos();
+		renderSampleData();
+		updateSamplePos();
 
-			editor.ui.update9xxPos = true;
-			editor.ui.lastSampleOffset = 0x900;
+		editor.ui.update9xxPos = true;
+		editor.ui.lastSampleOffset = 0x900;
 
-			// for quadrascope
-			editor.sampler.samDrawStart = s->offset;
-			editor.sampler.samDrawEnd = s->offset + s->length;
-		}
+		// for quadrascope
+		editor.sampler.samDrawStart = s->offset;
+		editor.sampler.samDrawEnd = s->offset + s->length;
 	}
 }
 
@@ -702,8 +702,10 @@
 	// this routine can be called while the sampler toolboxes are open, so redraw them
 	if (editor.ui.samplerScreenShown)
 	{
-		     if (editor.ui.samplerVolBoxShown) renderSamplerVolBox();
-		else if (editor.ui.samplerFiltersBoxShown) renderSamplerFiltersBox();
+		if (editor.ui.samplerVolBoxShown)
+			renderSamplerVolBox();
+		else if (editor.ui.samplerFiltersBoxShown)
+			renderSamplerFiltersBox();
 	}
 }
 
@@ -828,7 +830,7 @@
 }
 
 #define INTRP_QUADRATIC_TAPS 3
-#define INTRP8_QUADRATIC(s1, s2, s3, f) /* output: -32768..32767 */ \
+#define INTRP8_QUADRATIC(s1, s2, s3, f) /* output: -32768..32767 (+ spline overshoot) */ \
 { \
 	int32_t s4, frac = (f) >> 1; \
 	\
@@ -1042,7 +1044,7 @@
 			mixData[j] += samples[0];
 
 			v->posFrac += v->delta;
-			if (v->posFrac >= 65536)
+			if (v->posFrac > 0xFFFF)
 			{
 				v->pos += v->posFrac >> 16;
 				v->posFrac &= 0xFFFF;
@@ -1173,7 +1175,7 @@
 
 		if (loopStart+loopLength > s->length)
 		{
-			s->loopStart= 0;
+			s->loopStart = 0;
 			s->loopLength = 2;
 		}
 		else
@@ -1230,9 +1232,7 @@
 	smpFrom2 = hexToInteger2(&editor.mixText[7]);
 	smpTo = hexToInteger2(&editor.mixText[13]);
 
-	if (smpFrom1 == 0 || smpFrom1 > 0x1F ||
-	    smpFrom2 == 0 || smpFrom2 > 0x1F ||
-	    smpTo    == 0 || smpTo    > 0x1F)
+	if (smpFrom1 == 0 || smpFrom1 > 0x1F || smpFrom2 == 0 || smpFrom2 > 0x1F || smpTo == 0 || smpTo > 0x1F)
 	{
 		displayErrorMsg("NOT RANGE 01-1F !");
 		return;
@@ -1401,7 +1401,7 @@
 
 	for (i = from; i < to; i++)
 	{
-		tmp16 = (smpDat[i + 0] + smpDat[i + 1]) >> 1;
+		tmp16 = (smpDat[i+0] + smpDat[i+1]) >> 1;
 		CLAMP8(tmp16);
 		smpDat[i] = (int8_t)tmp16;
 	}
@@ -1425,10 +1425,12 @@
 		if (editor.tuningNote > 35)
 			editor.tuningNote = 35;
 
+		modEntry->channels[editor.tuningChan].n_volume = 64; // we need this for the scopes
+
 		paulaSetPeriod(editor.tuningChan, periodTable[editor.tuningNote]);
 		paulaSetVolume(editor.tuningChan, 64);
 		paulaSetData(editor.tuningChan, tuneToneData);
-		paulaSetLength(editor.tuningChan, sizeof (tuneToneData));
+		paulaSetLength(editor.tuningChan, sizeof (tuneToneData) / 2);
 		paulaStartDMA(editor.tuningChan);
 
 		// force loop flag on for scopes
@@ -1490,13 +1492,15 @@
 	}
 	else
 	{
-		middlePos = editor.sampler.samOffset + (int32_t)round(editor.sampler.samDisplay / 2.0);
+		middlePos = editor.sampler.samOffset + (int32_t)((editor.sampler.samDisplay / 2.0) + 0.5);
 
 		invertRange();
-		if (input.keyb.shiftPressed && (editor.markStartOfs != -1))
+		if (input.keyb.shiftPressed && editor.markStartOfs != -1)
 		{
-			     if (editor.markStartOfs < middlePos) editor.markEndOfs = middlePos;
-			else if (editor.markEndOfs > middlePos) editor.markStartOfs = middlePos;
+			if (editor.markStartOfs < middlePos)
+				editor.markEndOfs = middlePos;
+			else if (editor.markEndOfs > middlePos)
+				editor.markStartOfs = middlePos;
 		}
 		else
 		{
@@ -1717,7 +1721,7 @@
 			val32 = (s->loopStart - (markEnd - markStart)) & 0xFFFFFFFE;
 			if (val32 < 0)
 			{
-				s->loopStart  = 0;
+				s->loopStart = 0;
 				s->loopLength = 2;
 			}
 			else
@@ -1781,7 +1785,6 @@
 	}
 
 	s = &modEntry->samples[editor.currSample];
-
 	if (s->length > 0 && editor.markStartOfs == -1)
 	{
 		displayErrorMsg("SET CURSOR POS");
@@ -1887,33 +1890,39 @@
 	updateWindowTitle(MOD_IS_MODIFIED);
 }
 
-void samplerPlayWaveform(void)
+static void playCurrSample(uint8_t chn, int32_t startOffset, int32_t endOffset, bool playWaveformFlag)
 {
-	uint8_t chn;
-	int16_t tempPeriod;
 	moduleChannel_t *ch;
 	moduleSample_t *s;
 
-	chn = editor.cursor.channel;
-
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
 	assert(chn < AMIGA_VOICES);
 	assert(editor.currPlayNote <= 35);
 
-	s  = &modEntry->samples[editor.currSample];
+	s = &modEntry->samples[editor.currSample];
 	ch = &modEntry->channels[chn];
 
-	tempPeriod = periodTable[(37 * (s->fineTune & 0xF)) + editor.currPlayNote];
 	ch->n_samplenum = editor.currSample;
 	ch->n_volume = s->volume;
-	ch->n_period = tempPeriod;
-	ch->n_start = &modEntry->sampleData[s->offset];
-	ch->n_length = (s->loopStart > 0) ? (s->loopStart + s->loopLength) : s->length; // yes, this is correct. Do not touch
-	ch->n_loopstart = &modEntry->sampleData[s->offset + s->loopStart];
-	ch->n_replen = s->loopLength;
+	ch->n_period = periodTable[(37 * (s->fineTune & 0xF)) + editor.currPlayNote];
+	
+	if (playWaveformFlag)
+	{
+		ch->n_start = &modEntry->sampleData[s->offset];
+		ch->n_length = (s->loopStart > 0) ? (uint32_t)(s->loopStart + s->loopLength) / 2 : s->length / 2;
+		ch->n_loopstart = &modEntry->sampleData[s->offset + s->loopStart];
+		ch->n_replen = s->loopLength / 2;
+	}
+	else
+	{
+		ch->n_start = &modEntry->sampleData[s->offset + startOffset];
+		ch->n_length = (endOffset - startOffset) / 2;
+		ch->n_loopstart = &modEntry->sampleData[s->offset];
+		ch->n_replen = 1;
+	}
 
-	if (ch->n_length < 2)
-		ch->n_length = 2;
+	if (ch->n_length == 0)
+		ch->n_length = 1;
 
 	paulaSetVolume(chn, ch->n_volume);
 	paulaSetPeriod(chn, ch->n_period);
@@ -1926,64 +1935,35 @@
 		paulaStopDMA(chn);
 
 	// these take effect after the current DMA cycle is done
-	paulaSetData(chn, ch->n_loopstart);
-	paulaSetLength(chn, ch->n_replen);
+	if (playWaveformFlag)
+	{
+		paulaSetData(chn, ch->n_loopstart);
+		paulaSetLength(chn, ch->n_replen);
+	}
+	else
+	{
+		paulaSetData(chn, NULL);
+		paulaSetLength(chn, 1);
+	}
 
 	updateSpectrumAnalyzer(ch->n_volume, ch->n_period);
 }
 
+void samplerPlayWaveform(void)
+{
+	playCurrSample(editor.cursor.channel, 0, 0, true);
+}
+
 void samplerPlayDisplay(void)
 {
-	uint8_t chn;
-	int16_t tempPeriod;
-	moduleChannel_t *ch;
-	moduleSample_t *s;
+	int32_t start = editor.sampler.samOffset;
+	int32_t end = editor.sampler.samOffset + editor.sampler.samDisplay;
 
-	chn = editor.cursor.channel;
-
-	assert(editor.currSample >= 0 && editor.currSample <= 30);
-	assert(chn < AMIGA_VOICES);
-	assert(editor.currPlayNote <= 35);
-
-	s  = &modEntry->samples[editor.currSample];
-	ch = &modEntry->channels[chn];
-
-	tempPeriod = periodTable[(37 * (s->fineTune & 0xF)) + editor.currPlayNote];
-	ch->n_samplenum = editor.currSample;
-	ch->n_period = tempPeriod;
-	ch->n_volume = s->volume;
-	ch->n_start = &modEntry->sampleData[s->offset + editor.sampler.samOffset];
-	ch->n_length = editor.sampler.samDisplay;
-	ch->n_loopstart = &modEntry->sampleData[s->offset];
-	ch->n_replen = 2;
-
-	if (ch->n_length < 2)
-		ch->n_length = 2;
-
-	paulaSetVolume(chn, ch->n_volume);
-	paulaSetPeriod(chn, ch->n_period);
-	paulaSetData(chn, ch->n_start);
-	paulaSetLength(chn, ch->n_length);
-
-	if (!editor.muted[chn])
-		paulaStartDMA(chn);
-	else
-		paulaStopDMA(chn);
-
-	// these take effect after the current DMA cycle is done
-	paulaSetData(chn, NULL);
-	paulaSetLength(chn, 1);
-
-	updateSpectrumAnalyzer(ch->n_volume, ch->n_period);
+	playCurrSample(editor.cursor.channel, start, end, false);
 }
 
 void samplerPlayRange(void)
 {
-	uint8_t chn;
-	int16_t tempPeriod;
-	moduleChannel_t *ch;
-	moduleSample_t *s;
-
 	if (editor.markStartOfs == -1)
 	{
 		displayErrorMsg("NO RANGE SELECTED");
@@ -1996,42 +1976,7 @@
 		return;
 	}
 
-	chn = editor.cursor.channel;
-
-	assert(editor.currSample >= 0 && editor.currSample <= 30);
-	assert(chn < AMIGA_VOICES);
-	assert(editor.currPlayNote <= 35);
-
-	s = &modEntry->samples[editor.currSample];
-	ch = &modEntry->channels[chn];
-
-	tempPeriod = periodTable[(37 * (s->fineTune & 0xF)) + editor.currPlayNote];
-	ch->n_samplenum = editor.currSample;
-	ch->n_period = tempPeriod;
-	ch->n_volume = s->volume;
-	ch->n_start = &modEntry->sampleData[s->offset + editor.markStartOfs];
-	ch->n_length = editor.markEndOfs - editor.markStartOfs;
-	ch->n_loopstart = &modEntry->sampleData[s->offset];
-	ch->n_replen = 2;
-
-	if (ch->n_length < 2)
-		ch->n_length = 2;
-
-	paulaSetVolume(chn, ch->n_volume);
-	paulaSetPeriod(chn, ch->n_period);
-	paulaSetData(chn, ch->n_start);
-	paulaSetLength(chn, ch->n_length);
-
-	if (!editor.muted[chn])
-		paulaStartDMA(chn);
-	else
-		paulaStopDMA(chn);
-
-	// these take effect after the current DMA cycle is done
-	paulaSetData(chn, NULL);
-	paulaSetLength(chn, 1);
-
-	updateSpectrumAnalyzer(ch->n_volume, ch->n_period);
+	playCurrSample(editor.cursor.channel, editor.markStartOfs, editor.markEndOfs, false);
 }
 
 void setLoopSprites(void)
--- a/src/pt2_scopes.c
+++ b/src/pt2_scopes.c
@@ -150,7 +150,7 @@
 
 		volume = modEntry->channels[i].n_volume;
 
-		if (se->active && tmpScope.data != NULL && volume != 0 && !editor.muted[i] && tmpScope.length > 0)
+		if (se->active && tmpScope.data != NULL && volume != 0 && tmpScope.length > 0)
 		{
 			smpPeak = 0;
 			readPos = tmpScope.pos;
@@ -229,7 +229,7 @@
 			volume = -modEntry->channels[i].n_volume; // 0..64 -> -64..0
 
 			// render scope
-			if (se->active && tmpScope.data != NULL && volume != 0 && !editor.muted[i] && tmpScope.length > 0)
+			if (se->active && tmpScope.data != NULL && volume != 0 && tmpScope.length > 0)
 			{
 				// scope is active
 
--- a/src/pt2_visuals.c
+++ b/src/pt2_visuals.c
@@ -1230,7 +1230,7 @@
 
 	sprintf(verString, "v%s", PROG_VER_STR);
 	verStringX = 260 + (63 - ((uint32_t)strlen(verString) * (FONT_CHAR_W - 1))) / 2;
-	textOutTight(pixelBuffer, verStringX, 75, verString, palette[PAL_GENBKG2]);
+	textOutTight(pixelBuffer, verStringX, 67, verString, palette[PAL_GENBKG2]);
 }
 
 void renderEditOpMode(void)