This program generates sound by using FM tone generator YMF825 via SPI.
Diff: fmtone.c
- Revision:
- 0:c54d59d6fb78
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fmtone.c Fri Jan 05 22:58:49 2018 +0000 @@ -0,0 +1,189 @@ +// fmtone.c +#include "fmtype.h" +#include "fmtone.h" +#include "fmsd1.h" + +#define IMMUTABLE_TONE_MAX 8 +#define MUTABLE_TONE_MAX IMMUTABLE_TONE_MAX +#define AVAILABLE_TONE_NUMBER (IMMUTABLE_TONE_MAX+MUTABLE_TONE_MAX) +#define MAX_EXCLUSIVE_HEADER_SIZE 5 + +#define MAX_ELEMENT_PRM 2 +#define OPERATOR_PRM_REG_SZ 7 +#define MAX_TONE_PRM_SZ (MAX_FM_OPERATOR*OPERATOR_PRM_REG_SZ + MAX_ELEMENT_PRM) + +typedef enum { + WAIT_DATA, + DURING_SETTING, + SET_STATE_MAX +} SET_STATE; + +// Variable +static SET_STATE _toneSetState; +static int _tprmIndex; +static ToneData _userTone[MUTABLE_TONE_MAX]; +static const ToneData TPRM[IMMUTABLE_TONE_MAX] = { + + { // GrandPiano + 0x0b, // VoiceCommon + { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS + {0x01,0x0f,0x07,0x00,0x06,0x0f,0x27,0x00,0x01,0x08}, // op1 + {0x07,0x0e,0x03,0x02,0x03,0x02,0x28,0x00,0x05,0x00}, // op2 + {0x00,0x0d,0x01,0x01,0x04,0x03,0x22,0x01,0x01,0x00}, // op3 + {0x06,0x0d,0x02,0x02,0x06,0x04,0x00,0x01,0x01,0x00} // op4 + } + }, + { // E.Piano + 0x0d, // VoiceCommon + { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS + {0x54,0x0f,0x04,0x05,0x0c,0x0b,0x23,0x44,0x07,0x12}, // op1 + {0x02,0x0f,0x02,0x01,0x08,0x0f,0x04,0x45,0x01,0x00}, // op2 + {0x25,0x0f,0x00,0x01,0x0b,0x01,0x12,0x44,0x01,0x00}, // op3 + {0x04,0x0f,0x02,0x01,0x07,0x0f,0x04,0x41,0x01,0x00} // op4 + } + }, + { // TenorSax + 0x0d, // VoiceCommon + { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS + {0x36,0x07,0x03,0x00,0x00,0x00,0x05,0x44,0x01,0x01}, // op1 + {0x00,0x07,0x02,0x00,0x09,0x00,0x0f,0x43,0x01,0x08}, // op2 + {0x36,0x07,0x03,0x00,0x00,0x00,0x08,0x44,0x01,0x09}, // op3 + {0x02,0x07,0x02,0x00,0x09,0x00,0x0d,0x43,0x01,0x00} // op4 + } + }, + { // PickBass + 0x0b, // VoiceCommon + { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS + {0x56,0x0f,0x07,0x02,0x03,0x01,0x13,0x44,0x01,0x00}, // op1 + {0x04,0x0c,0x0b,0x04,0x06,0x07,0x15,0x44,0x07,0x00}, // op2 + {0x06,0x0f,0x09,0x02,0x06,0x02,0x17,0x44,0x02,0x00}, // op3 + {0x04,0x0b,0x02,0x06,0x08,0x06,0x00,0x44,0x01,0x00} // op4 + } + }, + { // TnklBell + 0x0d, // VoiceCommon + { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS + {0x31,0x0f,0x06,0x03,0x04,0x05,0x10,0x44,0x0e,0x00}, // op1 + {0x02,0x0c,0x06,0x07,0x06,0x0e,0x0b,0x44,0x02,0x00}, // op2 + {0x00,0x0c,0x06,0x02,0x02,0x05,0x1e,0x44,0x77,0x01}, // op3 + {0x00,0x0f,0x05,0x04,0x05,0x0d,0x01,0x54,0x06,0x00} // op4 + } + }, + { // NewAgePd + 0x0d, // VoiceCommon + { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS + {0x54,0x0f,0x0f,0x03,0x03,0x00,0x26,0x44,0x07,0x01}, // op1 + {0x02,0x0f,0x07,0x04,0x04,0x00,0x0b,0x44,0x05,0x00}, // op2 + {0x62,0x06,0x01,0x00,0x01,0x00,0x18,0x03,0x71,0x01}, // op3 + {0x02,0x08,0x01,0x00,0x05,0x01,0x00,0x03,0x01,0x00} // op4 + } + }, + { // Rim Shot + 0x0d, // VoiceCommon + { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS + {0x7c,0x0f,0x00,0x05,0x05,0x00,0x05,0x44,0x0c,0x02}, // op1 + {0x0c,0x0f,0x07,0x07,0x07,0x07,0x00,0x44,0x0b,0x00}, // op2 + {0x08,0x0f,0x0a,0x06,0x06,0x08,0x00,0x44,0x0c,0x00}, // op3 + {0x08,0x0f,0x07,0x07,0x07,0x07,0x00,0x44,0x07,0x02} // op4 + } + }, + { // Castanet + 0x0d, // VoiceCommon + { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS + {0x68,0x0f,0x07,0x05,0x09,0x0f,0x02,0x44,0x07,0x01}, // op1 + {0x0c,0x0a,0x08,0x05,0x0f,0x0f,0x00,0x44,0x05,0x06}, // op2 + {0x08,0x0f,0x05,0x06,0x05,0x00,0x27,0x44,0x02,0x05}, // op3 + {0x08,0x0c,0x0a,0x09,0x09,0x0a,0x14,0x44,0x05,0x00} // op4 + } + } +}; +const unsigned char tExcCheck[MAX_EXCLUSIVE_HEADER_SIZE] = { + 0x43, // Exclusive:1, Yamaha ID + 0x7f, // Exclusive:2, Make/DIY ID1 + 0x02, // Exclusive:3, Make/DIY ID2 + 0x00, // Exclusive:4, YMF825 ID + 0x00 // Exclusive:5, reserved +}; +void Tone_init( void ) +{ + int i; + for ( i=0; i<MUTABLE_TONE_MAX; i++ ){ + _userTone[i] = TPRM[i]; + } + _toneSetState = WAIT_DATA; + _tprmIndex = 0; + + Tone_sendTone(); +} +void Tone_setToneExc( unsigned char data, int excNum ) +{ + if ( _toneSetState == WAIT_DATA ){ + if (( excNum == 1 ) && ( data == tExcCheck[0] )){ + _toneSetState = DURING_SETTING; + } + } + else if ( _toneSetState == DURING_SETTING ){ + if ( excNum-1 < MAX_EXCLUSIVE_HEADER_SIZE ){ + if ( data != tExcCheck[excNum-1] ){ _toneSetState = WAIT_DATA; } + } + else if ( excNum == 6 ){ + if ( data < MUTABLE_TONE_MAX ){ _tprmIndex = data; } + else { _toneSetState = WAIT_DATA; } + } + else if ( excNum == 7 ){ + _userTone[_tprmIndex].voiceCommon = data; + } + else if ( excNum < 48 ){ + _userTone[_tprmIndex].opPrm[(excNum-8)/MAX_OPERATOR_PRM][(excNum-8)%MAX_OPERATOR_PRM] = data; + } + else { _toneSetState = WAIT_DATA; } + } +} +void Tone_sendTone( void ) +{ + int i,j; + unsigned char regImage[MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 1 + 4]; // 485 + + // top + regImage[0] = 0x80 + AVAILABLE_TONE_NUMBER; + + for ( i=0; i<AVAILABLE_TONE_NUMBER; i++ ){ + unsigned char* riPtr = ®Image[MAX_TONE_PRM_SZ*i + 1]; + + ToneData* td; + if ( i < IMMUTABLE_TONE_MAX ){ + td = (ToneData*)&(TPRM[i]); + } + else { + td = (ToneData*)&(_userTone[i-IMMUTABLE_TONE_MAX]); + } + + riPtr[0] = (td->voiceCommon & 0x60)>>5; + riPtr[1] = ((td->voiceCommon & 0x18)<<3) | (td->voiceCommon & 0x07); + + for ( j=0; j<MAX_FM_OPERATOR; j++ ){ + riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+0] = (td->opPrm[j][3] << 4) | (td->opPrm[j][0] & 0x08) | ((td->opPrm[j][0] & 0x04)>>2); + riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+1] = (td->opPrm[j][4] << 4) | td->opPrm[j][2]; + riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+2] = (td->opPrm[j][1] << 4) | td->opPrm[j][5]; + riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+3] = (td->opPrm[j][6] << 2) | (td->opPrm[j][0] & 0x03); + riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+4] = td->opPrm[j][7]; + riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+5] = ((td->opPrm[j][8] & 0x0f) << 4) | ((td->opPrm[j][8] & 0xf0) >> 4); + riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+6] = (td->opPrm[j][9] << 3) | ((td->opPrm[j][0] & 0x70) >> 4); + } + } + + // end + regImage[MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 1] = 0x80; + regImage[MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 2] = 0x03; + regImage[MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 3] = 0x81; + regImage[MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 4] = 0x80; + + // Soft Reset +// writeSingle(26,0xa3); +// writeSingle(26,0x00); + writeSingle(8,0xf6); + delayMs(1); + writeSingle(8,0x00); + + writeBurst( 7, regImage, MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 5 ); +}