- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
此问题是前一个问题 ( Audio producer threads with OSX AudioComponent consumer thread and callback in C ) 的后续问题,包括一个测试示例,该示例的工作和行为符合预期,但没有完全回答问题。我已经大幅改写了问题,并重新编码了示例,以便它仅包含纯 C 代码。 (我发现前一个示例中的少数 Objective-C 代码部分只会造成困惑并分散读者对问题本质的注意力。)
为了利用多个处理器核心以及使 CoreAudio 拉模型渲染线程尽可能轻量,LPCM 示例的生成器例程显然必须“坐在”不同的线程,在实时优先级渲染线程/回调之外。它必须将样本提供给循环缓冲区(本例中为TPCircularBuffer),系统将从该缓冲区安排以 inNumberFrames 为单位的数据提取。
Grand Central Dispatch API 提供了一个简单的解决方案,这是我根据一些个人研究(包括试错编码)推断出来的。这个解决方案很优雅,因为它不会阻止任何内容,也不会在推模型和拉模型之间发生冲突。然而,应该负责“子线程”的 GCD 到目前为止还不能满足生产者代码工作线程的特定并行化要求,因此我必须显式地生成一些POSIX 线程,取决于可用逻辑核心的数量。尽管在加速计算方面结果已经很显着,但我仍然觉得混合 POSIX 和 GCD 有点不舒服。特别是它适用于变量 wait_interval,并正确计算它,而不是通过预测渲染线程下一个周期可能需要多少个 PCM 样本。
这是我的测试程序的缩短和简化的(伪)代码,采用纯 C 语言。
Controller 声明:
#include "TPCircularBuffer.h"
#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AudioUnit.h>
#include <dispatch/dispatch.h>
#include <sys/sysctl.h>
#include <pthread.h>
typedef struct {
TPCircularBuffer buffer;
AudioComponentInstance toneUnit;
Float64 sampleRate;
AudioStreamBasicDescription streamFormat;
Float32* f; //array of updated frequencies
Float32* a; //array of updated amps
Float32* prevf; //array of prev. frequencies
Float32* preva; //array of prev. amps
Float32* val;
int* arg;
int* previous_arg;
UInt32 frames;
int state;
Boolean midif; //wip
} MyAudioController;
MyAudioController gen;
dispatch_semaphore_t mSemaphore;
Boolean multithreading, NF;
typedef struct data{
int tid;
int cpuCount;
}data;
Controller 管理:
void setup (void){
// Initialize circular buffer
TPCircularBufferInit(&(self->buffer), kBufferLength);
// Create the semaphore
mSemaphore = dispatch_semaphore_create(0);
// Setup audio
createToneUnit(&gen);
}
void dealloc (void) {
// Release buffer resources
TPCircularBufferCleanup(&buffer);
// Clean up semaphore
dispatch_release(mSemaphore);
// dispose of audio
if(gen.toneUnit){
AudioOutputUnitStop(gen.toneUnit);
AudioUnitUninitialize(gen.toneUnit);
AudioComponentInstanceDispose(gen.toneUnit);
}
}
调度程序调用(从主线程启动生产者队列):
void dproducer (Boolean on, Boolean multithreading, Boolean NF)
{
if (on == true)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
if((multithreading)||(NF))
producerSum(on);
else
producer(on);
});
}
return;
}
可线程生产者例程:
void producerSum(Boolean on)
{
int rc;
int num = getCPUnum();
pthread_t threads[num];
data thread_args[num];
void* resulT;
static Float32 frames [FR_MAX];
Float32 wait_interval;
int bytesToCopy;
Float32 floatmax;
while(on){
wait_interval = FACT*(gen.frames)/(gen.sampleRate);
Float32 damp = 1./(Float32)(gen.frames);
bytesToCopy = gen.frames*sizeof(Float32);
memset(frames, 0, FR_MAX*sizeof(Float32));
availableBytes = 0;
fbuffW = (Float32**)calloc(num + 1, sizeof(Float32*));
for (int i=0; i<num; ++i)
{
fbuffW[i] = (Float32*)calloc(gen.frames, sizeof(Float32));
thread_args[i].tid = i;
thread_args[i].cpuCount = num;
rc = pthread_create(&threads[i], NULL, producerTN, (void *) &thread_args[i]);
}
for (int i=0; i<num; ++i) rc = pthread_join(threads[i], &resulT);
for(UInt32 samp = 0; samp < gen.frames; samp++)
for(int i = 0; i < num; i++)
frames[samp] += fbuffW[i][samp];
//code for managing producer state and GUI updates
{ ... }
float *head = TPCircularBufferHead(&(gen.buffer), &availableBytes);
memcpy(head,(const void*)frames,MIN(bytesToCopy, availableBytes));//copies frames to head
TPCircularBufferProduce(&(gen.buffer),MIN(bytesToCopy,availableBytes));
dispatch_semaphore_wait(mSemaphore, dispatch_time(DISPATCH_TIME_NOW, wait_interval * NSEC_PER_SEC));
if(gen.state == stopped){gen.state = idle; on = false;}
for(int i = 0; i <= num; i++)
free(fbuffW[i]);
free(fbuffW);
}
return;
}
单个生产者线程可能看起来有点像这样:
void *producerT (void *TN)
{
Float32 samples[FR_MAX];
data threadData;
threadData = *((data *)TN);
int tid = threadData.tid;
int step = threadData.cpuCount;
int *ret = calloc(1,sizeof(int));
do_something(tid, step, &samples);
{ … }
return (void*)ret;
}
这是渲染回调(CoreAudio 实时消费者线程):
static OSStatus audioRenderCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
MyAudioController *THIS = (MyAudioController *)inRefCon;
// An event happens in the render thread- signal whoever is waiting
if (THIS->state == active) dispatch_semaphore_signal(mSemaphore);
// Mono audio rendering: we only need one target buffer
const int channel = 0;
Float32* targetBuffer = (Float32 *)ioData->mBuffers[channel].mData;
memset(targetBuffer,0,inNumberFrames*sizeof(Float32));
// Pull samples from circular buffer
int32_t availableBytes;
Float32 *buffer = TPCircularBufferTail(&THIS->buffer, &availableBytes);
//copy circularBuffer content to target buffer
int bytesToCopy = ioData->mBuffers[channel].mDataByteSize;
memcpy(targetBuffer, buffer, MIN(bytesToCopy, availableBytes));
{ … };
TPCircularBufferConsume(&THIS->buffer, availableBytes);
THIS->frames = inNumberFrames;
return noErr;
}
最佳答案
Grand Central Dispatch 已经负责将操作分派(dispatch)到多个处理器核心和线程。在典型的实时音频渲染或处理中,人们永远不需要等待信号或信号量,因为循环缓冲区消耗率是非常可预测的,并且随着时间的推移漂移得非常缓慢。 AVAudioSession API(如果可用)和音频单元 API 和回调允许您设置和确定回调缓冲区大小,从而设置和确定循环缓冲区可以更改的最大速率。因此,您可以在计时器上调度所有渲染操作,渲染每个计时器周期所需的确切数量,并让缓冲区大小和状态补偿线程调度时间中的任何抖动。
在运行时间极长的音频渲染中,您可能需要测量计时器操作和实时音频消耗(采样率)之间的偏差,并调整渲染的样本数量或计时器偏移量。
关于c - 音频样本生成器多线程 OSX,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34241278/
我正在处理不平衡的面板数据,我想从中抽取一个随机样本,该样本不受每个单位不同观察次数的影响。例如,在下面的代码中,IBM 被选中的可能性是 GOOG 的两倍,被选中的可能性是 MSFT 的五倍。有没有
有人可以指出实现 CollectionChanged 的示例。我正在使用 wpf mvvm 灯。我试图谷歌,没有找到任何足够好的东西。 最佳答案 public ObservableCollecti
我有 df我想对某些变量的分布进行一些抽样。比方说 df['type'].value_counts(normalize=True)返回: 0.3 A 0.5 B 0.2 C 我想做类似 sampled
我仍然无法理解样本/像素/片段之间有什么区别。 由于片段着色器按像素执行,我认为片段只是指一个像素,这是正确的吗?谁能给我一个例子和每个人的定义? 最佳答案 片段着色器按片段执行并发出像素。它们非常相
我正在尝试理解这个名为“The Amazing Audio Engine”的 GitHub 项目,它简化了在 iOS 上处理音频的过程。 我从麦克风捕捉并使用这种方法: id receiver = [
如何在诺基亚 Qt SDK(用于手机)中使用 QTableView。我引用了一些文档,但我仍然不清楚 QTableView。请任何人建议如何使用 QTableView。 我想显示具有三列的 QTabl
我已经能够获取 JmDNS 附带的示例来编译和运行,但是我无法获取任何类来发现我的服务。 我正在运行一个 Windows 环境,多台 PC 运行 VNC、SSH 和 Apache,我一直在尝试让 Jm
问题的具体实例 我的整数范围是 1-100。我想生成此范围内的 n 个总数,这些数字尽可能均匀分布并包括第一个和最后一个值。 示例 start = 1, end = 100, n = 5 Outp
我在线程组中有几个带有脚本的 JSR 223 采样器,它们在执行在调用 HTTP 请求之前进行一些工作。 问题在于 JSR 233 采样器包含在最终摘要报告中 我的问题是如何从最终计算中排除那些 JS
我需要有关存储后端歌曲预览的好方法的建议(现在正在查看iTunes,也许还有spotify和soundcloud)。我的想法是,我需要预下载并可能缓存30秒及更少的音频文件,以方便召回。 然后,我需要
我刚刚从 Github 下载了 Atmosphere 样本。当我在聊天样本上运行 jetty:run goal 时,我遇到了一些问题。 我可以使用浏览器访问该页面(http://localhost:9
我有一个包含五个项目的向量。 my_vec 有更换,当我需要时没有更换。最有效的方法是什么? 请注意,在我的向量中,我有两次值“a” - 因此,在返回的打乱向量集中,它们都应该有两次“a”。 最佳答案
我正在尝试学习如何阅读规范。让我们看看尝试压缩后会得到什么:1) 一个空缓冲区和 2) 一个感叹号: >>> zlib.compress(b'', 0) b'x\x01\x01\x00\x00\xff
我是 cuda 的新手,几周前才开始阅读有关并行编程和 cuda 的内容。在我安装了 cuda 工具包之后,我正在浏览 sdk 示例(安装工具包时附带的)并想尝试其中的一些。我从 0_Simple 文
我正在使用 FsCheck 生成自定义数据的 Gen . 假设你有一个函数返回 Gen : let chooseRectangle widthMax heightMax offset = gen
我有一个包含大约 800 万个观察值的数据框。我需要从中提取样本,但想从多个列中采样。 我尝试了以下方法,但不起作用: import pandas as pd state = ['mi', 'mi',
我学习安卓图形,我遇到了一个奇怪的问题: 我发现很多提到“FingerPaint”样本的地方,但我在样本文件夹中找不到它。 只有 47 个示例项目,没有一个是关于图形的。 如何下载此示例?我按照这
假设我有一个 pandas 数据框 rid category 0 0 c2 1 1 c3 2 2 c2 3 3 c3 4 4
我想用 Pandas sample功能,但具有不分组或过滤数据的标准。 import pandas as pd import numpy as np df = pd.DataFrame(np.rand
我正在尝试从 MNIST 数据集中绘制 10 个样本。每个数字之一。这是代码: import sklearn import pandas as pd import matplotlib.pyplot
我是一名优秀的程序员,十分优秀!