SFML community forums

Help => Audio => Topic started by: Irbis on January 15, 2011, 07:44:28 pm

Title: Getting samples with no delay
Post by: Irbis on January 15, 2011, 07:44:28 pm
Greetings, ladies and gentlemen.
I'm doing a project that requires a real-time spectrum visualization.
So, the algorithm looks like this:
1. Get playing offset
2. Get small amount of samples starting from that offset
3. Use FFT on those samples
4. Visualize

That's the code that I'm using for it:


Code: [Select]

sf::SoundBuffer SB;
SB.LoadFromFile("file.ogg");

const sf::Int16 * SBp;
SBp = SB.GetSamples();

sf::Sound SND;
SND.SetBuffer(SB);

SND.Play();

//Get current offset
//Fill an FFT input array with some amount of samples starting from that offset
//Call FFTW


The problem is that loading from file into the sound buffer takes some  time because it loads the whole file. I don't need the whole file at any moment, only small chunks.

Is it possible to load files chunk by chunk and get samples from those chunks without waiting for the whole file to load? As I understand sf::Music is doing the loading that way, but it doesn't allow me to get it's buffer.
Code: [Select]
Title: Getting samples with no delay
Post by: Nexus on January 15, 2011, 07:48:00 pm
Maybe sf::SoundStream is something for you?

By the way:
Code: [Select]
const sf::SoundBuffer * SB;
SB.LoadFromFile("file.ogg");
I really doubt that this is your actual code. There are two compiletime errors and undefined behaviour at runtime. ;)
Title: Getting samples with no delay
Post by: Irbis on January 15, 2011, 07:57:56 pm
Quote from: "Nexus"
Maybe sf::SoundStream is something for you?


Maybe I'm blind, but I wasn't able to find the solution to do this using SoundStream. Is it really possible to get samples from it? If so I'll try to read documentation about it once again and don't bother people with obvious questions;)

upd: Okay, after reading the SoundStream tutorial I can imagine how to get samples from SoundStream, but I don't see a way to get them while loading chunk by chunk, because it does the same thing - loads a file into the SoundBuffer in a memory first.

Quote from: "Nexus"

By the way:
Code: [Select]
const sf::SoundBuffer * SB;
SB.LoadFromFile("file.ogg");
I really doubt that this is your actual code. There are two compiletime errors and undefined behaviour at runtime. ;)


That's a typo, copypasted some messy code, already changed it.
Title: Getting samples with no delay
Post by: Irbis on January 16, 2011, 01:04:31 am
Okay, I wasn't able to find how to do this using only SFML, but I've written the workaround that combines code from the SoundStream tutorial and some libsndfile code. Maybe it'll be useful for someone:

SequentialSoundStreamer.hpp
Code: [Select]

#include <SFML/Audio.hpp>
#include <sndfile.h>
#include <fftw3.h>
#include <iostream>

namespace sfe
{

class SequentialSoundStreamer : public sf::SoundStream
{
public :
    SequentialSoundStreamer(std::size_t BufferSize) :
    myBufferSize(BufferSize)  {}
    bool Open(const char * Filename);

private :
    virtual bool OnGetData(sf::SoundStream::Chunk& Data);
    std::size_t            myBufferSize;

    SNDFILE * SoundFile;
    SF_INFO SoundFileInfo;
    short * SamplesArray;
};
}


SequentialSoundStreamer.cpp
Code: [Select]

#include "SequentialSoundStreamer.hpp"

namespace sfe
{
    bool SequentialSoundStreamer::Open(const char * Filename)
    {
        SoundFileInfo.format=0;
        if (!(SoundFile = sf_open (Filename, SFM_READ, &SoundFileInfo)))
            std::cout<<"\nCan't open the file.\n";

        Initialize(SoundFileInfo.channels,SoundFileInfo.samplerate);

        SamplesArray = (short*) fftw_malloc(sizeof(short) * myBufferSize);

        return false;
    }

    bool SequentialSoundStreamer::OnGetData(sf::SoundStream::Chunk& Data)
    {
        if (! (Data.NbSamples = sf_readf_short (SoundFile, SamplesArray, myBufferSize / SoundFileInfo.channels) * SoundFileInfo.channels))
           {std::cout<<"\nCan't read the file (can be the end of it).\n"; return false;}

        Data.Samples   = SamplesArray;

        return true;
    }

}


As sound is being loaded chunk by chunk these chunks (SamplesArray) can be passed whatever they needed to.
malloc can be used instead of fftw_malloc.
Title: Getting samples with no delay
Post by: Jeffs on March 20, 2011, 12:22:37 pm
That's funny, I'm working on almost the exact same project, and I have almost the exact same problem. I'll look into the solution you found! Thanks.