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}

- Wisdom is the art of using knowledge
- String theory: There's music in everything

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}

- Wisdom is the art of using knowledge
- String theory: There's music in everything

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: