Sigrid Solveig Haflínudóttirreplayer: fix compiling with !HAS_MIDI6f842e93 years agoHistory
3391 lines · 69.5 KB · C
RawDownload
// for finding memory leaks in debug mode with Visual Studio#if defined _DEBUG && defined _MSC_VER#include <crtdbg.h>#endif #include <stdint.h>#include <stdio.h>#include <math.h>#include "ft2_header.h"#include "ft2_config.h"#include "ft2_gui.h"#include "ft2_video.h"#include "ft2_pattern_ed.h"#include "ft2_sample_ed.h"#include "ft2_inst_ed.h"#include "ft2_diskop.h"#include "ft2_midi.h"#include "scopes/ft2_scopes.h"#include "ft2_mouse.h"#include "ft2_sample_loader.h"#include "ft2_tables.h"#include "ft2_structs.h"#include "mixer/ft2_windowed_sinc.h" static double dLogTab[4*12*16], dExp2MulTab[32];static bool bxxOverflow;static note_t nilPatternLine[MAX_CHANNELS]; typedef void (*volColumnEfxRoutine)(channel_t *ch);typedef void (*volColumnEfxRoutine2)(channel_t *ch, uint8_t *volColumnData);typedef void (*efxRoutine)(channel_t *ch, uint8_t param); // globally accessedint8_t playMode = 0;bool songPlaying = false, audioPaused = false, musicPaused = false;volatile bool replayerBusy = false;const uint16_t *note2Period = NULL;int16_t patternNumRows[MAX_PATTERNS];channel_t channel[MAX_CHANNELS];song_t song;instr_t *instr[128+4];note_t *pattern[MAX_PATTERNS];// ---------------------------------- void fixString(char *str, int32_t lastChrPos) // removes leading spaces and 0x1A chars{	for (int32_t i = lastChrPos; i >= 0; i--)	{		if (str[i] == ' ' || str[i] == 0x1A)			str[i] = '\0';		else if (str[i] != '\0')			break;	}	str[lastChrPos+1] = '\0';} void fixSongName(void){	fixString(song.name, 19);} void fixInstrAndSampleNames(int16_t insNum){	fixString(song.instrName[insNum], 21);	if (instr[insNum] != NULL)	{		sample_t *s = instr[insNum]->smp;		for (int32_t i = 0; i < MAX_SMP_PER_INST; i++, s++)			fixString(s->name, 21);	}} void resetChannels(void){	const bool audioWasntLocked = !audio.locked;	if (audioWasntLocked)		lockAudio(); 	memset(channel, 0, sizeof (channel)); 	channel_t *ch = channel;	for (int32_t i = 0; i < MAX_CHANNELS; i++, ch++)	{		ch->instrPtr = instr[0];		ch->status = IS_Vol;		ch->oldPan = 128;		ch->outPan = 128;		ch->finalPan = 128; 		ch->channelOff = !editor.chnMode[i]; // set channel mute flag from global mute flag	} 	if (audioWasntLocked)		unlockAudio();} void setSongModifiedFlag(void){	song.isModified = true;	editor.updateWindowTitle = true;} void removeSongModifiedFlag(void){	song.isModified = false;	editor.updateWindowTitle = true;} // used on external sample load and during sample loading (on some module formats)void tuneSample(sample_t *s, const int32_t midCFreq, bool linearPeriodsFlag){	#define MIN_PERIOD (0)	#define MAX_PERIOD (((10*12*16)-1)-1) /* -1 (because of bugged amigaPeriods table values) */ 	double (*dGetHzFromPeriod)(int32_t) = linearPeriodsFlag ? dLinearPeriod2Hz : dAmigaPeriod2Hz;	const uint16_t *periodTab = linearPeriodsFlag ? linearPeriods : amigaPeriods; 	if (midCFreq <= 0 || periodTab == NULL)	{		s->finetune = s->relativeNote = 0;		return;	} 	// handle frequency boundaries first... 	if (midCFreq <= (int32_t)dGetHzFromPeriod(periodTab[MIN_PERIOD]))	{		s->finetune = -128;		s->relativeNote = -48;		return;	} 	if (midCFreq >= (int32_t)dGetHzFromPeriod(periodTab[MAX_PERIOD]))	{		s->finetune = 127;		s->relativeNote = 71;		return;	} 	// check if midCFreq is matching any of the non-finetuned note frequencies (C-0..B-9) 	for (int8_t i = 0; i < 10*12; i++)	{		if (midCFreq == (int32_t)dGetHzFromPeriod(periodTab[16 + (i<<4)]))		{			s->finetune = 0;			s->relativeNote = i - NOTE_C4;			return;		}	} 	// find closest frequency in period table 	int32_t period = MAX_PERIOD;	for (; period >= MIN_PERIOD; period--)	{		const int32_t curr = (int32_t)dGetHzFromPeriod(periodTab[period]);		if (midCFreq == curr)			break; 		if (midCFreq > curr)		{			const int32_t next = (int32_t)dGetHzFromPeriod(periodTab[period+1]);			const int32_t errorCurr = ABS(curr-midCFreq);			const int32_t errorNext = ABS(next-midCFreq); 			if (errorCurr <= errorNext)				break; // current is the closest 			period++;			break; // current+1 is the closest		}	} 	s->finetune = ((period & 31) - 16) << 3;	s->relativeNote = (int8_t)(((period & ~31) >> 4) - NOTE_C4);} void setPatternLen(uint16_t pattNum, int16_t numRows){	assert(pattNum < MAX_PATTERNS);	if ((numRows < 1 || numRows > MAX_PATT_LEN) || numRows == patternNumRows[pattNum])		return; 	const bool audioWasntLocked = !audio.locked;	if (audioWasntLocked)		lockAudio(); 	patternNumRows[pattNum] = numRows; 	if (pattern[pattNum] != NULL)		killPatternIfUnused(pattNum); 	// non-FT2 security	song.pattDelTime = 0;	song.pattDelTime2 = 0;	song.pBreakFlag = false;	song.posJumpFlag = false;	song.pBreakPos = 0; 	song.currNumRows = numRows;	if (song.row >= song.currNumRows)	{		song.row = song.currNumRows - 1;		editor.row = song.row;	} 	checkMarkLimits(); 	if (audioWasntLocked)		unlockAudio(); 	ui.updatePatternEditor = true;	ui.updatePosSections = true;} int16_t getUsedSamples(int16_t smpNum){	if (instr[smpNum] == NULL)		return 0; 	instr_t *ins = instr[smpNum]; 	int16_t i = 16 - 1;	while (i >= 0 && ins->smp[i].dataPtr == NULL && ins->smp[i].name[0] == '\0')		i--; 	/* Yes, 'i' can be -1 here, and will be set to at least 0	** because of ins->ta values. Possibly an FT2 bug...	*/	for (int16_t j = 0; j < 96; j++)	{		if (ins->note2SampleLUT[j] > i)			i = ins->note2SampleLUT[j];	} 	return i+1;} int16_t getRealUsedSamples(int16_t smpNum){	if (instr[smpNum] == NULL)		return 0; 	int8_t i = 16 - 1;	while (i >= 0 && instr[smpNum]->smp[i].dataPtr == NULL)		i--; 	return i+1;} double dLinearPeriod2Hz(int32_t period){	period &= 0xFFFF; // just in case (actual period range is 0..65535) 	if (period == 0)		return 0.0; // in FT2, a period of 0 results in 0Hz 	const uint32_t invPeriod = ((12 * 192 * 4) - period) & 0xFFFF; // mask needed for FT2 period overflow quirk 	const uint32_t quotient  = invPeriod / (12 * 16 * 4);	const uint32_t remainder = invPeriod % (12 * 16 * 4); 	return dLogTab[remainder] * dExp2MulTab[(14-quotient) & 31]; // x = y >> ((14-quotient) & 31);} double dAmigaPeriod2Hz(int32_t period){	period &= 0xFFFF; // just in case (actual period range is 0..65535) 	if (period == 0)		return 0.0; // in FT2, a period of 0 results in 0Hz 	return (double)(8363 * 1712) / period;} double dPeriod2Hz(int32_t period){	return audio.linearPeriodsFlag ? dLinearPeriod2Hz(period) : dAmigaPeriod2Hz(period);} // returns *exact* FT2 C-4 voice rate (depending on finetune, relativeNote and linear/Amiga period mode)double getSampleC4Rate(sample_t *s){	int32_t note = NOTE_C4 + s->relativeNote;	if (note < 0)		return -1; // shouldn't happen (just in case...) 	if (note >= (10*12)-1)		return -1; // B-9 (after relativeTone add) = illegal! (won't play in replayer) 	const int32_t C4Period = (note << 4) + (((int8_t)s->finetune >> 3) + 16); 	const int32_t period = audio.linearPeriodsFlag ? linearPeriods[C4Period] : amigaPeriods[C4Period];	return dPeriod2Hz(period);} void setLinearPeriods(bool linearPeriodsFlag){	pauseAudio(); 	audio.linearPeriodsFlag = linearPeriodsFlag; 	if (audio.linearPeriodsFlag)		note2Period = linearPeriods;	else		note2Period = amigaPeriods; 	resumeAudio(); 	if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_AUDIO)	{		// update "frequency slides" radiobutton, if it's shown		setConfigAudioRadioButtonStates();	} 	// update mid-C freq. in instr. editor (it can slightly differ between Amiga/linear)	if (ui.instEditorShown)		drawC4Rate();} static void retrigVolume(channel_t *ch){	ch->realVol = ch->oldVol;	ch->outVol = ch->oldVol;	ch->outPan = ch->oldPan;	ch->status |= IS_Vol + IS_Pan + IS_QuickVol;} static void retrigEnvelopeVibrato(channel_t *ch){	if (!(ch->waveCtrl & 0x04)) ch->vibPos  = 0;	if (!(ch->waveCtrl & 0x40)) ch->tremPos = 0; 	ch->retrigCnt = 0;	ch->tremorPos = 0; 	instr_t *ins = ch->instrPtr;	assert(ins != NULL); 	if (ins->volEnvFlags & ENV_ENABLED)	{		ch->volEnvTick = 65535;		ch->volEnvPos = 0;	} 	if (ins->panEnvFlags & ENV_ENABLED)	{		ch->panEnvTick = 65535;		ch->panEnvPos = 0;	} 	ch->keyOff = false;	ch->fadeoutSpeed = ins->fadeout; // FT2 doesn't check if fadeout is more than 4095!	ch->fadeoutVol = 32768; 	if (ins->autoVibDepth > 0)	{		ch->autoVibPos = 0;		if (ins->autoVibSweep > 0)		{			ch->autoVibAmp = 0;			ch->autoVibSweep = (ins->autoVibDepth << 8) / ins->autoVibSweep;		}		else		{			ch->autoVibAmp = ins->autoVibDepth << 8;			ch->autoVibSweep = 0;		}	}} void keyOff(channel_t *ch){	ch->keyOff = true; 	instr_t *ins = ch->instrPtr;	assert(ins != NULL); 	if (ins->volEnvFlags & ENV_ENABLED)	{		if (ch->volEnvTick >= (uint16_t)ins->volEnvPoints[ch->volEnvPos][0])			ch->volEnvTick = ins->volEnvPoints[ch->volEnvPos][0] - 1;	}	else	{		ch->realVol = 0;		ch->outVol = 0;		ch->status |= IS_Vol + IS_QuickVol;	} 	if (!(ins->panEnvFlags & ENV_ENABLED)) // What..? Probably an FT2 bug.	{		if (ch->panEnvTick >= (uint16_t)ins->panEnvPoints[ch->panEnvPos][0])			ch->panEnvTick = ins->panEnvPoints[ch->panEnvPos][0] - 1;	}} void calcReplayerLogTab(void) // for linear period -> hz calculation{	for (int32_t i = 0; i < 32; i++)		dExp2MulTab[i] = 1.0 / exp2(i); // 1/(2^i) 	for (int32_t i = 0; i < 4*12*16; i++)		dLogTab[i] = (8363.0 * 256.0) * exp2(i / (4.0 * 12.0 * 16.0));} void calcReplayerVars(int32_t audioFreq){	assert(audioFreq > 0);	if (audioFreq <= 0)		return; 	audio.dHz2MixDeltaMul = (double)MIXER_FRAC_SCALE / audioFreq;	audio.quickVolRampSamples = (uint32_t)round(audioFreq / (double)FT2_QUICKRAMP_SAMPLES); 	for (int32_t bpm = MIN_BPM; bpm <= MAX_BPM; bpm++)	{		const int32_t i = bpm - MIN_BPM; // index for tables 		const double dBpmHz = bpm / 2.5;		const double dSamplesPerTick = audioFreq / dBpmHz; 		double dSamplesPerTickInt;		double dSamplesPerTickFrac = modf(dSamplesPerTick, &dSamplesPerTickInt); 		audio.samplesPerTickIntTab[i] = (uint32_t)dSamplesPerTickInt;		audio.samplesPerTickFracTab[i] = (uint64_t)((dSamplesPerTickFrac * BPM_FRAC_SCALE) + 0.5); // rounded 		// BPM Hz -> tick length for performance counter (syncing visuals to audio)		double dTimeInt;		double dTimeFrac = modf(editor.dPerfFreq / dBpmHz, &dTimeInt); 		audio.tickTimeIntTab[i] = (uint32_t)dTimeInt;		audio.tickTimeFracTab[i] = (uint64_t)((dTimeFrac * TICK_TIME_FRAC_SCALE) + 0.5); // rounded	}} // for piano in Instr. Ed. (values outside 0..95 can happen)int32_t getPianoKey(uint16_t period, int8_t finetune, int8_t relativeNote) {	assert(note2Period != NULL);	if (period > note2Period[0])		return -1; // outside left piano edge 	finetune = ((int8_t)finetune >> 3) + 16; // -128..127 -> 0..31 	int32_t hiPeriod = 10*12*16;	int32_t loPeriod = 0; 	for (int32_t i = 0; i < 7; i++)	{		const int32_t tmpPeriod = (((loPeriod + hiPeriod) >> 1) & ~15) + finetune; 		int32_t lookUp = tmpPeriod - 16;		if (lookUp < 0)			lookUp = 0; 		if (period >= note2Period[lookUp])			hiPeriod = (tmpPeriod - finetune) & ~15;		else			loPeriod = (tmpPeriod - finetune) & ~15;	} 	return (loPeriod >> 4) - relativeNote;} static void startTone(uint8_t note, uint8_t efx, uint8_t efxData, channel_t *ch){	if (note == NOTE_OFF)	{		keyOff(ch);		return;	} 	// if we came from Rxy (retrig), we didn't check note (Ton) yet	if (note == 0)	{		note = ch->noteNum;		if (note == 0)			return; // if still no note, exit from routine	} 	ch->noteNum = note; 	assert(ch->instrNum <= 130);	instr_t *ins = instr[ch->instrNum];	if (ins == NULL)		ins = instr[0]; // empty instruments use this placeholder instrument 	ch->instrPtr = ins;	ch->mute = ins->mute; 	if (note > 96) // non-FT2 security (should never happen because I clamp in the patt. loader now)		note = 96; 	ch->smpNum = ins->note2SampleLUT[note-1] & 0xF; // FT2 doesn't AND here, but let's do it for safety	sample_t *s = &ins->smp[ch->smpNum]; 	ch->smpPtr = s;

Lines 1–500 of 3391.

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