This program generates sound by using FM tone generator YMF825 via SPI.

Dependencies:   microbit

fmvoice.c

Committer:
hasebems
Date:
2018-01-05
Revision:
0:c54d59d6fb78

File content as of revision 0:c54d59d6fb78:

//	fmvoice.c
#include	"fmtype.h"
#include	"fmvoice.h"
#include	"fmtone.h"
#include	"fmnote.h"
#include	"fmsd1.h"
#include	"fmpart.h"

//	setter
void Fmvoice_setVoiceNum( Fmvoice* _this, unsigned char vn ){ _this->_vnum = vn; }
void Fmvoice_setNextVc( Fmvoice* _this, Fmvoice* vc ){ _this->_nextVc = vc; }

//	getter
unsigned char Fmvoice_vnum( Fmvoice* _this ){ return _this->_vnum; }
bool Fmvoice_isKeyon( Fmvoice* _this ){ return _this->_keyon;}
Fmvoice* Fmvoice_nextVc( Fmvoice* _this ){ return _this->_nextVc; }

void Fmvoice_init( Fmvoice* _this )
{
	_this->_keyon = (false);
	_this->_nextVc = FMNULL;
}
void Fmvoice_keyon( Fmvoice* _this, void* nt, void* pt, void* tn, unsigned char note, unsigned char vel )
{
	Part* ptp = (Part*)pt;

	_this->_parent = nt;
	_this->_keyon = true;
	_this->_nextVc = FMNULL;

	//	set voice number
	writeSingle( 11, _this->_vnum );

	//	Damp
	writeSingle( REG_TOP_ADRS+REG_CTRL, 0x30 );

	//	FNUM,BLOCK
	Fmvoice_setBasicPit( _this, note );

	//	Vol
	writeSingle( REG_TOP_ADRS+REG_VOL, vel&0xfc );

	//	ChVol
	writeSingle( REG_TOP_ADRS+REG_CH_VOL, 0x71 );

	//	XVB
	Fmvoice_chgVibDpt(_this, Part_cc1(ptp));

	//	INT, FRAC
	Fmvoice_chgPit(_this, Part_pb(ptp));

	//	KeyOn, ToneNum
	writeSingle( REG_TOP_ADRS+REG_CTRL, 0x40 + Part_toneNumber(ptp) );
}
void Fmvoice_keyoff( Fmvoice* _this )
{
	_this->_keyon = false;
	writeSingle( 11, _this->_vnum );
	writeSingle( REG_TOP_ADRS+REG_CTRL, 0 );
}
void Fmvoice_release( Fmvoice* _this )
{
	_this->_keyon = false;
	if ( _this->_parent != FMNULL ){
		Note* nt = (Note*)_this->_parent;
		Note_releaseVc(nt,_this);
	}
	_this->_nextVc = FMNULL;

	writeSingle( 11, _this->_vnum );
	writeSingle( REG_TOP_ADRS+REG_CTRL, 0x30 );
}
void Fmvoice_chgPit( Fmvoice* _this, unsigned short pb )
{
	static const unsigned short tPitTbl[256] = {
	256,257,259,260,262,263,264,266,267,269,270,272,273,275,276,278,
	279,281,282,284,285,287,288,290,292,293,295,296,298,300,301,303,
	304,306,308,309,311,313,314,316,318,320,321,323,325,327,328,330,
	332,334,336,337,339,341,343,345,347,349,350,352,354,356,358,360,
	362,364,366,368,370,372,374,376,378,380,382,384,386,388,391,393,
	395,397,399,401,403,406,408,410,412,415,417,419,421,424,426,428,
	431,433,435,438,440,442,445,447,450,452,454,457,459,462,464,467,
	470,472,475,477,480,482,485,488,490,493,496,498,501,504,506,509,
	512,515,518,520,523,526,529,532,535,538,540,543,546,549,552,555,
	558,561,564,567,571,574,577,580,583,586,589,593,596,599,602,606,
	609,612,616,619,622,626,629,632,636,639,643,646,650,653,657,660,
	664,668,671,675,679,682,686,690,693,697,701,705,709,712,716,720,
	724,728,732,736,740,744,748,752,756,760,764,769,773,777,781,785,
	790,794,798,803,807,811,816,820,825,829,834,838,843,847,852,856,
	861,866,870,875,880,885,890,894,899,904,909,914,919,924,929,934,
	939,944,949,954,960,965,970,975,981,986,991,997,1002,1007,1013,1023	};

	unsigned char reg[2];
	unsigned char pit = pb/64;
	reg[1] = (unsigned char)((tPitTbl[pit]<<1) & 0x007e);
	reg[0] = (unsigned char)(((tPitTbl[pit]<<2) & 0x1f00)>>8);

	writeSingle( 11, _this->_vnum );
	writeSingle( REG_TOP_ADRS+REG_INT, reg[0] );
	writeSingle( REG_TOP_ADRS+REG_FRC, reg[1] );
}
void Fmvoice_chgVibDpt( Fmvoice* _this, unsigned char vibDpt )
{
	vibDpt = vibDpt >>4;
	if ( vibDpt == 0 ){ vibDpt = 1;}
	writeSingle( 11, _this->_vnum );
	writeSingle( REG_TOP_ADRS+REG_XVB, vibDpt );
}
void Fmvoice_setBasicPit( Fmvoice* _this, unsigned char note )
{
	static const unsigned short tFreq[240] = {
	347,348,349,350,351,352,353,354,355,356,	357,358,359,360,361,362,363,365,366,367,
	368,369,370,371,372,373,374,375,376,377,	378,380,381,382,383,384,385,386,387,388,
	390,391,392,393,394,395,396,397,399,400,	401,402,403,404,406,407,408,409,410,412,
	413,414,415,416,417,419,420,421,422,424,	425,426,427,428,430,431,432,433,435,436,
	437,439,440,441,442,444,445,446,447,449,	450,451,453,454,455,457,458,459,461,462,
	463,465,466,467,469,470,471,473,474,475,	477,478,480,481,482,484,485,487,488,489,
	491,492,494,495,496,498,499,501,502,504,	505,507,508,510,511,513,514,515,517,518,
	520,521,523,524,526,528,529,531,532,534,	535,537,538,540,541,543,545,546,548,549,
	551,552,554,556,557,559,561,562,564,565,	567,569,570,572,574,575,577,579,580,582,
	584,585,587,589,590,592,594,596,597,599,	601,602,604,606,608,609,611,613,615,617,
	618,620,622,624,626,627,629,631,633,635,	636,638,640,642,644,646,648,649,651,653,
	655,657,659,661,663,665,667,668,670,672,	674,676,678,680,682,684,686,688,690,692};

	signed short realNote = note;
	while ( realNote > 128 ){ realNote -= 12;}
	while ( realNote < 0 ){ realNote += 12;}

	int tblIndex = (realNote % 12) * 20;

	unsigned char reg[2];
	unsigned short fr = tFreq[tblIndex];
	unsigned char oct = realNote/12 - 1;
	reg[0] = (unsigned char)(((fr & 0x0380)>>4) | oct);
	reg[1] = (unsigned char)(fr & 0x007f);

	writeSingle( 11, _this->_vnum );
	writeSingle( REG_TOP_ADRS+REG_BLK, reg[0] );
	writeSingle( REG_TOP_ADRS+REG_FNUM, reg[1] );
}