Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » step calculation for sampled sin sample

Credits go to Arthur Kalliokoski and Elias for helping out!
This thread is locked; no one can reply to it. rss feed Print
step calculation for sampled sin sample
Ariesnl
Member #2,902
November 2002
avatar

Calling for a math guru,
would be nice if someone could explain this

I need to find the stepsize to get a nice sin wave
and maybe other waves in the future. but I'm confused

Anyone ?

#SelectExpand
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
avatar

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().

“Throughout history, poverty is the normal condition of man. Advances which permit this norm to be exceeded — here and there, now and then — are the work of an extremely small minority, frequently despised, often condemned, and almost always opposed by all right-thinking people. Whenever this tiny minority is kept from creating, or (as sometimes happens) is driven out of a society, the people then slip back into abject poverty. This is known as "bad luck.”

― Robert A. Heinlein

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.

--
"Either help out or stop whining" - Evert

Ariesnl
Member #2,902
November 2002
avatar

Thnx,
I think this is what it should look like.
I'll try to make some effects using harmonics , see what can be done with this.

Allegro 5 should definitely get some "record sample" or "audio input" functions

#SelectExpand
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.

--
"Either help out or stop whining" - Evert

Go to: