Simple FM Sound Synthesis with touch screen and accelerometer control, based on STM32F746G-DISCO
Dependencies: ADXL345 AUDIO_DISCO_F746NG BSP_DISCO_F746NG LCD_DISCO_F746NG SDRAM_DISCO_F746NG TS_DISCO_F746NG mbed-dev
Fork of Workshop_5 by
sinth.cpp@3:cd1cb0003a3d, 2017-01-01 (annotated)
- Committer:
- stefanofasciani
- Date:
- Sun Jan 01 13:54:19 2017 +0000
- Revision:
- 3:cd1cb0003a3d
- Parent:
- 2:a1330350c32e
First Commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
stefanofasciani | 2:a1330350c32e | 1 | |
stefanofasciani | 2:a1330350c32e | 2 | // Author: Stefano Fasciani - stefanofasciani@stefanofasciani.com |
stefanofasciani | 2:a1330350c32e | 3 | // Date 7/8/2016 |
stefanofasciani | 2:a1330350c32e | 4 | // FM Sinth for DISCO_F746NG and ADXL345 |
stefanofasciani | 2:a1330350c32e | 5 | |
stefanofasciani | 2:a1330350c32e | 6 | #include "sinth.h" |
stefanofasciani | 2:a1330350c32e | 7 | |
stefanofasciani | 2:a1330350c32e | 8 | float table[TABLE_SIZE]; |
stefanofasciani | 2:a1330350c32e | 9 | int16_t out_buffer[AUDIO_BLOCK_SIZE*2]; |
stefanofasciani | 2:a1330350c32e | 10 | float osc_buf[AUDIO_BLOCK_SIZE/2]; |
stefanofasciani | 2:a1330350c32e | 11 | __IO uint32_t audio_out_buffer_state = BUFFER_OFFSET_NONE; |
stefanofasciani | 2:a1330350c32e | 12 | float idx_1 = 0; |
stefanofasciani | 2:a1330350c32e | 13 | float idx_2 = 0; |
stefanofasciani | 2:a1330350c32e | 14 | float filt_old_samp = 0; |
stefanofasciani | 2:a1330350c32e | 15 | static float frqTL = 0.04266666666667; |
stefanofasciani | 2:a1330350c32e | 16 | static float two_pi_48k = 1.3089969389957471826927680763665e-4; |
stefanofasciani | 2:a1330350c32e | 17 | int acc_readings[3]; |
stefanofasciani | 2:a1330350c32e | 18 | int update_round = 0; |
stefanofasciani | 2:a1330350c32e | 19 | |
stefanofasciani | 2:a1330350c32e | 20 | void BSP_AUDIO_OUT_TransferComplete_CallBack(void){ |
stefanofasciani | 2:a1330350c32e | 21 | audio_out_buffer_state = BUFFER_OFFSET_FULL; |
stefanofasciani | 2:a1330350c32e | 22 | return; |
stefanofasciani | 2:a1330350c32e | 23 | } |
stefanofasciani | 2:a1330350c32e | 24 | |
stefanofasciani | 2:a1330350c32e | 25 | |
stefanofasciani | 2:a1330350c32e | 26 | void BSP_AUDIO_OUT_HalfTransfer_CallBack(void){ |
stefanofasciani | 2:a1330350c32e | 27 | audio_out_buffer_state = BUFFER_OFFSET_HALF; |
stefanofasciani | 2:a1330350c32e | 28 | return; |
stefanofasciani | 2:a1330350c32e | 29 | } |
stefanofasciani | 2:a1330350c32e | 30 | |
stefanofasciani | 2:a1330350c32e | 31 | uint8_t SetSysClock_PLL_HSE_200MHz() |
stefanofasciani | 2:a1330350c32e | 32 | { |
stefanofasciani | 2:a1330350c32e | 33 | RCC_ClkInitTypeDef RCC_ClkInitStruct; |
stefanofasciani | 2:a1330350c32e | 34 | RCC_OscInitTypeDef RCC_OscInitStruct; |
stefanofasciani | 2:a1330350c32e | 35 | |
stefanofasciani | 2:a1330350c32e | 36 | // Enable power clock |
stefanofasciani | 2:a1330350c32e | 37 | __PWR_CLK_ENABLE(); |
stefanofasciani | 2:a1330350c32e | 38 | |
stefanofasciani | 2:a1330350c32e | 39 | // Enable HSE oscillator and activate PLL with HSE as source |
stefanofasciani | 2:a1330350c32e | 40 | RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; |
stefanofasciani | 2:a1330350c32e | 41 | RCC_OscInitStruct.HSEState = RCC_HSE_ON; /* External xtal on OSC_IN/OSC_OUT */ |
stefanofasciani | 2:a1330350c32e | 42 | |
stefanofasciani | 2:a1330350c32e | 43 | // Warning: this configuration is for a 25 MHz xtal clock only |
stefanofasciani | 2:a1330350c32e | 44 | RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; |
stefanofasciani | 2:a1330350c32e | 45 | RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; |
stefanofasciani | 2:a1330350c32e | 46 | RCC_OscInitStruct.PLL.PLLM = 25; // VCO input clock = 1 MHz (25 MHz / 25) |
stefanofasciani | 2:a1330350c32e | 47 | RCC_OscInitStruct.PLL.PLLN = 400; // VCO output clock = 400 MHz (1 MHz * 400) |
stefanofasciani | 2:a1330350c32e | 48 | RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // PLLCLK = 200 MHz (400 MHz / 2) |
stefanofasciani | 2:a1330350c32e | 49 | RCC_OscInitStruct.PLL.PLLQ = 8; // USB clock = 50 MHz (400 MHz / 8) |
stefanofasciani | 2:a1330350c32e | 50 | |
stefanofasciani | 2:a1330350c32e | 51 | if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) |
stefanofasciani | 2:a1330350c32e | 52 | { |
stefanofasciani | 2:a1330350c32e | 53 | return 0; // FAIL |
stefanofasciani | 2:a1330350c32e | 54 | } |
stefanofasciani | 2:a1330350c32e | 55 | |
stefanofasciani | 2:a1330350c32e | 56 | // Activate the OverDrive to reach the 216 MHz Frequency |
stefanofasciani | 2:a1330350c32e | 57 | if (HAL_PWREx_EnableOverDrive() != HAL_OK) |
stefanofasciani | 2:a1330350c32e | 58 | { |
stefanofasciani | 2:a1330350c32e | 59 | return 0; // FAIL |
stefanofasciani | 2:a1330350c32e | 60 | } |
stefanofasciani | 2:a1330350c32e | 61 | |
stefanofasciani | 2:a1330350c32e | 62 | // Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers |
stefanofasciani | 2:a1330350c32e | 63 | RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); |
stefanofasciani | 2:a1330350c32e | 64 | RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 200 MHz |
stefanofasciani | 2:a1330350c32e | 65 | RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 200 MHz |
stefanofasciani | 2:a1330350c32e | 66 | RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // 50 MHz |
stefanofasciani | 2:a1330350c32e | 67 | RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // 100 MHz |
stefanofasciani | 2:a1330350c32e | 68 | |
stefanofasciani | 2:a1330350c32e | 69 | if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK) |
stefanofasciani | 2:a1330350c32e | 70 | { |
stefanofasciani | 2:a1330350c32e | 71 | return 0; // FAIL |
stefanofasciani | 2:a1330350c32e | 72 | } |
stefanofasciani | 2:a1330350c32e | 73 | HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_4); |
stefanofasciani | 2:a1330350c32e | 74 | return 1; // OK |
stefanofasciani | 2:a1330350c32e | 75 | } |
stefanofasciani | 2:a1330350c32e | 76 | |
stefanofasciani | 2:a1330350c32e | 77 | void sint_osc(){ |
stefanofasciani | 2:a1330350c32e | 78 | |
stefanofasciani | 2:a1330350c32e | 79 | int i; |
stefanofasciani | 2:a1330350c32e | 80 | float mod; |
stefanofasciani | 2:a1330350c32e | 81 | int indexBase; |
stefanofasciani | 2:a1330350c32e | 82 | float indexFract, value1, value2; |
stefanofasciani | 2:a1330350c32e | 83 | |
stefanofasciani | 2:a1330350c32e | 84 | for (i=0;i<AUDIO_BLOCK_SIZE/2;i++){ |
stefanofasciani | 2:a1330350c32e | 85 | indexBase = floor(idx_2); |
stefanofasciani | 2:a1330350c32e | 86 | indexFract = idx_2 - (float)indexBase; |
stefanofasciani | 2:a1330350c32e | 87 | value1 = table[indexBase]; |
stefanofasciani | 2:a1330350c32e | 88 | value2 = table[(indexBase+1)%TABLE_SIZE]; |
stefanofasciani | 2:a1330350c32e | 89 | mod = moddepth*(value1 + ((value2 - value1) * indexFract)); |
stefanofasciani | 2:a1330350c32e | 90 | |
stefanofasciani | 2:a1330350c32e | 91 | indexBase = floor(idx_1); |
stefanofasciani | 2:a1330350c32e | 92 | indexFract = idx_1 - (float)indexBase; |
stefanofasciani | 2:a1330350c32e | 93 | value1 = table[indexBase]; |
stefanofasciani | 2:a1330350c32e | 94 | value2 = table[(indexBase+1)%TABLE_SIZE]; |
stefanofasciani | 2:a1330350c32e | 95 | osc_buf[i] = amplitude*(value1 + ((value2 - value1) * indexFract)); |
stefanofasciani | 2:a1330350c32e | 96 | |
stefanofasciani | 2:a1330350c32e | 97 | idx_1 = idx_1 + ((frqTL * pitch) + mod); |
stefanofasciani | 2:a1330350c32e | 98 | while (idx_1 >= TABLE_SIZE){ |
stefanofasciani | 2:a1330350c32e | 99 | idx_1 -= TABLE_SIZE; |
stefanofasciani | 2:a1330350c32e | 100 | } |
stefanofasciani | 2:a1330350c32e | 101 | while (idx_1 < 0){ |
stefanofasciani | 2:a1330350c32e | 102 | idx_1 += TABLE_SIZE; |
stefanofasciani | 2:a1330350c32e | 103 | } |
stefanofasciani | 2:a1330350c32e | 104 | idx_2 = idx_2 + (frqTL * modrate); |
stefanofasciani | 2:a1330350c32e | 105 | while (idx_2 >= TABLE_SIZE){ |
stefanofasciani | 2:a1330350c32e | 106 | idx_2 -= TABLE_SIZE; |
stefanofasciani | 2:a1330350c32e | 107 | } |
stefanofasciani | 2:a1330350c32e | 108 | while (idx_2 < 0){ |
stefanofasciani | 2:a1330350c32e | 109 | idx_2 += TABLE_SIZE; |
stefanofasciani | 2:a1330350c32e | 110 | } |
stefanofasciani | 2:a1330350c32e | 111 | |
stefanofasciani | 2:a1330350c32e | 112 | } |
stefanofasciani | 2:a1330350c32e | 113 | |
stefanofasciani | 2:a1330350c32e | 114 | osc_buf[0] = filter*osc_buf[0] + (1-filter)*filt_old_samp; |
stefanofasciani | 2:a1330350c32e | 115 | for(i=1;i<AUDIO_BLOCK_SIZE/2;i++){ |
stefanofasciani | 2:a1330350c32e | 116 | osc_buf[i] = filter*osc_buf[i] + (1-filter)*osc_buf[i-1]; |
stefanofasciani | 2:a1330350c32e | 117 | } |
stefanofasciani | 2:a1330350c32e | 118 | filt_old_samp = osc_buf[(AUDIO_BLOCK_SIZE/2)-1]; |
stefanofasciani | 2:a1330350c32e | 119 | |
stefanofasciani | 2:a1330350c32e | 120 | |
stefanofasciani | 2:a1330350c32e | 121 | return; |
stefanofasciani | 2:a1330350c32e | 122 | } |
stefanofasciani | 2:a1330350c32e | 123 | |
stefanofasciani | 2:a1330350c32e | 124 | void copy_buffer(int offset){ |
stefanofasciani | 2:a1330350c32e | 125 | int i; |
stefanofasciani | 2:a1330350c32e | 126 | for(i=0;i<AUDIO_BLOCK_SIZE/2;i++){ |
stefanofasciani | 2:a1330350c32e | 127 | out_buffer[offset+(i*2)] = out_buffer[offset+(i*2)+1] = (int16_t)(30000*osc_buf[i]); |
stefanofasciani | 2:a1330350c32e | 128 | } |
stefanofasciani | 2:a1330350c32e | 129 | |
stefanofasciani | 2:a1330350c32e | 130 | return; |
stefanofasciani | 2:a1330350c32e | 131 | } |
stefanofasciani | 2:a1330350c32e | 132 | |
stefanofasciani | 2:a1330350c32e | 133 | |
stefanofasciani | 2:a1330350c32e | 134 | void init_sin_table(){ |
stefanofasciani | 2:a1330350c32e | 135 | |
stefanofasciani | 2:a1330350c32e | 136 | int i; |
stefanofasciani | 2:a1330350c32e | 137 | for(i=0;i<TABLE_SIZE;i++){ |
stefanofasciani | 2:a1330350c32e | 138 | table[i] = sinf((float)(two_pi_48k*(23.4375f)*(float)i)); |
stefanofasciani | 2:a1330350c32e | 139 | } |
stefanofasciani | 2:a1330350c32e | 140 | return; |
stefanofasciani | 2:a1330350c32e | 141 | } |
stefanofasciani | 2:a1330350c32e | 142 | |
stefanofasciani | 2:a1330350c32e | 143 | float map_full(float x, float in_min, float in_max, float out_min, float out_max) { |
stefanofasciani | 2:a1330350c32e | 144 | return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; |
stefanofasciani | 2:a1330350c32e | 145 | } |
stefanofasciani | 2:a1330350c32e | 146 | |
stefanofasciani | 2:a1330350c32e | 147 | float map(float x, float out_min, float out_max) { |
stefanofasciani | 2:a1330350c32e | 148 | return (x - 0.0f) * (out_max - out_min) / (1.0f - 0.0f) + out_min; |
stefanofasciani | 2:a1330350c32e | 149 | } |
stefanofasciani | 2:a1330350c32e | 150 | |
stefanofasciani | 2:a1330350c32e | 151 | float get_touch_horizontal(){ |
stefanofasciani | 2:a1330350c32e | 152 | float temp = map_full(TS.touchX[0],1,480,0.0,1.0); |
stefanofasciani | 2:a1330350c32e | 153 | if(temp > 1)temp=1; |
stefanofasciani | 2:a1330350c32e | 154 | else if(temp < 0)temp=0; |
stefanofasciani | 2:a1330350c32e | 155 | return temp; |
stefanofasciani | 2:a1330350c32e | 156 | } |
stefanofasciani | 2:a1330350c32e | 157 | |
stefanofasciani | 2:a1330350c32e | 158 | float get_touch_vertical(){ |
stefanofasciani | 2:a1330350c32e | 159 | float temp = map_full(TS.touchY[0],1,272,0.0,1.0); |
stefanofasciani | 2:a1330350c32e | 160 | if(temp > 1)temp=1; |
stefanofasciani | 2:a1330350c32e | 161 | else if(temp < 0)temp=0; |
stefanofasciani | 2:a1330350c32e | 162 | return temp; |
stefanofasciani | 2:a1330350c32e | 163 | } |
stefanofasciani | 2:a1330350c32e | 164 | |
stefanofasciani | 2:a1330350c32e | 165 | float get_acc_horizontal(){ |
stefanofasciani | 2:a1330350c32e | 166 | float temp = map_full((float)(int16_t)acc_readings[1],230,-230,0.0,1.0); //for full range -/+256 |
stefanofasciani | 2:a1330350c32e | 167 | if(temp > 1)temp=1; |
stefanofasciani | 2:a1330350c32e | 168 | else if(temp < 0)temp=0; |
stefanofasciani | 2:a1330350c32e | 169 | return temp; |
stefanofasciani | 2:a1330350c32e | 170 | } |
stefanofasciani | 2:a1330350c32e | 171 | |
stefanofasciani | 2:a1330350c32e | 172 | float get_acc_vertical(){ |
stefanofasciani | 2:a1330350c32e | 173 | float temp = map_full((float)(int16_t)acc_readings[0],230,-230,0.0,1.0); //for full range -/+256 |
stefanofasciani | 2:a1330350c32e | 174 | if(temp > 1)temp=1; |
stefanofasciani | 2:a1330350c32e | 175 | else if(temp < 0)temp=0; |
stefanofasciani | 2:a1330350c32e | 176 | return temp; |
stefanofasciani | 2:a1330350c32e | 177 | } |
stefanofasciani | 2:a1330350c32e | 178 | |
stefanofasciani | 2:a1330350c32e | 179 | void display_keyboard(){ |
stefanofasciani | 2:a1330350c32e | 180 | |
stefanofasciani | 2:a1330350c32e | 181 | lcd.SetTextColor(LCD_COLOR_LIGHTRED); |
stefanofasciani | 2:a1330350c32e | 182 | lcd.FillRect(2,0,38,272); |
stefanofasciani | 2:a1330350c32e | 183 | lcd.FillRect(82,0,38,272); |
stefanofasciani | 2:a1330350c32e | 184 | lcd.FillRect(162,0,38,272); |
stefanofasciani | 2:a1330350c32e | 185 | lcd.FillRect(202,0,38,272); |
stefanofasciani | 2:a1330350c32e | 186 | lcd.FillRect(282,0,38,272); |
stefanofasciani | 2:a1330350c32e | 187 | lcd.FillRect(362,0,38,272); |
stefanofasciani | 2:a1330350c32e | 188 | lcd.FillRect(442,0,38,272); |
stefanofasciani | 2:a1330350c32e | 189 | |
stefanofasciani | 2:a1330350c32e | 190 | lcd.SetTextColor(LCD_COLOR_DARKRED); |
stefanofasciani | 2:a1330350c32e | 191 | lcd.FillRect(42,0,38,272); |
stefanofasciani | 2:a1330350c32e | 192 | lcd.FillRect(122,0,38,272); |
stefanofasciani | 2:a1330350c32e | 193 | lcd.FillRect(242,0,38,272); |
stefanofasciani | 2:a1330350c32e | 194 | lcd.FillRect(322,0,38,272); |
stefanofasciani | 2:a1330350c32e | 195 | lcd.FillRect(402,0,38,272); |
stefanofasciani | 2:a1330350c32e | 196 | |
stefanofasciani | 2:a1330350c32e | 197 | lcd.SetTextColor(LCD_COLOR_BLACK); |
stefanofasciani | 2:a1330350c32e | 198 | lcd.FillRect(1,21,480,232); |
stefanofasciani | 2:a1330350c32e | 199 | |
stefanofasciani | 2:a1330350c32e | 200 | return; |
stefanofasciani | 2:a1330350c32e | 201 | } |
stefanofasciani | 2:a1330350c32e | 202 | |
stefanofasciani | 2:a1330350c32e | 203 | float get_note_pitch(){ |
stefanofasciani | 2:a1330350c32e | 204 | |
stefanofasciani | 2:a1330350c32e | 205 | float pitch = 0; |
stefanofasciani | 2:a1330350c32e | 206 | |
stefanofasciani | 2:a1330350c32e | 207 | if((TS.touchX[0]>=1)&&(TS.touchX[0]<=40)) pitch = 523.25f; |
stefanofasciani | 2:a1330350c32e | 208 | else if((TS.touchX[0]>=41)&&(TS.touchX[0]<=80)) pitch = 554.37f; |
stefanofasciani | 2:a1330350c32e | 209 | else if((TS.touchX[0]>=81)&&(TS.touchX[0]<=120)) pitch = 587.33f; |
stefanofasciani | 2:a1330350c32e | 210 | else if((TS.touchX[0]>=121)&&(TS.touchX[0]<=160)) pitch = 622.25f; |
stefanofasciani | 2:a1330350c32e | 211 | else if((TS.touchX[0]>=161)&&(TS.touchX[0]<=200)) pitch = 659.25f; |
stefanofasciani | 2:a1330350c32e | 212 | else if((TS.touchX[0]>=201)&&(TS.touchX[0]<=240)) pitch = 698.46f; |
stefanofasciani | 2:a1330350c32e | 213 | else if((TS.touchX[0]>=241)&&(TS.touchX[0]<=280)) pitch = 739.99f; |
stefanofasciani | 2:a1330350c32e | 214 | else if((TS.touchX[0]>=281)&&(TS.touchX[0]<=320)) pitch = 783.99f; |
stefanofasciani | 2:a1330350c32e | 215 | else if((TS.touchX[0]>=321)&&(TS.touchX[0]<=360)) pitch = 830.61f; |
stefanofasciani | 2:a1330350c32e | 216 | else if((TS.touchX[0]>=361)&&(TS.touchX[0]<=400)) pitch = 880.00; |
stefanofasciani | 2:a1330350c32e | 217 | else if((TS.touchX[0]>=401)&&(TS.touchX[0]<=440)) pitch = 932.33; |
stefanofasciani | 2:a1330350c32e | 218 | else if((TS.touchX[0]>=441)&&(TS.touchX[0]<=480)) pitch = 987.77; |
stefanofasciani | 2:a1330350c32e | 219 | |
stefanofasciani | 2:a1330350c32e | 220 | return pitch; |
stefanofasciani | 2:a1330350c32e | 221 | } |