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

Dependencies:   microbit

Committer:
hasebems
Date:
Fri Jan 05 22:58:49 2018 +0000
Revision:
0:c54d59d6fb78
???????????????

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hasebems 0:c54d59d6fb78 1 // fmtone.c
hasebems 0:c54d59d6fb78 2 #include "fmtype.h"
hasebems 0:c54d59d6fb78 3 #include "fmtone.h"
hasebems 0:c54d59d6fb78 4 #include "fmsd1.h"
hasebems 0:c54d59d6fb78 5
hasebems 0:c54d59d6fb78 6 #define IMMUTABLE_TONE_MAX 8
hasebems 0:c54d59d6fb78 7 #define MUTABLE_TONE_MAX IMMUTABLE_TONE_MAX
hasebems 0:c54d59d6fb78 8 #define AVAILABLE_TONE_NUMBER (IMMUTABLE_TONE_MAX+MUTABLE_TONE_MAX)
hasebems 0:c54d59d6fb78 9 #define MAX_EXCLUSIVE_HEADER_SIZE 5
hasebems 0:c54d59d6fb78 10
hasebems 0:c54d59d6fb78 11 #define MAX_ELEMENT_PRM 2
hasebems 0:c54d59d6fb78 12 #define OPERATOR_PRM_REG_SZ 7
hasebems 0:c54d59d6fb78 13 #define MAX_TONE_PRM_SZ (MAX_FM_OPERATOR*OPERATOR_PRM_REG_SZ + MAX_ELEMENT_PRM)
hasebems 0:c54d59d6fb78 14
hasebems 0:c54d59d6fb78 15 typedef enum {
hasebems 0:c54d59d6fb78 16 WAIT_DATA,
hasebems 0:c54d59d6fb78 17 DURING_SETTING,
hasebems 0:c54d59d6fb78 18 SET_STATE_MAX
hasebems 0:c54d59d6fb78 19 } SET_STATE;
hasebems 0:c54d59d6fb78 20
hasebems 0:c54d59d6fb78 21 // Variable
hasebems 0:c54d59d6fb78 22 static SET_STATE _toneSetState;
hasebems 0:c54d59d6fb78 23 static int _tprmIndex;
hasebems 0:c54d59d6fb78 24 static ToneData _userTone[MUTABLE_TONE_MAX];
hasebems 0:c54d59d6fb78 25 static const ToneData TPRM[IMMUTABLE_TONE_MAX] = {
hasebems 0:c54d59d6fb78 26
hasebems 0:c54d59d6fb78 27 { // GrandPiano
hasebems 0:c54d59d6fb78 28 0x0b, // VoiceCommon
hasebems 0:c54d59d6fb78 29 { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS
hasebems 0:c54d59d6fb78 30 {0x01,0x0f,0x07,0x00,0x06,0x0f,0x27,0x00,0x01,0x08}, // op1
hasebems 0:c54d59d6fb78 31 {0x07,0x0e,0x03,0x02,0x03,0x02,0x28,0x00,0x05,0x00}, // op2
hasebems 0:c54d59d6fb78 32 {0x00,0x0d,0x01,0x01,0x04,0x03,0x22,0x01,0x01,0x00}, // op3
hasebems 0:c54d59d6fb78 33 {0x06,0x0d,0x02,0x02,0x06,0x04,0x00,0x01,0x01,0x00} // op4
hasebems 0:c54d59d6fb78 34 }
hasebems 0:c54d59d6fb78 35 },
hasebems 0:c54d59d6fb78 36 { // E.Piano
hasebems 0:c54d59d6fb78 37 0x0d, // VoiceCommon
hasebems 0:c54d59d6fb78 38 { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS
hasebems 0:c54d59d6fb78 39 {0x54,0x0f,0x04,0x05,0x0c,0x0b,0x23,0x44,0x07,0x12}, // op1
hasebems 0:c54d59d6fb78 40 {0x02,0x0f,0x02,0x01,0x08,0x0f,0x04,0x45,0x01,0x00}, // op2
hasebems 0:c54d59d6fb78 41 {0x25,0x0f,0x00,0x01,0x0b,0x01,0x12,0x44,0x01,0x00}, // op3
hasebems 0:c54d59d6fb78 42 {0x04,0x0f,0x02,0x01,0x07,0x0f,0x04,0x41,0x01,0x00} // op4
hasebems 0:c54d59d6fb78 43 }
hasebems 0:c54d59d6fb78 44 },
hasebems 0:c54d59d6fb78 45 { // TenorSax
hasebems 0:c54d59d6fb78 46 0x0d, // VoiceCommon
hasebems 0:c54d59d6fb78 47 { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS
hasebems 0:c54d59d6fb78 48 {0x36,0x07,0x03,0x00,0x00,0x00,0x05,0x44,0x01,0x01}, // op1
hasebems 0:c54d59d6fb78 49 {0x00,0x07,0x02,0x00,0x09,0x00,0x0f,0x43,0x01,0x08}, // op2
hasebems 0:c54d59d6fb78 50 {0x36,0x07,0x03,0x00,0x00,0x00,0x08,0x44,0x01,0x09}, // op3
hasebems 0:c54d59d6fb78 51 {0x02,0x07,0x02,0x00,0x09,0x00,0x0d,0x43,0x01,0x00} // op4
hasebems 0:c54d59d6fb78 52 }
hasebems 0:c54d59d6fb78 53 },
hasebems 0:c54d59d6fb78 54 { // PickBass
hasebems 0:c54d59d6fb78 55 0x0b, // VoiceCommon
hasebems 0:c54d59d6fb78 56 { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS
hasebems 0:c54d59d6fb78 57 {0x56,0x0f,0x07,0x02,0x03,0x01,0x13,0x44,0x01,0x00}, // op1
hasebems 0:c54d59d6fb78 58 {0x04,0x0c,0x0b,0x04,0x06,0x07,0x15,0x44,0x07,0x00}, // op2
hasebems 0:c54d59d6fb78 59 {0x06,0x0f,0x09,0x02,0x06,0x02,0x17,0x44,0x02,0x00}, // op3
hasebems 0:c54d59d6fb78 60 {0x04,0x0b,0x02,0x06,0x08,0x06,0x00,0x44,0x01,0x00} // op4
hasebems 0:c54d59d6fb78 61 }
hasebems 0:c54d59d6fb78 62 },
hasebems 0:c54d59d6fb78 63 { // TnklBell
hasebems 0:c54d59d6fb78 64 0x0d, // VoiceCommon
hasebems 0:c54d59d6fb78 65 { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS
hasebems 0:c54d59d6fb78 66 {0x31,0x0f,0x06,0x03,0x04,0x05,0x10,0x44,0x0e,0x00}, // op1
hasebems 0:c54d59d6fb78 67 {0x02,0x0c,0x06,0x07,0x06,0x0e,0x0b,0x44,0x02,0x00}, // op2
hasebems 0:c54d59d6fb78 68 {0x00,0x0c,0x06,0x02,0x02,0x05,0x1e,0x44,0x77,0x01}, // op3
hasebems 0:c54d59d6fb78 69 {0x00,0x0f,0x05,0x04,0x05,0x0d,0x01,0x54,0x06,0x00} // op4
hasebems 0:c54d59d6fb78 70 }
hasebems 0:c54d59d6fb78 71 },
hasebems 0:c54d59d6fb78 72 { // NewAgePd
hasebems 0:c54d59d6fb78 73 0x0d, // VoiceCommon
hasebems 0:c54d59d6fb78 74 { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS
hasebems 0:c54d59d6fb78 75 {0x54,0x0f,0x0f,0x03,0x03,0x00,0x26,0x44,0x07,0x01}, // op1
hasebems 0:c54d59d6fb78 76 {0x02,0x0f,0x07,0x04,0x04,0x00,0x0b,0x44,0x05,0x00}, // op2
hasebems 0:c54d59d6fb78 77 {0x62,0x06,0x01,0x00,0x01,0x00,0x18,0x03,0x71,0x01}, // op3
hasebems 0:c54d59d6fb78 78 {0x02,0x08,0x01,0x00,0x05,0x01,0x00,0x03,0x01,0x00} // op4
hasebems 0:c54d59d6fb78 79 }
hasebems 0:c54d59d6fb78 80 },
hasebems 0:c54d59d6fb78 81 { // Rim Shot
hasebems 0:c54d59d6fb78 82 0x0d, // VoiceCommon
hasebems 0:c54d59d6fb78 83 { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS
hasebems 0:c54d59d6fb78 84 {0x7c,0x0f,0x00,0x05,0x05,0x00,0x05,0x44,0x0c,0x02}, // op1
hasebems 0:c54d59d6fb78 85 {0x0c,0x0f,0x07,0x07,0x07,0x07,0x00,0x44,0x0b,0x00}, // op2
hasebems 0:c54d59d6fb78 86 {0x08,0x0f,0x0a,0x06,0x06,0x08,0x00,0x44,0x0c,0x00}, // op3
hasebems 0:c54d59d6fb78 87 {0x08,0x0f,0x07,0x07,0x07,0x07,0x00,0x44,0x07,0x02} // op4
hasebems 0:c54d59d6fb78 88 }
hasebems 0:c54d59d6fb78 89 },
hasebems 0:c54d59d6fb78 90 { // Castanet
hasebems 0:c54d59d6fb78 91 0x0d, // VoiceCommon
hasebems 0:c54d59d6fb78 92 { // KC | AR | DR | SR | RR | SL | TL | VB | PT | WS
hasebems 0:c54d59d6fb78 93 {0x68,0x0f,0x07,0x05,0x09,0x0f,0x02,0x44,0x07,0x01}, // op1
hasebems 0:c54d59d6fb78 94 {0x0c,0x0a,0x08,0x05,0x0f,0x0f,0x00,0x44,0x05,0x06}, // op2
hasebems 0:c54d59d6fb78 95 {0x08,0x0f,0x05,0x06,0x05,0x00,0x27,0x44,0x02,0x05}, // op3
hasebems 0:c54d59d6fb78 96 {0x08,0x0c,0x0a,0x09,0x09,0x0a,0x14,0x44,0x05,0x00} // op4
hasebems 0:c54d59d6fb78 97 }
hasebems 0:c54d59d6fb78 98 }
hasebems 0:c54d59d6fb78 99 };
hasebems 0:c54d59d6fb78 100 const unsigned char tExcCheck[MAX_EXCLUSIVE_HEADER_SIZE] = {
hasebems 0:c54d59d6fb78 101 0x43, // Exclusive:1, Yamaha ID
hasebems 0:c54d59d6fb78 102 0x7f, // Exclusive:2, Make/DIY ID1
hasebems 0:c54d59d6fb78 103 0x02, // Exclusive:3, Make/DIY ID2
hasebems 0:c54d59d6fb78 104 0x00, // Exclusive:4, YMF825 ID
hasebems 0:c54d59d6fb78 105 0x00 // Exclusive:5, reserved
hasebems 0:c54d59d6fb78 106 };
hasebems 0:c54d59d6fb78 107 void Tone_init( void )
hasebems 0:c54d59d6fb78 108 {
hasebems 0:c54d59d6fb78 109 int i;
hasebems 0:c54d59d6fb78 110 for ( i=0; i<MUTABLE_TONE_MAX; i++ ){
hasebems 0:c54d59d6fb78 111 _userTone[i] = TPRM[i];
hasebems 0:c54d59d6fb78 112 }
hasebems 0:c54d59d6fb78 113 _toneSetState = WAIT_DATA;
hasebems 0:c54d59d6fb78 114 _tprmIndex = 0;
hasebems 0:c54d59d6fb78 115
hasebems 0:c54d59d6fb78 116 Tone_sendTone();
hasebems 0:c54d59d6fb78 117 }
hasebems 0:c54d59d6fb78 118 void Tone_setToneExc( unsigned char data, int excNum )
hasebems 0:c54d59d6fb78 119 {
hasebems 0:c54d59d6fb78 120 if ( _toneSetState == WAIT_DATA ){
hasebems 0:c54d59d6fb78 121 if (( excNum == 1 ) && ( data == tExcCheck[0] )){
hasebems 0:c54d59d6fb78 122 _toneSetState = DURING_SETTING;
hasebems 0:c54d59d6fb78 123 }
hasebems 0:c54d59d6fb78 124 }
hasebems 0:c54d59d6fb78 125 else if ( _toneSetState == DURING_SETTING ){
hasebems 0:c54d59d6fb78 126 if ( excNum-1 < MAX_EXCLUSIVE_HEADER_SIZE ){
hasebems 0:c54d59d6fb78 127 if ( data != tExcCheck[excNum-1] ){ _toneSetState = WAIT_DATA; }
hasebems 0:c54d59d6fb78 128 }
hasebems 0:c54d59d6fb78 129 else if ( excNum == 6 ){
hasebems 0:c54d59d6fb78 130 if ( data < MUTABLE_TONE_MAX ){ _tprmIndex = data; }
hasebems 0:c54d59d6fb78 131 else { _toneSetState = WAIT_DATA; }
hasebems 0:c54d59d6fb78 132 }
hasebems 0:c54d59d6fb78 133 else if ( excNum == 7 ){
hasebems 0:c54d59d6fb78 134 _userTone[_tprmIndex].voiceCommon = data;
hasebems 0:c54d59d6fb78 135 }
hasebems 0:c54d59d6fb78 136 else if ( excNum < 48 ){
hasebems 0:c54d59d6fb78 137 _userTone[_tprmIndex].opPrm[(excNum-8)/MAX_OPERATOR_PRM][(excNum-8)%MAX_OPERATOR_PRM] = data;
hasebems 0:c54d59d6fb78 138 }
hasebems 0:c54d59d6fb78 139 else { _toneSetState = WAIT_DATA; }
hasebems 0:c54d59d6fb78 140 }
hasebems 0:c54d59d6fb78 141 }
hasebems 0:c54d59d6fb78 142 void Tone_sendTone( void )
hasebems 0:c54d59d6fb78 143 {
hasebems 0:c54d59d6fb78 144 int i,j;
hasebems 0:c54d59d6fb78 145 unsigned char regImage[MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 1 + 4]; // 485
hasebems 0:c54d59d6fb78 146
hasebems 0:c54d59d6fb78 147 // top
hasebems 0:c54d59d6fb78 148 regImage[0] = 0x80 + AVAILABLE_TONE_NUMBER;
hasebems 0:c54d59d6fb78 149
hasebems 0:c54d59d6fb78 150 for ( i=0; i<AVAILABLE_TONE_NUMBER; i++ ){
hasebems 0:c54d59d6fb78 151 unsigned char* riPtr = &regImage[MAX_TONE_PRM_SZ*i + 1];
hasebems 0:c54d59d6fb78 152
hasebems 0:c54d59d6fb78 153 ToneData* td;
hasebems 0:c54d59d6fb78 154 if ( i < IMMUTABLE_TONE_MAX ){
hasebems 0:c54d59d6fb78 155 td = (ToneData*)&(TPRM[i]);
hasebems 0:c54d59d6fb78 156 }
hasebems 0:c54d59d6fb78 157 else {
hasebems 0:c54d59d6fb78 158 td = (ToneData*)&(_userTone[i-IMMUTABLE_TONE_MAX]);
hasebems 0:c54d59d6fb78 159 }
hasebems 0:c54d59d6fb78 160
hasebems 0:c54d59d6fb78 161 riPtr[0] = (td->voiceCommon & 0x60)>>5;
hasebems 0:c54d59d6fb78 162 riPtr[1] = ((td->voiceCommon & 0x18)<<3) | (td->voiceCommon & 0x07);
hasebems 0:c54d59d6fb78 163
hasebems 0:c54d59d6fb78 164 for ( j=0; j<MAX_FM_OPERATOR; j++ ){
hasebems 0:c54d59d6fb78 165 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);
hasebems 0:c54d59d6fb78 166 riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+1] = (td->opPrm[j][4] << 4) | td->opPrm[j][2];
hasebems 0:c54d59d6fb78 167 riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+2] = (td->opPrm[j][1] << 4) | td->opPrm[j][5];
hasebems 0:c54d59d6fb78 168 riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+3] = (td->opPrm[j][6] << 2) | (td->opPrm[j][0] & 0x03);
hasebems 0:c54d59d6fb78 169 riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+4] = td->opPrm[j][7];
hasebems 0:c54d59d6fb78 170 riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+5] = ((td->opPrm[j][8] & 0x0f) << 4) | ((td->opPrm[j][8] & 0xf0) >> 4);
hasebems 0:c54d59d6fb78 171 riPtr[MAX_ELEMENT_PRM+OPERATOR_PRM_REG_SZ*j+6] = (td->opPrm[j][9] << 3) | ((td->opPrm[j][0] & 0x70) >> 4);
hasebems 0:c54d59d6fb78 172 }
hasebems 0:c54d59d6fb78 173 }
hasebems 0:c54d59d6fb78 174
hasebems 0:c54d59d6fb78 175 // end
hasebems 0:c54d59d6fb78 176 regImage[MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 1] = 0x80;
hasebems 0:c54d59d6fb78 177 regImage[MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 2] = 0x03;
hasebems 0:c54d59d6fb78 178 regImage[MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 3] = 0x81;
hasebems 0:c54d59d6fb78 179 regImage[MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 4] = 0x80;
hasebems 0:c54d59d6fb78 180
hasebems 0:c54d59d6fb78 181 // Soft Reset
hasebems 0:c54d59d6fb78 182 // writeSingle(26,0xa3);
hasebems 0:c54d59d6fb78 183 // writeSingle(26,0x00);
hasebems 0:c54d59d6fb78 184 writeSingle(8,0xf6);
hasebems 0:c54d59d6fb78 185 delayMs(1);
hasebems 0:c54d59d6fb78 186 writeSingle(8,0x00);
hasebems 0:c54d59d6fb78 187
hasebems 0:c54d59d6fb78 188 writeBurst( 7, regImage, MAX_TONE_PRM_SZ*AVAILABLE_TONE_NUMBER + 5 );
hasebems 0:c54d59d6fb78 189 }