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

Dependencies:   microbit

fmpart.c

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

File content as of revision 0:c54d59d6fb78:

//	fmpart.c
#include	"fmtype.h"
#include	"fmpart.h"
#include	"fmsd1.h"
#include	"fmasgn.h"
#include	"fmtone.h"

//	Prototype
static Note* getNote(Part* _this);

//	getter
unsigned char Part_cc1(Part* _this){ return _this->_cc1; }
unsigned char Part_cc7(Part* _this){ return _this->_cc7; }
unsigned short Part_pb(Part* _this){ return _this->_pbvalue; }
unsigned char Part_toneNumber(Part* _this){ return _this->_toneNumber; }

void Part_init( Part* _this )
{
	int i;

	Asgn_init();
	Tone_init();

	_this->_topNt = 0;
	_this->_endNt = 0;
	_this->_cc1 = 0;
	_this->_cc7 = 100;
	_this->_cc64 = 0;
	_this->_pbvalue = 0x2000;
	_this->_toneNumber = 0;

	for ( i=0; i<MAX_NOTE_OBJECT; i++ ){
		Note_init(&_this->_note[i]);
		Note_setPart(&_this->_note[i], (void*)_this);
	}
}
void Part_note( Part* _this, unsigned char note, unsigned char velocity )
{
	if ( velocity != 0 ){
		//	keyon
		Note* newNt = getNote(_this);
		if ( Note_keyon(newNt,&_this->_tone,note,velocity) == true ){
			if ( _this->_endNt != FMNULL ){
				Note_setNextPtr( _this->_endNt,newNt );
				Note_setPrevPtr( newNt,_this->_endNt );
			}
			_this->_endNt = newNt;
			if ( _this->_topNt ==FMNULL ){
				_this->_topNt = newNt;
			}
		}
	}
	else {
		//	keyoff
		Note* nt = _this->_topNt;
		while( nt != 0 ){
			if (( Note_note(nt) == note ) &&
				( Note_isKeyOn(nt) == true ) &&
				( Note_isHeld(nt) == false )){
				if ( _this->_cc64 < 64 ){
					Note_keyoff(nt);
				}
				else {
					Note_setHold(nt,true);
				}
				break;
			}
			nt = Note_nextPtr(nt);
		}
	}
}
void Part_releaseNote( Part* _this, Note* nt )
{
	Note* prevPtr = Note_prevPtr(nt);
	if ( _this->_endNt == nt ){
		_this->_endNt = prevPtr;
	}
	if ( prevPtr != FMNULL ){
		Note_setNextPtr(prevPtr, Note_nextPtr(nt));
	}

	Note* nextPtr = Note_nextPtr(nt);
	if ( _this->_topNt == nt ){
		_this->_topNt = nextPtr;
	}
	if ( nextPtr != FMNULL ){
		Note_setPrevPtr(nextPtr, Note_prevPtr(nt));
	}
}
void Part_cc( Part* _this, unsigned char ccnum, unsigned char value )
{
	Note* nt = _this->_topNt;

	//	Limit
	if (value > 127) { value = 127; }

	switch (ccnum) {
		case 1: {
			_this->_cc1 = value;
			while ( nt != FMNULL ) {
				Note_chgVibDpt(nt);
				nt = Note_nextPtr(nt);
			}
			break;
		}
		case 7: {
			_this->_cc7 = value;
			writeSingle( REG_MASTER_VOL, (value<<1)&0xfc );
			break;
		}
		case 64: {
			_this->_cc64 = value;
			if ( value < 64 ){
				while ( nt != FMNULL ) {
					if ( Note_isHeld(nt) == true ){
						Note_keyoff(nt);
					}
					nt = Note_nextPtr(nt);
				}
			}
			break;
		}
		default: break;
	}
}
void Part_pc( Part* _this, unsigned char num )
{
	Note* nt = _this->_topNt;
	Note* nextNt;

	//	Damp
	while ( nt != FMNULL ) {
		nextNt = Note_nextPtr(nt);
		Note_damp(nt);
		nt = nextNt;
	}

	_this->_toneNumber = num;
}
void Part_pbend( Part* _this, unsigned char lsb, unsigned char msb )
{
	Note* nt = _this->_topNt;
	_this->_pbvalue = (msb<<7)|(lsb&0x7f);
	while ( nt != FMNULL ) {
		Note_chgPit(nt);
		nt = Note_nextPtr(nt);
	}
}
static Note* getNote( Part* _this )
{
	int	i;
	Note* newNt = 0;
	for ( i=0; i<MAX_NOTE_OBJECT; i++ ){
		newNt = &(_this->_note[i]);
		if ( Note_isInUse(newNt) ==  false ){
			return newNt;
		}
	}
	//	if nothing
	newNt = _this->_topNt;
	Note_damp(newNt);
	return newNt;
}