C++ 在后台读取文件
C++ Read file in the background
我正在实现一个音频播放器应用程序,它预先缓冲一小部分音频数据并在需要时读取其余数据,例如播放命令到达时。这是一个实时应用程序,播放命令和播放开始之间的延迟几乎为零非常重要。
示例:我的音频流是 10 Mb,我在选择文件时读取其中的一部分并开始创建这样的缓冲区:
// Stuff to do as soon as the file is selected
// Allocate new memory for the current sample
// contains sample length in number of samples
sampleSize = SampleLib.smp.len;
// assume it's a 16-bit audio file, each sample is 2 bytes long
byteSize = sampleSize * sizeof(short);
// Allow 10 extra samples and fill with zeroes
SampleData = new short[sampleSize + 10]();
// PRELOAD_BYTESIZE is set to 65535 bytes
preloadByteSize = byteSize > PRELOAD_BYTESIZE ? PRELOAD_BYTESIZE : byteSize;
// Set pointer in file - WavePointer contains the exact location where the sample data starts in file
fseek(inFile, WavePointer, SEEK_SET);
// read preloadByteSize from inFile into SampleData
fread(SampleData, 1, preloadByteSize, inFile);
此时我的缓冲区 SampleData
仅包含部分音频数据,以便在播放命令到达时立即开始播放。同时,程序应填充缓冲区的其余部分并继续播放,直到音频样本结束而不会中断。
// Stuff to do as soon the playback starts
// Load the rest of the sample data
// If file is already in memory, avoid reading it again
if (preloadByteSize < ByteSize)
{
// Set pointer in file at stample start + preload size
fseek(fpFile, WavePointers + preloadByteSize, SEEK_SET);
// read the remaining bytes from inFile and fill the empty part of the buffer
fread(SampleData + preloadByteSize / sizeof(short), 1, ByteSize - preloadByteSize, inFile);
// remember the number of loaded bytes
preloadByteSize = ByteSize;
}
我希望第二部分代码在文件播放时在后台执行,但实际上它都是串行处理,所以直到缓冲区的其余部分加载完毕才会开始播放,从而延迟回放。
我可以有一个后台线程来加载文件数据而不干扰音频任务吗?我可以使用 OpenMP 执行此操作吗?
BackgroundWorker Class
这里有一些很好的例子:
您也许可以使用 OpenMP 执行此操作,但这涉及并发性而非并行性,因此我会查看 pthreads 或 C++11 线程:
这里我使用pthread启动了三个线程。它可能会给你一些工作......享受:
// g++ -o audio *.cpp ../common/*.cpp -std=c++11 -lm -lpthread
#include "cpp_openal_opengl_dna.h"
#include <thread>
#include <exception>
#include <mutex>
void launch_producer(Circular_Buffer * given_circular_buffer,
struct_sample_specs * ptr_struct_sample_specs, std::string chosen_file) {
}
void launch_mvc_visualization(Audio_Model * given_audio_model) {
}
void launch_audio_playback(Circular_Buffer * given_circular_buffer, Audio_Model * given_audio_model) {
}
int main() {
std::cout << "hello Corinde" << std::endl; // prints hello Corinde
// here we launch three threads
// thread t1 reads an input file to populate audio buffer
// notice the first parameter is the function above followed by its input parms
std::thread t1(launch_producer, circular_buffer, ptr_struct_sample_specs,
all_file_names[WHICH_FILE_INPUT]);
Audio_Model * audio_model = new Audio_Model(MAX_SIZE_CIRCULAR_BUFFER);
// thread t2 does real time OpenGL visualization of audio buffer data
std::thread t2(launch_mvc_visualization, audio_model); // OpenGL graphics visualization
// thread t3 renders the audio buffers as sound to your speakers
std::thread t3(launch_audio_playback, circular_buffer, audio_model);
// -------------------------
std::cout << "all three threads now launched" << std::endl;
t1.join();
t2.join();
t3.join();
std::cout << "processing is complete" << std::endl;
// ----------
return 0;
}
我想我刚刚使用 std::thread
和方法 detach()
解决了问题。
为此,每次我必须从中加载新的样本数据时,我都必须重新打开文件,所以我现在有一个全局变量来存储文件名并以这种方式调用函数:
// The loading function that will be executed in a new thread
void continuePreload(unsigned long ByteSize)
{
// Re-open the file 'openFile'
FILE *fpFile = fopen(openFile, "rb");
// Set pointer in file at stample start + preload size
fseek(fpFile, WavePointers + preloadByteSize, SEEK_SET);
// Read the remaining bytes
fread(SampleData + preloadByteSize / sizeof(short), 1, ByteSize - preloadByteSize, fpFile);
// Close file
fclose(fpFile);
// Remember how many bytes we loaded
preloadByteSize = ByteSize;
}
在播放事件功能中...
// Get the size in bytes
const unsigned long ByteSize = SampleLib.smp.len * sizeof(short);
if (preloadByteSize < ByteSize)
{
std::thread loadSample(&myClass::continuePreload, this, ByteSize);
loadSample.detach();
}
程序现在完全按照我的预期运行:每当播放事件到达时,它开始使用先前预加载的内容从样本缓冲区播放音频,同时新线程完成加载文件的剩余部分并完全填满缓冲区。
只要从磁盘加载比音频播放快,我们就没有竞争条件。如果加载太慢,我仍然可以增加预加载大小,稍微减慢初始加载时间。
我正在实现一个音频播放器应用程序,它预先缓冲一小部分音频数据并在需要时读取其余数据,例如播放命令到达时。这是一个实时应用程序,播放命令和播放开始之间的延迟几乎为零非常重要。
示例:我的音频流是 10 Mb,我在选择文件时读取其中的一部分并开始创建这样的缓冲区:
// Stuff to do as soon as the file is selected
// Allocate new memory for the current sample
// contains sample length in number of samples
sampleSize = SampleLib.smp.len;
// assume it's a 16-bit audio file, each sample is 2 bytes long
byteSize = sampleSize * sizeof(short);
// Allow 10 extra samples and fill with zeroes
SampleData = new short[sampleSize + 10]();
// PRELOAD_BYTESIZE is set to 65535 bytes
preloadByteSize = byteSize > PRELOAD_BYTESIZE ? PRELOAD_BYTESIZE : byteSize;
// Set pointer in file - WavePointer contains the exact location where the sample data starts in file
fseek(inFile, WavePointer, SEEK_SET);
// read preloadByteSize from inFile into SampleData
fread(SampleData, 1, preloadByteSize, inFile);
此时我的缓冲区 SampleData
仅包含部分音频数据,以便在播放命令到达时立即开始播放。同时,程序应填充缓冲区的其余部分并继续播放,直到音频样本结束而不会中断。
// Stuff to do as soon the playback starts
// Load the rest of the sample data
// If file is already in memory, avoid reading it again
if (preloadByteSize < ByteSize)
{
// Set pointer in file at stample start + preload size
fseek(fpFile, WavePointers + preloadByteSize, SEEK_SET);
// read the remaining bytes from inFile and fill the empty part of the buffer
fread(SampleData + preloadByteSize / sizeof(short), 1, ByteSize - preloadByteSize, inFile);
// remember the number of loaded bytes
preloadByteSize = ByteSize;
}
我希望第二部分代码在文件播放时在后台执行,但实际上它都是串行处理,所以直到缓冲区的其余部分加载完毕才会开始播放,从而延迟回放。 我可以有一个后台线程来加载文件数据而不干扰音频任务吗?我可以使用 OpenMP 执行此操作吗?
BackgroundWorker Class
这里有一些很好的例子:
您也许可以使用 OpenMP 执行此操作,但这涉及并发性而非并行性,因此我会查看 pthreads 或 C++11 线程:
这里我使用pthread启动了三个线程。它可能会给你一些工作......享受:
// g++ -o audio *.cpp ../common/*.cpp -std=c++11 -lm -lpthread
#include "cpp_openal_opengl_dna.h"
#include <thread>
#include <exception>
#include <mutex>
void launch_producer(Circular_Buffer * given_circular_buffer,
struct_sample_specs * ptr_struct_sample_specs, std::string chosen_file) {
}
void launch_mvc_visualization(Audio_Model * given_audio_model) {
}
void launch_audio_playback(Circular_Buffer * given_circular_buffer, Audio_Model * given_audio_model) {
}
int main() {
std::cout << "hello Corinde" << std::endl; // prints hello Corinde
// here we launch three threads
// thread t1 reads an input file to populate audio buffer
// notice the first parameter is the function above followed by its input parms
std::thread t1(launch_producer, circular_buffer, ptr_struct_sample_specs,
all_file_names[WHICH_FILE_INPUT]);
Audio_Model * audio_model = new Audio_Model(MAX_SIZE_CIRCULAR_BUFFER);
// thread t2 does real time OpenGL visualization of audio buffer data
std::thread t2(launch_mvc_visualization, audio_model); // OpenGL graphics visualization
// thread t3 renders the audio buffers as sound to your speakers
std::thread t3(launch_audio_playback, circular_buffer, audio_model);
// -------------------------
std::cout << "all three threads now launched" << std::endl;
t1.join();
t2.join();
t3.join();
std::cout << "processing is complete" << std::endl;
// ----------
return 0;
}
我想我刚刚使用 std::thread
和方法 detach()
解决了问题。
为此,每次我必须从中加载新的样本数据时,我都必须重新打开文件,所以我现在有一个全局变量来存储文件名并以这种方式调用函数:
// The loading function that will be executed in a new thread
void continuePreload(unsigned long ByteSize)
{
// Re-open the file 'openFile'
FILE *fpFile = fopen(openFile, "rb");
// Set pointer in file at stample start + preload size
fseek(fpFile, WavePointers + preloadByteSize, SEEK_SET);
// Read the remaining bytes
fread(SampleData + preloadByteSize / sizeof(short), 1, ByteSize - preloadByteSize, fpFile);
// Close file
fclose(fpFile);
// Remember how many bytes we loaded
preloadByteSize = ByteSize;
}
在播放事件功能中...
// Get the size in bytes
const unsigned long ByteSize = SampleLib.smp.len * sizeof(short);
if (preloadByteSize < ByteSize)
{
std::thread loadSample(&myClass::continuePreload, this, ByteSize);
loadSample.detach();
}
程序现在完全按照我的预期运行:每当播放事件到达时,它开始使用先前预加载的内容从样本缓冲区播放音频,同时新线程完成加载文件的剩余部分并完全填满缓冲区。
只要从磁盘加载比音频播放快,我们就没有竞争条件。如果加载太慢,我仍然可以增加预加载大小,稍微减慢初始加载时间。