|
step calculation for sampled sin sample |
Ariesnl
Member #2,902
November 2002
|
Calling for a math guru, I need to find the stepsize to get a nice sin wave Anyone ? 1void CustomProgram::Tone(int a_nFrequency, int a_nDuration)
2{
3 unsigned int samples = (float(a_nDuration)/1000.0 * a_nFrequency)*100;
4 unsigned long sample_size=al_get_channel_count(ALLEGRO_CHANNEL_CONF_1) *al_get_audio_depth_size(ALLEGRO_AUDIO_DEPTH_INT16);
5 unsigned long bytes = samples * sample_size;
6
7 void *buff = NULL;
8 buff = al_malloc(bytes);
9
10 al_destroy_sample(m_pSample);
11 m_pSample = al_create_sample (buff,samples, a_nFrequency,ALLEGRO_AUDIO_DEPTH_INT16,ALLEGRO_CHANNEL_CONF_1,true);
12
13
14 if (m_pSample!=NULL)
15 {
16 int16_t * ptr = (int16_t *) al_get_sample_data(m_pSample);
17 double step = double(2 * PI * a_nDuration * a_nFrequency) / samples; // <----- This one here !
18 for (unsigned int i=0;i<samples;i++)
19 {
20 ptr[i]= sin(i*step) * 30000;
21 }
22 al_play_sample (m_pSample,1.0,0,1.0,ALLEGRO_PLAYMODE_ONCE,NULL);
23 }
24}
Perhaps one day we will find that the human factor is more complicated than space and time (Jean luc Picard) |
Arthur Kalliokoski
Second in Command
February 2005
|
You need to have a_nFrequency steps per second for a_nDuration seconds. The desired frequency of sine wave needs to be divided by a_nFrequency steps per second to get the increment to pass to the float that is input to the sin() function. Let's say that a_nFrequency is 28,000 hertz, duration is 10 seconds, and you want a sin wave to produce concert A (440 hertz). So you'd need 28,000 * 10 sample elements to put the sin values into, and the increment per sample element would be 440.0/28000.0 . As Elias pointed out below, I forgot about the 2.0 * M_PI to get one complete cycle from sin(). They all watch too much MSNBC... they get ideas. |
Elias
Member #358
May 2000
|
Well, just look at a sine wave: y = sin(x) If x runs from 0 to 2 * pi, you get one complete wave. Now multiply by 2 * pi: y = sin(x * 2 * pi) Now the full wave goes from 0 to 1. Now assume x is our time in seconds, and you want a 440 Hz tone: y = sin(x * 2 * pi * 440); Now each seconds there is 440 complete sine waves. Now, instead of having the time in seconds, x is a sample position, 48000 samples make up one second: y = sin(x * 2 * pi * 440 / 48000); In your code, a_nFrequency is the 48000. So a_nDuration/samples is your tone's frequency. I'm a bit unsure about those variable names, I'd say you can simplify that function a lot and still have it do the same thing. -- |
Ariesnl
Member #2,902
November 2002
|
Thnx, Allegro 5 should definitely get some "record sample" or "audio input" functions 1void CustomProgram::Tone(int a_nFrequency, int a_nVolume, int a_nDuration)
2{
3 int nSampleRate = 48000;
4 if (a_nVolume > 255)
5 {
6 a_nVolume = 255;
7 }
8 else if (a_nVolume<0)
9 {
10 a_nVolume = 0;
11 }
12
13 int nInternalVolume = (30000 * a_nVolume)/255;
14 unsigned int samples = (nSampleRate * a_nDuration) / 1000.0;
15 unsigned long sample_size=al_get_channel_count(ALLEGRO_CHANNEL_CONF_1) *al_get_audio_depth_size(ALLEGRO_AUDIO_DEPTH_INT16);
16 unsigned long bytes = samples * sample_size;
17
18 void *buff = NULL;
19 buff = al_malloc(bytes);
20
21 al_destroy_sample(m_pSample);
22 m_pSample = al_create_sample (buff,samples, nSampleRate ,ALLEGRO_AUDIO_DEPTH_INT16,ALLEGRO_CHANNEL_CONF_1,true);
23 double dFi = double(2 * PI * a_nFrequency) / nSampleRate;
24
25 if (m_pSample!=NULL)
26 {
27 int16_t * ptr = (int16_t *) al_get_sample_data(m_pSample);
28 for (unsigned int i=0;i<samples;i++)
29 {
30 ptr[i]= sin(i * dFi) * nInternalVolume;
31
32 }
33 al_play_sample (m_pSample,1.0,0,1.0,ALLEGRO_PLAYMODE_ONCE,NULL);
34 }
35}
Perhaps one day we will find that the human factor is more complicated than space and time (Jean luc Picard) |
Elias
Member #358
May 2000
|
Looks good to me now, assuming a_nDuration is in ms. -- |
|