SFML community forums

Help => Audio => Topic started by: LuckyNeo on March 13, 2011, 11:11:37 am

Title: I need to limit the number of recorded samples
Post 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?
Title: I need to limit the number of recorded samples
Post by: Laurent on March 13, 2011, 07:52:31 pm
There's a tutorial with a complete working source code. Have you tried it?
Title: I need to limit the number of recorded samples
Post by: LuckyNeo on March 14, 2011, 11:51:54 am
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:
Code: [Select]
SamplesCount = 1300;
and then stopped through signal
Code: [Select]
emit ProcessFinished(), in slot there is
Code: [Select]
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.
Title: I need to limit the number of recorded samples
Post by: Laurent on March 14, 2011, 12:11:19 pm
Can you show a complete and minimal source code that reproduces this problem?
Title: I need to limit the number of recorded samples
Post by: LuckyNeo on March 15, 2011, 07:10:57 am
Code: [Select]



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();
}
Title: I need to limit the number of recorded samples
Post by: Laurent on March 15, 2011, 07:42:13 am
Can you provide the complete definition and implementation of MyRecorder?
Title: I need to limit the number of recorded samples
Post by: devlin on March 15, 2011, 08:25:23 am
Code: [Select]
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)
Title: I need to limit the number of recorded samples
Post by: LuckyNeo on March 15, 2011, 05:38:36 pm
Main window .cpp file (shortened)
Code: [Select]

...
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
Code: [Select]


#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
Code: [Select]


#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;
}
Title: I need to limit the number of recorded samples
Post by: Laurent on March 15, 2011, 06:08:25 pm
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.
Title: I need to limit the number of recorded samples
Post by: LuckyNeo on March 15, 2011, 06:16:42 pm
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?
Title: I need to limit the number of recorded samples
Post by: Laurent on March 15, 2011, 07:00:28 pm
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?
Title: I need to limit the number of recorded samples
Post by: LuckyNeo on March 15, 2011, 07:03:37 pm
I only want to stop it after certain amount of samples
Title: I need to limit the number of recorded samples
Post by: Laurent on March 15, 2011, 07:12:35 pm
Code: [Select]
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.
Title: I need to limit the number of recorded samples
Post by: LuckyNeo on March 15, 2011, 08:14:44 pm
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?
Title: I need to limit the number of recorded samples
Post by: Laurent on March 15, 2011, 08:45:43 pm
You can pass less samples to the base class
Code: [Select]
sf::SoundBufferRecorder::OnProcessSamples(Samples, this->samplesCount);
return false;
Title: I need to limit the number of recorded samples
Post by: LuckyNeo on March 15, 2011, 11:02:56 pm
When I pasted this line:
Code: [Select]
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?
Title: I need to limit the number of recorded samples
Post by: Laurent on March 16, 2011, 08:04:16 am
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?
Title: I need to limit the number of recorded samples
Post by: LuckyNeo on March 16, 2011, 04:09:50 pm
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:

Code: [Select]
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.
Title: I need to limit the number of recorded samples
Post by: Laurent on March 16, 2011, 04:32:18 pm
Quote
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.

Code: [Select]
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.