1870 lines · 40.0 KB · C
RawDownload
// for finding memory leaks in debug mode with Visual Studio#if defined _DEBUG && defined _MSC_VER#include <crtdbg.h>#endif #include <stdio.h>#include <stdint.h>#include "ft2_header.h"#include "ft2_config.h"#include "ft2_keyboard.h"#include "ft2_audio.h"#include "ft2_midi.h"#include "ft2_pattern_ed.h"#include "ft2_sysreqs.h"#include "ft2_textboxes.h"#include "ft2_tables.h"#include "ft2_structs.h" enum{	KEYTYPE_NUM = 0,	KEYTYPE_ALPHA = 1}; static double dVolScaleFK1 = 1.0, dVolScaleFK2 = 1.0; // for block cut/copy/pastestatic bool blockCopied;static int16_t markXSize, markYSize;static uint16_t ptnBufLen, trkBufLen; // for transposing - these are set and tested accordinglystatic int8_t lastTranspVal;static uint8_t lastInsMode, lastTranspMode;static uint32_t transpDelNotes; // count of under-/overflowing notes for warning messagestatic note_t clearNote; static note_t blkCopyBuff[MAX_PATT_LEN * MAX_CHANNELS];static note_t ptnCopyBuff[MAX_PATT_LEN * MAX_CHANNELS];static note_t trackCopyBuff[MAX_PATT_LEN]; static const int8_t tickArr[16] = { 16, 8, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1 }; void recordNote(uint8_t note, int8_t vol); // when the cursor is at the note slotstatic bool testNoteKeys(SDL_Scancode scancode){	const int8_t noteNum = scancodeKeyToNote(scancode);	if (noteNum == NOTE_OFF)	{		// inserts "note off" if editing song		if (playMode == PLAYMODE_EDIT || playMode == PLAYMODE_RECPATT || playMode == PLAYMODE_RECSONG)		{			if (!allocatePattern(editor.editPattern))				return true; // key pressed 			pattern[editor.editPattern][(editor.row * MAX_CHANNELS) + cursor.ch].note = NOTE_OFF; 			const uint16_t numRows = patternNumRows[editor.editPattern];			if (playMode == PLAYMODE_EDIT && numRows >= 1)				setPos(-1, (editor.row + editor.editRowSkip) % numRows, true); 			ui.updatePatternEditor = true;			setSongModifiedFlag();		} 		return true; // key pressed	} 	if (noteNum > 0 && noteNum <= 96)	{		recordNote(noteNum, -1);		return true; // note key pressed (and note triggered)	} 	return false; // no note key pressed} // when the cursor is at the note slotvoid testNoteKeysRelease(SDL_Scancode scancode){	const int8_t noteNum = scancodeKeyToNote(scancode); // convert key scancode to note number	if (noteNum > 0 && noteNum <= 96)		recordNote(noteNum, 0); // release note} static bool testEditKeys(SDL_Scancode scancode, SDL_Keycode keycode){	int8_t i; 	if (cursor.object == CURSOR_NOTE)	{		// the edit cursor is at the note slot 		if (testNoteKeys(scancode))		{			keyb.keyRepeat = (playMode == PLAYMODE_EDIT); // repeat keys only if in edit mode			return true; // we jammed an instrument		} 		return false; // no note key pressed, test other keys	} 	if (playMode != PLAYMODE_EDIT && playMode != PLAYMODE_RECSONG && playMode != PLAYMODE_RECPATT)		return false; // we're not editing, test other keys 	// convert key to slot data 	if (cursor.object == CURSOR_VOL1)	{		// volume column effect type (mixed keys) 		for (i = 0; i < KEY2VOL_ENTRIES; i++)		{			if (keycode == key2VolTab[i])				break;		} 		if (i == KEY2VOL_ENTRIES)		{			// volume column key not found, let's try a hack for '-' and '+' keys first			if (scancode == SDL_SCANCODE_MINUS)				i = 5;			else if (scancode == SDL_SCANCODE_EQUALS)				i = 6;			else				i = -1; // invalid key for slot		}	}	else if (cursor.object == CURSOR_EFX0)	{		// effect type (mixed keys) 		for (i = 0; i < KEY2EFX_ENTRIES; i++)		{			if (keycode == key2EfxTab[i])				break;		} 		if (i == KEY2EFX_ENTRIES)			i = -1; // invalid key for slot	}	else	{		// all other slots (hex keys) 		for (i = 0; i < KEY2HEX_ENTRIES; i++)		{			if (keycode == key2HexTab[i])				break;		} 		if (i == KEY2HEX_ENTRIES)			i = -1; // invalid key for slot	} 	if (i == -1 || !allocatePattern(editor.editPattern))		return false; // no edit to be done 	// insert slot data 	note_t *p = &pattern[editor.editPattern][(editor.row * MAX_CHANNELS) + cursor.ch];	switch (cursor.object)	{		case CURSOR_INST1:		{			uint8_t oldVal = p->instr; 			p->instr = (p->instr & 0x0F) | (i << 4);			if (p->instr > MAX_INST)				p->instr = MAX_INST; 			if (p->instr != oldVal)				setSongModifiedFlag();		}		break; 		case CURSOR_INST2:		{			uint8_t oldVal = p->instr;			p->instr = (p->instr & 0xF0) | i; 			if (p->instr != oldVal)				setSongModifiedFlag();		}		break; 		case CURSOR_VOL1:		{			uint8_t oldVal = p->vol; 			p->vol = (p->vol & 0x0F) | ((i + 1) << 4);			if (p->vol >= 0x51 && p->vol <= 0x5F)				p->vol = 0x50; 			if (p->vol != oldVal)				setSongModifiedFlag();		}		break; 		case CURSOR_VOL2:		{			uint8_t oldVal = p->vol; 			if (p->vol < 0x10)				p->vol = 0x10 + i;			else				p->vol = (p->vol & 0xF0) | i; 			if (p->vol >= 0x51 && p->vol <= 0x5F)				p->vol = 0x50; 			if (p->vol != oldVal)				setSongModifiedFlag();		}		break; 		case CURSOR_EFX0:		{			uint8_t oldVal = p->efx; 			p->efx = i;			if (p->efx != oldVal)				setSongModifiedFlag();		}		break; 		case CURSOR_EFX1:		{			uint8_t oldVal = p->efxData; 			p->efxData = (p->efxData & 0x0F) | (i << 4);			if (p->efxData != oldVal)				setSongModifiedFlag();		}		break; 		case CURSOR_EFX2:		{			uint8_t oldVal = p->efxData; 			p->efxData = (p->efxData & 0xF0) | i;			if (p->efxData != oldVal)				setSongModifiedFlag();		}		break; 		default: break;	} 	// increase row (only in edit mode) 	const int16_t numRows = patternNumRows[editor.editPattern];	if (playMode == PLAYMODE_EDIT && numRows >= 1)		setPos(-1, (editor.row + editor.editRowSkip) % numRows, true); 	if (i == 0) // if we inserted a zero, check if pattern is empty, for killing		killPatternIfUnused(editor.editPattern); 	ui.updatePatternEditor = true;	return true;} static void evaluateTimeStamp(int16_t *songPos, int16_t *pattNum, int16_t *row, int16_t *tick){	int16_t outSongPos = editor.songPos;	int16_t outPattern = editor.editPattern;	int16_t outRow = editor.row;	int16_t outTick = editor.speed - editor.tick; 	outTick = CLAMP(outTick, 0, editor.speed - 1); 	// this is needed, but also breaks quantization on speed>15	if (outTick > 15)		outTick = 15; 	const int16_t numRows = patternNumRows[outPattern]; 	if (config.recQuant > 0)	{		if (config.recQuantRes >= 16)		{			outTick += (editor.speed >> 1) + 1;		}		else		{			int16_t r = tickArr[config.recQuantRes-1];			int16_t p = outRow & (r - 1); 			if (p < (r >> 1))				outRow -= p;			else				outRow = (outRow + r) - p; 			outTick = 0;		}	} 	if (outTick > editor.speed)	{		outTick -= editor.speed;		outRow++;	} 	if (outRow >= numRows)	{		outRow = 0; 		if (playMode == PLAYMODE_RECSONG)			outSongPos++; 		if (outSongPos >= song.songLength)			outSongPos = song.songLoopStart; 		outPattern = song.orders[outSongPos];	} 	*songPos = outSongPos;	*pattNum = outPattern;	*row = outRow;	*tick = outTick;} void recordNote(uint8_t noteNum, int8_t vol) // directly ported from the original FT2 code - what a mess, but it works...{	int8_t i;	int16_t pattNum, songPos, row, tick;	int32_t time;	note_t *p; 	const int16_t oldRow = editor.row; 	if (songPlaying)	{		// row quantization		evaluateTimeStamp(&songPos, &pattNum, &row, &tick);	}	else	{		songPos = editor.songPos;		pattNum = editor.editPattern;		row = editor.row;		tick = 0;	} 	bool editmode = (playMode == PLAYMODE_EDIT);	bool recmode = (playMode == PLAYMODE_RECSONG) || (playMode == PLAYMODE_RECPATT); 	if (noteNum == NOTE_OFF)		vol = 0; 	int8_t c = -1;	int8_t k = -1; 	if (editmode || recmode)	{		// find out what channel is the most suitable in edit/record mode 		if ((config.multiEdit && editmode) || (config.multiRec && recmode))		{			time = 0x7FFFFFFF;			for (i = 0; i < song.numChannels; i++)			{				if (editor.chnMode[i] && config.multiRecChn[i] && editor.keyOffTime[i] < time && editor.keyOnTab[i] == 0)				{					c = i;					time = editor.keyOffTime[i];				}			}		}		else		{			c = cursor.ch;		} 		for (i = 0; i < song.numChannels; i++)		{			if (noteNum == editor.keyOnTab[i] && config.multiRecChn[i])				k = i;		}	}	else	{		// find out what channel is the most suitable in idle/play mode (jamming)		if (config.multiKeyJazz)		{			time = 0x7FFFFFFF;			c = 0; 			if (songPlaying)			{				for (i = 0; i < song.numChannels; i++)				{					if (editor.keyOffTime[i] < time && editor.keyOnTab[i] == 0 && config.multiRecChn[i])					{						c = i;						time = editor.keyOffTime[i];					}				}			} 			if (time == 0x7FFFFFFF)			{				for (i = 0; i < song.numChannels; i++)				{					if (editor.keyOffTime[i] < time && editor.keyOnTab[i] == 0)					{						c = i;						time = editor.keyOffTime[i];					}				}			}		}		else		{			c = cursor.ch;		} 		for (i = 0; i < song.numChannels; i++)		{			if (noteNum == editor.keyOnTab[i])				k = i;		}	} 	if (vol != 0)	{		if (c < 0 || (k >= 0 && (config.multiEdit || (recmode || !editmode))))			return; 		// play note 		editor.keyOnTab[c] = noteNum; 		if (row >= oldRow) // non-FT2 fix: only do this if we didn't quantize to next row		{#ifdef HAS_MIDI			playTone(c, editor.curInstr, noteNum, vol, midi.currMIDIVibDepth, midi.currMIDIPitch);#else			playTone(c, editor.curInstr, noteNum, vol, 0, 0);#endif		} 		if (editmode || recmode)		{			if (allocatePattern(pattNum))			{				const int16_t numRows = patternNumRows[pattNum];				p = &pattern[pattNum][(row * MAX_CHANNELS) + c]; 				// insert data				p->note = noteNum;				if (editor.curInstr > 0)					p->instr = editor.curInstr; 				if (vol >= 0)					p->vol = 0x10 + vol; 				if (!recmode)				{					// increase row (only in edit mode)					if (numRows >= 1)						setPos(-1, (editor.row + editor.editRowSkip) % numRows, true);				}				else				{					// apply tick delay for note if quantization is disabled					if (!config.recQuant && tick > 0)					{						p->efx = 0x0E;						p->efxData = 0xD0 + (tick & 0x0F);					}				} 				ui.updatePatternEditor = true;				setSongModifiedFlag();			}		}	}	else	{		// note off 		if (k != -1)			c = k; 		if (c < 0)			return; 		editor.keyOffNr++; 		editor.keyOnTab[c] = 0;		editor.keyOffTime[c] = editor.keyOffNr; 		if (row >= oldRow) // non-FT2 fix: only do this if we didn't quantize to next row		{#ifdef HAS_MIDI			playTone(c, editor.curInstr, NOTE_OFF, vol, midi.currMIDIVibDepth, midi.currMIDIPitch);#else

Lines 1–500 of 1870.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t