SFML community forums

Help => Audio => Topic started by: Notnasiul on July 25, 2011, 01:01:30 pm

Title: Creating an oscillator
Post by: Notnasiul on July 25, 2011, 01:01:30 pm
Has anyone done this? I'm starting with SFML, so I'm still pretty lost. I found this basic effect generator http://www.sfml-dev.org/forum/viewtopic.php?t=3449&highlight=soundman which is great for precise sound effects, but I need something that creates a continuous sound. That is, an oscillator.

I guess I have to fill a soundbuffer with the right samples (using a sine wave, knowing the target frequency and amplitude), feed it to a sound object and play it. But I must be doing something wrong... Just as a test I did this:

Code: [Select]

#include <SFML/Audio.hpp>
#include "math.h"

int main()
{
    int nSamples = 10000; // How many samples do I need for a cycle?
    sf::Int16 samples[nSamples];
    sf::SoundBuffer buffer;
    sf::Sound sound;
    //Fill samples with a pure A tone (440hrz)
    for (int i = 0; i < nSamples ; i++) {
        samples[i] = ( sin(440.0f * (2.0f * 3.1415f) * i / 44100));
    }
    bool ok = buffer.LoadFromSamples(samples, nSamples , 1, 44100);
    if (!ok) exit(-1);
    sound.SetBuffer(buffer);
    sound.Play();
    sf::Sleep(5.0f);
    return 0;
}


Nothing is heard when executed...
Title: Creating an oscillator
Post by: Nexus on July 25, 2011, 01:06:50 pm
std::sin() returns values in [-1,1]. If you use sf::Int16, you probably want to scale the samples.

By the way, you should avoid std::exit(), as it doesn't call destructors an thus doesn't clean up correctly. And use <cmath> instead of <math.h>. Apart from that, the following code is not standard-conforming. You should use const int nSamples for portable code.
Code: [Select]
int nSamples = 10000; // How many samples do I need for a cycle?
sf::Int16 samples[nSamples];
Title: Creating an oscillator
Post by: Notnasiul on July 25, 2011, 01:49:54 pm
Right, and I guess that scale corresponds to the amplitude. It works.

Now, using Loop that sound will play forever, even in background (great!). And this is where I'm not sure whether I have to use a soundbuffer or a soundstream...

Say I created those samples at 440Hrz, but now I want to change their frequency to 880Hrz. If I update the samples vector, reload them in the soundbuffer and reasign this soundbuffer to the current sound, it will simply ignore me and keep playing the previous frequency. That's where I guess a soundstream will be handy: I just would feed it with new samples at 880.

I don't know, that may be a complete nonsense. The question would be: how would I change a sound's buffer samples while it's playing?

This post seems to be related: http://www.sfml-dev.org/forum/viewtopic.php?t=3929&postdays=0&postorder=asc&start=0, I'll read it ;)
Title: Creating an oscillator
Post by: Laurent on July 25, 2011, 01:53:07 pm
Quote
The question would be: how would I change a sound's buffer samples while it's playing?

If the obvious way doesn't work, it might be a bug in SFML. Can you please provide a complete and minimal source code that reproduces this problem?
Title: Creating an oscillator
Post by: Notnasiul on July 25, 2011, 02:05:51 pm
Ok, let's see...

Oscillator.h
Code: [Select]

#ifndef __OSCILLATOR__
#define __OSCILLATOR__

#include <SFML/Audio.hpp>
#include <iostream>
#include <math.h>

#define NSAMPLES 44100

class Oscillator
{
public :
    Oscillator (float frequency, float amplitude);
    void setTone(float frequency, float amplitude);

private :
    sf::SoundBuffer buffer;
    sf::Sound sound;

    sf::Int16 samples[NSAMPLES];
};
#endif


Oscillator.cpp
Code: [Select]

#include "Oscillator.h"

Oscillator::Oscillator(float frequency, float amplitude) {
    setTone( frequency, amplitude);
    sound.SetLoop(true);
    sound.Play();
}

void Oscillator::setTone(float frequency, float amplitude) {
    for (int i = 0; i < NSAMPLES; i++) {
        samples[i] = ( amplitude * sin(frequency * (2.0f * 3.1415f) * i / 44100));
    }
    buffer.LoadFromSamples(samples, NSAMPLES, 1, 44100);
    sound.SetBuffer(buffer);
}


main.cpp
Code: [Select]

#include <SFML/Audio.hpp>
#include "Oscillator.h"

int main() {
   Oscillator *o = new Oscillator(440, 10000);
   sf::Sleep(2.0f);
   o->setTone(880,10000); // but we still hear 440 after this...
   sf::Sleep(2.0f);
   return 0;
}


SetTone works the first time it's called, in the constructor. But samples won't change the second time it's called, after two seconds.

EDIT: I guess this is not the right way of doing this. I should have a look at soundstream...
Title: Creating an oscillator
Post by: Laurent on July 25, 2011, 02:07:26 pm
Ok thanks, I'll test this as soon as possible.

By the way, which version of SFML do you use?
Title: Creating an oscillator
Post by: Notnasiul on July 25, 2011, 02:09:52 pm
Sorry, still with 1.6. I know you told me to switch to 2.0, but I did not manage to prepare it with cmake for codeblocks. That's in my todo list :(
Title: Creating an oscillator
Post by: Notnasiul on August 08, 2011, 01:54:08 pm
Could anyone try this or was I punished for working with 1.6? :D
Title: Creating an oscillator
Post by: Laurent on August 08, 2011, 02:21:17 pm
Quote
Could anyone try this or was I punished for working with 1.6?

Kind of :D
I'm not working on 1.6 anymore, so I won't test until you try first with SFML 2.
Plus... I still have no audio (I can't find a Windows 7 x64 driver for my audio chipset), so I will definitely not be able to test this :?
Title: Creating an oscillator
Post by: Notnasiul on August 08, 2011, 03:57:42 pm
lol, ok, I'll try SFML 2.0, although compiling it is being a hell! (well, it did compile with Visual Studio express edition 2008, but now I'm getting lots of undefined references on my application... so still trying to link everything correctly!)
Title: Creating an oscillator
Post by: Laurent on August 08, 2011, 04:18:49 pm
If you link SFML statically, don't forget to define SFML_STATIC in your preprocessor defines.