SFML community forums
Help => Audio => Topic started 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:
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.
-
Maybe sf::SoundStream is something for you?
By the way: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. ;)
-
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.
By the way: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.
-
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
#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
#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.
-
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.