SFML community forums
Help => Audio => Topic started by: LuckyNeo on March 13, 2011, 11:11:37 am
-
Hi,
I need to start recording and after given number of samples stop recording. In doc, I've found OnProcessSamples, but I don't really know how to use it. Every time I do it, it don't record anything.
Do you have a clue?
-
There's a tutorial with a complete working source code. Have you tried it?
-
I have tried it, if you mean this one http://www.sfml-dev.org/tutorials/1.6/audio-capture.php
I changed value of SamplesCount within OnProcessSamples this way:
SamplesCount = 1300;
and then stopped through signal emit ProcessFinished()
, in slot there is recorder->Stop()
to stop recording after needed number of samples. But after I've copied buffer with GetBuffer() it showed zero samples when I called GetSamplesCount.
There must be something I've missed in OnProcessSamples, but I don't know what.
-
Can you show a complete and minimal source code that reproduces this problem?
-
SignalCatcher::SignalCatcher(sf::SoundBuffer* snd_buffer, int samplesCount, int sampleRate = 44100): samplesCount(samplesCount)
{
this->recorder = new MyRecorder(samplesCount);
this->cat_buffer = *snd_buffer;
this->sampleRate = sampleRate;
connect(recorder, SIGNAL(processFinished()),
this, SLOT(onProcessFinished()));
}
bool SignalCatcher::start()
{
if (sf::SoundRecorder::CanCapture())
{
recorder->Start();
return true;
}
else {
return false;
}
}
bool SignalCatcher::stop()
{
recorder->Stop();
this->cat_buffer = recorder.GetBuffer();
qDebug() << "stopped";
return true;
}
bool MyRecorder::OnProcessSamples(const sf::Int16* Samples, std::size_t SamplesCount) {
SamplesCount = this->samplesCount;
emit processFinished();
return true;
}
void SignalCatcher::onProcessFinished() {
qDebug() << "finished";
this->stop();
}
-
Can you provide the complete definition and implementation of MyRecorder?
-
bool MyRecorder::OnProcessSamples(const sf::Int16* Samples, std::size_t SamplesCount) {
SamplesCount = this->samplesCount;
emit processFinished();
return true;
}
Ehm, the first line won't do a thing - will it? You're not passing it by reference into the function - so won't be able to read it from the outside. Or did you intend to do the assignment the other way around?
(Sorry if this is completely wrong - haven't dabbled in the Audio parts much - but that part stuck out like a sore thumb to me)
-
Main window .cpp file (shortened)
...
void JOP::on_btnStartRec_clicked()
{
cat = new SignalCatcher(&bufferCat, 12345, 44100);
cat->start();
}
void JOP::on_btnStopRec_clicked()
{
qDebug() << cat->cat_buffer.GetSamplesCount();
delete cat;
}
...
jop_signalcatcher.h
#ifndef JOP_SIGNALCATCHER_H
#define JOP_SIGNALCATCHER_H
#include <SFML/Audio.hpp>
#include "jop_core.h"
class MyRecorder : public QObject, public sf::SoundBufferRecorder
{
Q_OBJECT
private:
int samplesCount;
public:
MyRecorder(int samplesCount);
MyRecorder();
virtual bool OnProcessSamples(const sf::Int16* Samples, std::size_t SamplesCount);
signals:
void processFinished();
};
class SignalCatcher : public QObject
{
Q_OBJECT
private:
int sampleRate;
const unsigned int samplesCount;
public:
SignalCatcher(sf::SoundBuffer* snd_buffer, int samplesCount, int samplerate);
sf::SoundBuffer cat_buffer;
void setSampleRate(int smprate);
int getSampleRate();
bool start();
bool stop();
MyRecorder *recorder;
const sf::Int16* Samples;
public slots:
virtual void onProcessFinished();
};
#endif // JOP_SIGNALCATCHER_H
jop_signalcatcher.cpp
#include "jop_signalcatcher.h"
SignalCatcher::SignalCatcher(sf::SoundBuffer* snd_buffer, int samplesCount, int sampleRate = 44100): samplesCount(samplesCount)
{
this->recorder = new MyRecorder(samplesCount);
this->cat_buffer = *snd_buffer;
this->sampleRate = sampleRate;
QObject::connect(recorder, SIGNAL(processFinished()),
this, SLOT(onProcessFinished()));
}
bool SignalCatcher::start()
{
if (sf::SoundRecorder::CanCapture())
{
recorder->Start();
return true;
}
else {
return false;
}
}
bool SignalCatcher::stop()
{
recorder->Stop();
this->cat_buffer = recorder->GetBuffer();
qDebug() << "stopped";
return true;
}
bool MyRecorder::OnProcessSamples(const sf::Int16* Samples, std::size_t SamplesCount) {
SamplesCount = this->samplesCount;
emit processFinished();
return true;
}
MyRecorder::MyRecorder(int samplesCount) {
this->samplesCount = samplesCount;
}
MyRecorder::MyRecorder() {
this->samplesCount = 44100;
}
void SignalCatcher::onProcessFinished() {
qDebug() << "finished";
this->stop();
}
void SignalCatcher::setSampleRate(int smprate)
{
this->sampleRate = smprate;
}
int SignalCatcher::getSampleRate()
{
return sampleRate;
}
-
Here are the biggest mistakes that I can see in your code.
1. By overriding OnProcessSamples, sf::SoundBufferRecorder cannot work. It has its own implementation of OnProcessSamples, if you never call it you won't get any sample in the buffer.
2. I'm not sure you can call Stop() from OnProcessSamples, you must return false instead when you want to stop recording.
-
I realized that maybe I have to save Samples in OnProcessSamples(const sf::Int16* Samples, std::size_t SamplesCount) manually to SoundBuffer using LoadFromSamples().
But I still don't know how to change number of processed samples, I've found out that default SamplesCount is 44096. How can I change this number?
-
Do you want to change it, or only stop after a certain amount of samples? If you really want to change it, can you explain exactly what you want to achieve?
-
I only want to stop it after certain amount of samples
-
bool MyRecorder::OnProcessSamples(const sf::Int16* Samples, std::size_t SamplesCount)
{
sf::SoundBufferRecorder::OnProcessSamples(Samples, SamplesCount);
samplesCount += SamplesCount;
return samplesCount < limit;
}
Not perfect but I hope that you get the idea.
-
I think I get how you mean it. It is stopped when samplesCount exceeds the limit.
But firstly I use recorder for some electrical measurements which take less than a second (44100 samples) and secondly recorder's member variable "samplesCount" is the limit, it is amount of samples I want to record.
I think that your solution can control only whole seconds.
Is there a way to stop recording in less than one second, e.g. 1300 samples?
-
You can pass less samples to the base class
sf::SoundBufferRecorder::OnProcessSamples(Samples, this->samplesCount);
return false;
-
When I pasted this line:
sf::SoundBufferRecorder::OnProcessSamples(Samples, this->samplesCount);
I got this error:
‘virtual bool sf::SoundBufferRecorder::OnProcessSamples(const sf::Int16*, size_t)’ is private
How to fix it without editing SoundBufferRecorder.hpp?
-
Oh... sorry I didn't realize that. So forget about this code.
Well, do you need to stop the recorder exactly after a certain amount of samples, or is it acceptable to let it run slightly longer and adjust the number of samples later, in the returned sound buffer?
-
Of course, it can run slightly longer. It shouldn't affect the measurement, only increase a wait time of analyzing. And it also brings noticeable delay when I will use AUDIO IN as an oscilloscope.
Stop recording sooner would be perfect, unless it is difficult to implement.
I made this code yesterday:
bool MyRecorder::OnProcessSamples(const sf::Int16* Samples, std::size_t SamplesCount) {
buffer.LoadFromSamples(Samples, this->samplesCount, 1, 44100);
return false;
}
Did you mean it this way? Only imperfection is that it takes minimally one second.
-
Did you mean it this way?
More or less. The idea is to write your own recorder (not derived from sf::SoundBufferRecorder, but from sf::SoundRecorder directly) so that you can control how many samples you process.
class MyRecorder : public sf::SoundRecorder
{
bool OnProcessSamples(const Int16* Samples, std::size_t SamplesCount)
{
bool ok = true;
if (mySamples.size() + SamplesCount > myLimit)
{
ok = false;
SamplesCount = myLimit - mySamples.size();
}
std::copy(Samples, Samples + SamplesCount, std::back_inserter(mySamples));
return ok;
}
std::size_t myLimit;
std::vector<sf::Int16> mySamples;
};
Since you're using the collected samples to perform analysis, I don't think you need to store the samples in a sf::SoundBuffer; an array should be better.
Now, concerning the "lag", SFML calls OnProcessSamples every 100 ms so you should have a delay of 1 second.