- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试使用 Waveform Audio library 创建一个 C++ 程序这将播放另一个程序提供的 AudioFrames(原始音频数据,每帧包含大约 1920 个字节)(现在我只是通过将文件读取为 AudioFrames 来模拟它)。从 this thread 修改代码我能够制作完成这项工作的 SoundPlayer 类,但我得到的输出非常不稳定。帧大小越大越好,但即使帧大到 96000 字节,音频仍然每秒左右出现故障(我需要的帧也比这小得多)。
我该如何解决这个问题?
Here是我正在使用的测试文件。这是代码本身:
#include <windows.h>
#include <iostream>
#pragma comment(lib, "Winmm.lib")
constexpr int FRAME_SIZE_IN_BYTES = 1920;
struct AudioFrame
{
char *Data;
int DataSize;
};
class SoundPlayer
{
public:
SoundPlayer()
{
// Initialize the sound format we will request from sound card
m_waveFormat.wFormatTag = WAVE_FORMAT_PCM; // Uncompressed sound format
m_waveFormat.nChannels = 1; // 1 = Mono, 2 = Stereo
m_waveFormat.wBitsPerSample = 16; // Bits per sample per channel
m_waveFormat.nSamplesPerSec = 48000; // Sample Per Second
m_waveFormat.nBlockAlign = m_waveFormat.nChannels * m_waveFormat.wBitsPerSample / 8;
m_waveFormat.nAvgBytesPerSec = m_waveFormat.nSamplesPerSec * m_waveFormat.nBlockAlign;
m_waveFormat.cbSize = 0;
}
void Play(AudioFrame* af)
{
// Create our "Sound is Done" event
m_done = CreateEvent(0, FALSE, FALSE, 0);
// Open the audio device
if (waveOutOpen(&m_waveOut, 0, &m_waveFormat, (DWORD)m_done, 0, CALLBACK_EVENT) != MMSYSERR_NOERROR)
{
std::cout << "Sound card cannot be opened." << std::endl;
return;
}
// Create the wave header for our sound buffer
m_waveHeader.lpData = af->Data;
m_waveHeader.dwBufferLength = af->DataSize;
m_waveHeader.dwFlags = 0;
m_waveHeader.dwLoops = 0;
// Prepare the header for playback on sound card
if (waveOutPrepareHeader(m_waveOut, &m_waveHeader, sizeof(m_waveHeader)) != MMSYSERR_NOERROR)
{
std::cout << "Error preparing Header!" << std::endl;
return;
}
ResetEvent(m_done); // Reset our Event so it is non-signaled, it will be signaled again with buffer finished
// Play the sound!
if (waveOutWrite(m_waveOut, &m_waveHeader, sizeof(m_waveHeader)) != MMSYSERR_NOERROR)
{
std::cout << "Error writing to sound card!" << std::endl;
return;
}
// Wait until sound finishes playing
if (WaitForSingleObject(m_done, INFINITE) != WAIT_OBJECT_0)
{
std::cout << "Error waiting for sound to finish" << std::endl;
return;
}
// Unprepare our wav header
if (waveOutUnprepareHeader(m_waveOut, &m_waveHeader, sizeof(m_waveHeader)) != MMSYSERR_NOERROR)
{
std::cout << "Error unpreparing header!" << std::endl;
return;
}
// Close the wav device
if (waveOutClose(m_waveOut) != MMSYSERR_NOERROR)
{
std::cout << "Sound card cannot be closed!" << std::endl;
return;
}
// Release our event handle
CloseHandle(m_done);
}
private:
HWAVEOUT m_waveOut; // Handle to sound card output
WAVEFORMATEX m_waveFormat; // The sound format
WAVEHDR m_waveHeader; // WAVE header for our sound data
HANDLE m_done; // Event Handle that tells us the sound has finished being played.
// This is a very efficient way to put the program to sleep
// while the sound card is processing the sound buffer
};
int main()
{
FILE * fileDes;
fopen_s(&fileDes, "Ducksauce.raw", "rb");
if (fileDes == nullptr)
std::cout << "File opening failed.\n";
int bufferSize = FRAME_SIZE_IN_BYTES;
char *buffer = new char[bufferSize];
SoundPlayer sp;
while (fread(buffer, sizeof(char), bufferSize, fileDes) > 0)
{
AudioFrame af;
af.Data = buffer;
af.DataSize = bufferSize;
sp.Play(&af);
}
fclose(fileDes);
delete[] buffer;
return 0;
}
编辑:版本号 2。仍然没有按预期工作。
#include <windows.h>
#include <iostream>
#pragma comment(lib, "Winmm.lib")
constexpr int FRAME_SIZE_IN_BYTES = 1920;
struct AudioFrame
{
char *Data;
int DataSize;
};
class SoundPlayer
{
public:
SoundPlayer()
{
// Initialize the sound format we will request from sound card
m_waveFormat.wFormatTag = WAVE_FORMAT_PCM; // Uncompressed sound format
m_waveFormat.nChannels = 1; // 1 = Mono, 2 = Stereo
m_waveFormat.wBitsPerSample = 16; // Bits per sample per channel
m_waveFormat.nSamplesPerSec = 48000; // Sample Per Second
m_waveFormat.nBlockAlign = m_waveFormat.nChannels * m_waveFormat.wBitsPerSample / 8;
m_waveFormat.nAvgBytesPerSec = m_waveFormat.nSamplesPerSec * m_waveFormat.nBlockAlign;
m_waveFormat.cbSize = 0;
// Create our "Sound is Done" event
m_done = CreateEvent(0, FALSE, FALSE, 0);
// Open the audio device
if (waveOutOpen(&m_waveOut, 0, &m_waveFormat, (DWORD)m_done, 0, CALLBACK_EVENT) != MMSYSERR_NOERROR)
{
std::cout << "Sound card cannot be opened." << std::endl;
return;
}
}
~SoundPlayer()
{
// Close the wav device
if (waveOutClose(m_waveOut) != MMSYSERR_NOERROR)
{
std::cout << "Sound card cannot be closed!" << std::endl;
return;
}
// Release our event handle
CloseHandle(m_done);
}
void StartPlaying(AudioFrame* af)
{
// Create the wave header for our sound buffer
m_waveHeader.lpData = af->Data;
m_waveHeader.dwBufferLength = af->DataSize;
m_waveHeader.dwFlags = 0;
m_waveHeader.dwLoops = 0;
// Prepare the header for playback on sound card
if (waveOutPrepareHeader(m_waveOut, &m_waveHeader, sizeof(m_waveHeader)) != MMSYSERR_NOERROR)
{
std::cout << "Error preparing Header!" << std::endl;
return;
}
ResetEvent(m_done); // Reset our Event so it is non-signaled, it will be signaled again with buffer finished
// Play the sound!
if (waveOutWrite(m_waveOut, &m_waveHeader, sizeof(m_waveHeader)) != MMSYSERR_NOERROR)
{
std::cout << "Error writing to sound card!" << std::endl;
return;
}
}
void WaitUntilFrameFinishes()
{
// Wait until sound finishes playing
if (WaitForSingleObject(m_done, INFINITE) != WAIT_OBJECT_0)
{
std::cout << "Error waiting for sound to finish" << std::endl;
return;
}
// Unprepare our wav header
if (waveOutUnprepareHeader(m_waveOut, &m_waveHeader, sizeof(m_waveHeader)) != MMSYSERR_NOERROR)
{
std::cout << "Error unpreparing header!" << std::endl;
return;
}
}
private:
HWAVEOUT m_waveOut; // Handle to sound card output
WAVEFORMATEX m_waveFormat; // The sound format
WAVEHDR m_waveHeader; // WAVE header for our sound data
HANDLE m_done; // Event Handle that tells us the sound has finished being played.
// This is a very efficient way to put the program to sleep
// while the sound card is processing the sound buffer
};
int main()
{
FILE * fileDes;
fopen_s(&fileDes, "Ducksauce.raw", "rb");
if (fileDes == nullptr)
std::cout << "File opening failed.\n";
int bufferSize = FRAME_SIZE_IN_BYTES;
char *buffer = new char[bufferSize];
SoundPlayer sp;
// Read first time
fread(buffer, sizeof(char), bufferSize, fileDes);
while (true)
{
AudioFrame af;
af.Data = buffer;
af.DataSize = bufferSize;
// Start playing, but don't block
sp.StartPlaying(&af);
// Prepare the next chunk
if (fread(buffer, sizeof(char), bufferSize, fileDes) <= 0)
break;
// Now block the code, waiting with next chunk already loaded
// and ready to be played in the next iteration.
sp.WaitUntilFrameFinishes();
}
fclose(fileDes);
delete[] buffer;
return 0;
}
编辑 2:如果我在 while 之前添加它,它会起作用:
for (int i = 0; i < 3; i++ )
{
fread(buffer, sizeof(char), bufferSize, fileDes);
af.Data = buffer;
af.DataSize = bufferSize;
sp.StartPlaying(&af);
}
我也修改了一下:
while (true)
{
// Prepare the next chunk
if (fread(buffer, sizeof(char), bufferSize, fileDes) <= 0)
break;
// Now block the code, waiting with next chunk already loaded
// and ready to be played in the next iteration.
sp.WaitUntilFrameFinishes();
af.Data = buffer;
af.DataSize = bufferSize;
sp.StartPlaying(&af);
}
最佳答案
您应该在播放声音时从磁盘读取数据,而不是在缓冲区之间!
如果您不能一次读取整个文件,您应该更改您的Play
函数,使其不只是调用WaitForSingleObject
。使用它会使您的代码阻塞并等待声音停止播放。
您需要的是开始播放,然后返回您的阅读循环,准备下一个缓冲区,然后等待音乐结束,就像这样(在 SoundPlayer
):
void WaitUntilFrameFinishes() {
// Wait until sound finishes playing
if (WaitForSingleObject(m_done, INFINITE) != WAIT_OBJECT_0)
// ... move all the code from Play till the end here
}
然后回到主
循环:
// Read first frame
fread(buffer, sizeof(char), bufferSize, fileDes);
while (true)
{
AudioFrame af;
af.Data = buffer;
af.DataSize = bufferSize;
// Start playing, but don't block
sp.Play(&af);
// Prepare the next chunk
if (fread(buffer, sizeof(char), bufferSize, fileDes) <= 0) {
break;
// Now block the code, waiting with next chunk already loaded
// and ready to be played in the next iteration.
sp.WaitUntilFrameFinishes();
}
理想情况下,您还将 fread
调用包装到可以以更好的方式提供 block 的东西中。
关于c++ - 波形音频 - waveOutWrite 发出断断续续的声音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52056127/
我将简要介绍一下我的应用程序的所有元素: 我有一个将音频记录到 AVAudioPCMBuffer 的应用程序。然后将该缓冲区转换为 NSData,然后转换为 [UInt8]。然后通过 OutputSt
我正在用 Java 制作一个非常简单的乒乓球游戏,并且我正在使用 KeyListener 进行此操作。我想要它,所以当用户按下键盘上的向右或向左键时,乒乓 block 会朝那个方向移动。这是一个足够简
我正在用 Java 制作一个非常简单的乒乓球游戏,并且我正在使用 KeyListener 进行此操作。我想要它,所以当用户按下键盘上的向右或向左键时,乒乓 block 会朝那个方向移动。这是一个足够简
所以我一直遇到动画问题,尤其是当两个动画同时发生或在 Activity 加载时发生时。我知道这可能是资源问题,并且主线程中发生了很多事情,导致动画卡顿。 我发现了一些有趣的建议: 1.线程(Threa
我推一个ViewController其中包含的 View 不多,UIScrollView其中包含 10 个 View ,我有一个单例 ViewController并一次次推,不释放和再次分配ViewC
矩形应该向下移动,先向左然后向右。但出于某种原因,他们只是有点“跳跃”。谁能告诉我为什么? .imgbox { position: relative; float:left;
我的动画有问题。我正在写一个由标题、正文(对话框所在的位置)和输入字段组成的聊天。它的位置是这样的: .chatWindowContainer { display: flex; fle
我有一个项目正在渲染视频播放并对其应用 CIFilters。我知道我可以使用视频合成来获取带滤镜的视频,但问题是滤镜需要可滑动(预览下一个滤镜,因此我们对第一个 ImageView 使用 mask ,
我正在处理过渡,当过渡应用于不同函数中的选择时,我注意到有些卡顿和闪烁。但是,如果转换与方法链一起应用,它会完全按照规定工作。 下面是简单移动一些文本的小例子(Fiddle)。在过渡开始之前,最左边的
我的适配器正确地将图像应用到 RecyclerView 并正确滚动……直到我添加大量项目。然后它变得相当不稳定,我知道这是我的方法的问题。请看下面的代码: class FragmentMenuView
我试图在用户提交表单后滚动到页面底部。但是,当我执行以下代码时,浏览器会滚动到页面底部,但不允许我在没有锁定/关闭/抖动的情况下向上滚动(通过鼠标滚轮、滚动条或箭头键)。 var scrollToBo
问题 我正在尝试让 Canvas 上的图像从左向右平滑移动。它在 Chrome/Safari 上还不错(仍然有点卡顿),但在多台机器上的 Firefox 中有明显的卡顿(在 Windows 和 Mac
我无法在 SceneKit 中获得平滑的阴影。您将在下面找到将灯光和图片添加到我的场景的代码。我圈出了像素化的区域。 即使是 SceneKit 提供的基本几何图形也无法正确着色。 有谁知道我该如何解决
我正在制作一个简单的应用程序,允许用户每天写一两句话来描述他们的一天。 我有一个 UICollectionView 将每一天显示为一个单元格。在该单元格中,有一个 UITextView,用户可以在其中
我在使用 UITableView 时遇到了这个问题,tableView 的 cells 高度不同,自动布局约束设置不当。当您向下滚动到 tableView 的底部并加载更多数据(无论使用 reload
我正在尝试创建一个包含一堆 block 的页面(通常包含可以通过单击框展开的“溢出:隐藏”文本)。但是,当我单击该框以调整其高度(以显示所有文本)时,我还想通过使用 ScrollTop 使该框成为焦点
我的程序绘制了在窗口上移动的圆圈。我想我一定是遗漏了一些基本的 gtk/cairo 概念,因为对于我正在做的事情来说,它似乎运行得太慢/断断续续。有任何想法吗?感谢您的帮助! #!/usr/bin/p
目前我有一个 UITableView,里面有一个可以调整大小的 UITextView。该单元格正在使用 beginUpdates/endUpdates 自动调整大小,但是当它这样做时,表格 View
我是一名优秀的程序员,十分优秀!