讨厌的速度蜱虫
Annoying tick with speex
我正在制作一个使用Speex, OpenAL和linsndfile的应用程序。
问题是,当我使用libsndfile在文件(原始pcm unsigned 16)中写入示例缓冲区时,一切都是正确的。但如果我对它们进行编码,然后使用Spexx进行解码,我就会在每个样本之间得到一个"刻度"。我首先想到的是样本丢失或缓冲区太大。但是我什么也没找到。起初,代码是在一个带有boost线程的体系结构中,并被拆分为多个类。即使有了这么少的代码,我的问题仍然是。
下面是产生这个问题的完整的最小代码。谢谢你的帮助。
#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
这么说,如果你不需要为你解码的所有帧保持相同的状态,那么首先就不会有状态对象了
相关文章:
- 为什么在读取文件大小时文件IO速度会发生变化
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- 文件系统:复制功能的速度秘诀是什么
- 学习多线程C++:添加线程不会使执行速度更快,即使它看起来应该
- 在C++中使用并行化的预期速度是多少(不是 OpenMp,而是 <thread>)
- 两个连续的 OpenMP 并行区域会相互减慢速度
- 查找标准::hash_map与标准::矢量的速度
- 加快在C++中读取/处理日志文件的速度
- 为什么这些算法的运行速度比它们应该的要快?
- 如何提高文件的读取速度?
- 通过libpqxx提高PostgreSQL数据库的更新速度
- 使用 IMFSinkWriter 编码的视频的播放速度会根据宽度而变化
- 计算车辆之间的距离并设置速度,使距离保持不变,例如 5 米
- 如何加快大字符串的解析速度?
- 使用 reverse_iterator 而不是const_reverse_iterator并获得讨厌的编译器警告和错误
- 如何比较两个函数的速度和性能
- 线程相互减慢速度
- 多线程减慢程序速度:无错误共享,无互斥锁,无缓存未命中,无小工作量
- 使用 Unity 构建加快C++构建速度,并减少标头依赖项
- 讨厌的速度蜱虫