Annoying tick with speex [closed]

前提是你 提交于 2019-12-11 04:09:44

问题


I am making an application in which I use Speex, OpenAL and linsndfile.

The problem is that when i write a sample buffer in the file (raw pcm unsigned 16) using libsndfile everything is right.But if i encode them, then decode them using Spexx, I get like a 'tick' between each sample. I first though about a sample loss or some buffer being too big. But i did'nt find anything. At first the code was in an architecture with boost threads and was splitted in multiple classes. Even whith this minimal code, my problem is still.

Here is the full minimal code which produce the problem. Thanks for you help.

#include <iostream>
#include <stdexcept>
#include <vector>
#include <cstring>
#include <algorithm>
#include <sndfile.h>
#include <AL/al.h>
#include <AL/alc.h>
#include <speex/speex.h>

typedef std::vector<ALshort> Samples;

std::string chooseDevice()
{
    std::vector<std::string> ret;
    const ALCchar* DeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);

    int i = 0;
    if (DeviceList)
        while (strlen(DeviceList) > 0) {
            std::string tmp = DeviceList;
            ret.push_back(tmp);
            DeviceList += strlen(DeviceList) + 1;
            std::cout << i++  <<  ": " <<  tmp << std::endl;
        }
    std::cout << "Choose a device : " << std::flush;
    if (!(std::cin >> i))
        throw std::runtime_error("NaN");
    return ret[i];
}

SNDFILE* openFile()
{
    SNDFILE* file;
    SF_INFO fileInfo;
    fileInfo.channels = 1;
    fileInfo.samplerate = 8000;
    fileInfo.format = SF_FORMAT_PCM_16 | SF_FORMAT_WAV;
    file = sf_open("capture.wav", SFM_WRITE, &fileInfo);
    if (!file)
        throw std::runtime_error("SNDFILE error");
    return file;
}

enum Mode {DIRECT = 1, ENCODE_AND_DECODE};

void writeToFile(SNDFILE* file, const Samples& samples, const Mode mode)
{
    static std::vector<ALshort> buffer;
    switch (mode) {
        case DIRECT: sf_write_short(file, &samples[0], samples.size()); break;      // Ecriture ici
        case ENCODE_AND_DECODE: {
                std::copy(samples.begin(), samples.end(), std::back_inserter(buffer));
                int frameSize;
                void* encoderState = speex_encoder_init(&speex_wb_mode);
                speex_encoder_ctl(encoderState, SPEEX_GET_FRAME_SIZE, &frameSize);

                // AL pourrait donner trop ou pas assez d'échantillons
                while (buffer.size() >= frameSize) {
                    // encodage
                    void* encoderState = speex_encoder_init(&speex_wb_mode);
                    SpeexBits bits;
                    speex_encoder_ctl(encoderState, SPEEX_GET_FRAME_SIZE, &frameSize);
                    buffer.reserve(2*frameSize);
                    std::vector<char> output;
                    output.resize(2*frameSize);
                    speex_bits_init(&bits);
                    speex_encode_int(encoderState, &buffer[0], &bits);
                    int bytes = speex_bits_write(&bits, &output[0], output.size());
                    speex_bits_destroy(&bits);
                    speex_encoder_destroy(encoderState);

                    // décodage
                    speex_bits_init(&bits);
                    encoderState = speex_decoder_init(&speex_wb_mode);
                    speex_encoder_ctl(encoderState, SPEEX_GET_FRAME_SIZE, &frameSize);
                    speex_bits_read_from(&bits, &output[0], bytes);
                    std::vector<short> samples(frameSize); 
                    speex_decode_int(encoderState, &bits, &samples[0]);
                    sf_write_short(file, &samples[0], frameSize);                         // Ecriture ici
                    speex_decoder_destroy(encoderState);
                    speex_bits_destroy(&bits);
                    buffer.erase(buffer.begin(), buffer.begin()+frameSize);
                    std::cout << "." << std::flush;
                }
            }
            break;
    }
}

void closeFile(SNDFILE* file)
{
    sf_close(file);
    std::cout << "enregistré dans capture.wav" << std::endl;
}

int main()
{
    ALCdevice* device;
    ALCdevice* captureDevice;
    ALCcontext* context;

    device = alcOpenDevice(0);
    if (!device)
        throw std::runtime_error("Unable to open the AL device");
    context = alcCreateContext(device, 0);
    if (!context)
        throw std::runtime_error("Unable to create AL context");
    if (!alcMakeContextCurrent(context))
        throw std::runtime_error("Unable to set the context");
    if (alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_FALSE)
        throw std::runtime_error("AL Capture extension not available");
    captureDevice = alcCaptureOpenDevice(chooseDevice().c_str(), 8000, AL_FORMAT_MONO16, 8000);
    if (!captureDevice)
        throw std::runtime_error("Unable to open the capture device");

    Samples samples;

    SNDFILE* file = openFile();
    std::cout << "Mode direct (1) ou encodage et décodage ? (2) : " << std::endl;
    int i;
    std::cin >> i;
    Mode mode = Mode(i);
    time_t start = time(0);
    alcCaptureStart(captureDevice);
    while (time(0) - start < 5) {
        ALCint availableSamples;
        alcGetIntegerv(captureDevice, ALC_CAPTURE_SAMPLES, 1, &availableSamples);
        if (availableSamples > 0) {
            samples.resize(availableSamples);
            alcCaptureSamples(captureDevice, &samples[0], availableSamples);
            writeToFile(file, samples, mode); 
        }
    }
    alcCaptureStop(captureDevice);
    closeFile(file);
    alcCaptureCloseDevice(captureDevice);
    alcMakeContextCurrent(0);
    alcDestroyContext(context);
    alcCloseDevice(device);
}

-lspeex -lsndfile -lopenal


回答1:


Well, put it this way, if you didn't need to keep the same state for all the frames you decode, there would be no state object in the first place.



来源:https://stackoverflow.com/questions/7347929/annoying-tick-with-speex

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!