I've been working with an STM32F4 wanting to generate notes passing values to a DAC like so:
float playNote(float noteFrequency, float t)
{
float w = 2 * PI * noteFrequency;
return sinf(w * t);
}
With this being how a note is generated in DAC (With DAC size being 500):
void getData4Dac(uint16_t* dac_buff, uint8_t note)
{
uint16_t n;
float t = 0;
for(n=0; n<(DAC_BUFF_SIZE); n++)
{
switch (note)
{
case 0:
y = 0; // Pause
break;
case 1:
y = playNote(NOTE_C, t);
break;
case 2:
y = playNote(NOTE_D, t);
break;
case 3:
y = playNote(NOTE_E, t);
break;
case 4:
y = playNote(NOTE_F, t);
break;
case 5:
y = playNote(NOTE_G, t);
break;
case 6:
y = playNote(NOTE_A, t);
break;
case 7:
y = playNote(NOTE_H, t);
break;
case 8:
y = playNote(NOTE_C2, t);
break;
default:
y = 0;
break;
}
dac_buff[n] = (uint16_t)(y * 2047 + 2048);
t = t + 0.5e-4;
}
}
Now I've got two problems here.
The first one (which is really a question): The values of NOTE_x are:
#define NOTE_C 240
#define NOTE_D 280
#define NOTE_E 320
#define NOTE_F 360
#define NOTE_G 400
#define NOTE_A 440
#define NOTE_H 480
#define NOTE_C2 520
Real note frequencies for the 4th Octave range from 261.63Hz to 493.88Hz but if I set my frequencies to those exact values there is a lot of noise. My question is where is what's the reason for that noise and why do my exact values produce no noise?
The second question is:
I wanted to play multiple notes at the same time like so
for(n=0; n<(DAC_BUFF_SIZE); n++)
{
active_notes = 0;
y = 0;
for(i = 0; i < NUMBER_OF_NOTES; i++){
if(note_durations[i] > 0){
active_notes++;
y += sinf(2 * PI * note_frequencies[i] * (1 << octave) * t);
// y = sinf(2 * PI * note_frequencies[i] * (1 << octave) * t);
}
}
y /= active_notes;
t += 0.5e-4;
dac_buff[n] = (uint16_t)(y*2047 + 2048);
}
But doing this y += [signal] totally messes up the sound and creates a lot of noise. Can someone help me figure out why that is happening and what do i have to keep in mind to get the notes clean when doing y += [signal].
Thanks!
Edit: Here's my entire main function
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "cs43l22.h"
#include "dac.h"
#include "math.h"
#define PI 3.1415
#define DAC_BUFF_SIZE 500
#define NOTE_C 230
#define NOTE_D 280
#define NOTE_E 320
#define NOTE_F 360
#define NOTE_G 400
#define NOTE_A 440
#define NOTE_H 480
#define NOTE_C2 520
#define NOTE_Cis 17.32
#define NOTE_Dis 19.45
#define NOTE_Fis 23.12
#define NOTE_Gis 25.96
#define NOTE_Ais 29.14
extern volatile int8_t octave;
extern volatile uint8_t note_durations[NUMBER_OF_NOTES];
static float note_frequencies[NUMBER_OF_NOTES];
uint16_t dac_buff[DAC_BUFF_SIZE];
uint32_t btime = 0;
void getData4Dac(uint16_t * dac_buff, int8_t octave);
void initNotes(void);
void updateNoteDurations(void);
int main(void)
{
initUSART2(USART2_BAUDRATE_921600);
enIrqUSART2();
initDmaDAC1(dac_buff, DAC_BUFF_SIZE);
getData4Dac(dac_buff, octave);
initCS43L22(10, 48000);
initSYSTIM();
initNotes();
printUSART2("PLAY NOW:");
while(1)
{
if(chk4TimeoutSYSTIM(btime, 1000) == SYSTIM_TIMEOUT){
updateNoteDurations();
btime = getSYSTIM();
}
while((SPI3->SR & 0x00000002) == 0);
SPI3->DR = 0x00;
chkBuffUSART2();
getData4Dac(dac_buff, octave);
}
}
void getData4Dac(uint16_t* dac_buff, int8_t octave)
{
uint8_t active_notes;
uint16_t n, i;
float y=0, t=0;
for(n=0; n<(DAC_BUFF_SIZE); n++)
{
active_notes = 0;
y = 0;
for(i = 0; i < NUMBER_OF_NOTES; i++){
if(note_durations[i] > 0){
active_notes++;
y += sinf(2 * PI * note_frequencies[i] * t); // sklonjeno octave
}
}
y /= active_notes;
t += 0.5e-4;
dac_buff[n] = (uint16_t)(y*2048 + 2048);
}
}
void initNotes(){
uint8_t i;
for(i = 0; i < NUMBER_OF_NOTES; i++){
note_durations[i] = 0;
}
note_frequencies[0] = NOTA_C;
note_frequencies[1] = NOTA_Cis;
note_frequencies[2] = NOTA_D;
note_frequencies[3] = NOTA_Dis;
note_frequencies[4] = NOTA_E;
note_frequencies[5] = NOTA_F;
note_frequencies[6] = NOTA_Fis;
note_frequencies[7] = NOTA_G;
note_frequencies[8] = NOTA_Gis;
note_frequencies[9] = NOTA_A;
note_frequencies[10] = NOTA_Ais;
note_frequencies[11] = NOTA_H;
note_frequencies[12] = NOTA_C2;
}
void updateNoteDurations(){
uint8_t i;
for(i = 0; i < NUMBER_OF_NOTES; i++){
if(note_durations[i] > 0){
note_durations[i]--;
}
}
}
My question is where is what's the reason for that noise and why do my exact values produce no noise?
Short answer: Discontinuity
If I understand your code correct, you fill the dac_buffer with samples and then replays the same dac_buffer a number of times.
The time starts at 0
and you increase the time with 0.5e-4
for each sample and you have 500 samples, so the number of sine-periods in the buffer will be:
periods = 0.5e-4 * 500 * NOTE_FREQUENCY
So for these notes you have:
#define NOTE_C 240 // exactly 6 periods
#define NOTE_D 280 // exactly 7 periods
but for note frequency 261.63
you'll get 6.54 periods.
A single buffer will hold:
and when you repeat that e.g. 3 times you get:
As the picture shows, you have discontinuity when you start the replay. Such discontinuity causes noise.
As e.g. note frequency 240 is exactly 6 periods, it will not have that discontinuity and consequently less noise.
If possible, depending on note frequency you need to adjust the number of samples used so that it always matches an integer number of periods (or as close as posible).
BTW: Recreating a signal directly from samples will always contain noise. To get rid of that, you need a low-pass filter after the DAC.