如何使用外部音频接口访问具有核心音频的单个通道(How to access individual channels with core audio from an external audio interface)
我正在学习CoreAudio,我正在阅读Apple的文档中的一些示例,并弄清楚如何设置和不设置。 到目前为止,我能够连接到默认连接的音频输入设备并将其输出到默认输出设备。 我连接了一个2通道接口,并能够从中输出输入并输出它。
但是我正在搜索他们的API参考和示例,但是找不到任何可以从我的界面访问各个输入通道的实质内容。
我能够从我的渲染回调函数中的AudioBufferList中删除并提取样本并以这种方式操作它,但我想知道是否有正确的方法或更正式的方式从每个输入通道访问数据。
编辑:
这是我从我使用的示例中找到的用户数据:
typedef struct MyAUGraphPlayer { AudioStreamBasicDescription streamFormat; AUGraph graph; AudioUnit inputUnit; AudioUnit outputUnit; AudioBufferList * inputBuffer; CARingBuffer * ringBuffer; Float64 firstInputSampleTime; Float64 firstOutputSampleTime; Float64 inToOutSampleTimeOffset; } MyAUGraphPlayer;
这就是我设置输入单元的方式:
void CreateInputUnit(MyAUGraphPlayer * player) { //Generates a description that matches audio HAL AudioComponentDescription inputcd = {0}; inputcd.componentType = kAudioUnitType_Output; inputcd.componentSubType = kAudioUnitSubType_HALOutput; inputcd.componentManufacturer = kAudioUnitManufacturer_Apple; UInt32 deviceCount = AudioComponentCount ( &inputcd ); printf("Found %d devices\n", deviceCount); AudioComponent comp = AudioComponentFindNext(NULL, &inputcd); if(comp == NULL) { printf("Can't get output unit\n"); exit(1); } OSStatus status; status = AudioComponentInstanceNew(comp, &player->inputUnit); assert(status == noErr); //Explicitly enable Input and disable output UInt32 disableFlag = 0; UInt32 enableFlag = 1; AudioUnitScope outputBus = 0; AudioUnitScope inputBus = 1; status = AudioUnitSetProperty(player->inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, inputBus, &enableFlag, sizeof(enableFlag)) assert(status == noErr); status = AudioUnitSetProperty(player->inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, outputBus, &disableFlag, sizeof(enableFlag)); assert(status == noErr); printf("Finished enabling input and disabling output on an inputUnit\n"); //Get the default Audio input Device AudioDeviceID defaultDevice = kAudioObjectUnknown; UInt32 propertySize = sizeof(defaultDevice); AudioObjectPropertyAddress defaultDeviceProperty; defaultDeviceProperty.mSelector = kAudioHardwarePropertyDefaultInputDevice; defaultDeviceProperty.mScope = kAudioObjectPropertyScopeGlobal; defaultDeviceProperty.mElement = kAudioObjectPropertyElementMaster; status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultDeviceProperty, 0, NULL, &propertySize, &defaultDevice); assert(status == noErr); //Set the current device property of the AUHAL status = AudioUnitSetProperty(player->inputUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, outputBus, &defaultDevice, sizeof(defaultDevice)); assert(status == noErr); //Get the AudioStreamBasicDescription from Input AUHAL propertySize = sizeof(AudioStreamBasicDescription); status = AudioUnitGetProperty(player->inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &player->streamFormat, &propertySize); assert(status == noErr); //Adopt hardware input sample rate AudioStreamBasicDescription deviceFormat; status = AudioUnitGetProperty(player->inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, inputBus, &deviceFormat, &propertySize); assert(status == noErr); player->streamFormat.mSampleRate = deviceFormat.mSampleRate; printf("Sample Rate %f...\n", deviceFormat.mSampleRate); propertySize = sizeof(AudioStreamBasicDescription); status = AudioUnitSetProperty(player->inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &player->streamFormat, propertySize); assert(status == noErr); //Calculating Capture buffer size for an I/O unit UInt32 bufferSizeFrames = 0; propertySize = sizeof(UInt32); status = AudioUnitGetProperty(player->inputUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, &bufferSizeFrames, &propertySize); assert(status == noErr); UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32); //Create AudioBufferList to receive capture data UInt32 propSize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * player->streamFormat.mChannelsPerFrame); //Malloc buffer lists player->inputBuffer = (AudioBufferList *) malloc(propSize); player->inputBuffer->mNumberBuffers = player->streamFormat.mChannelsPerFrame; //Pre malloc buffers for AudioBufferLists for(UInt32 i = 0; i < player->inputBuffer->mNumberBuffers; i++){ player->inputBuffer->mBuffers[i].mNumberChannels = 1; player->inputBuffer->mBuffers[i].mDataByteSize = bufferSizeBytes; player->inputBuffer->mBuffers[i].mData = malloc(bufferSizeBytes); } //Create the ring buffer player->ringBuffer = new CARingBuffer(); player->ringBuffer->Allocate(player->streamFormat.mChannelsPerFrame, player->streamFormat.mBytesPerFrame, bufferSizeFrames * 3); printf("Number of channels: %d\n", player->streamFormat.mChannelsPerFrame); printf("Number of buffers: %d\n", player->inputBuffer->mNumberBuffers); //Set render proc to supply samples AURenderCallbackStruct callbackStruct; callbackStruct.inputProc = InputRenderProc; callbackStruct.inputProcRefCon = player; status = AudioUnitSetProperty(player->inputUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callbackStruct, sizeof(callbackStruct); assert(status == noErr); status = AudioUnitInitialize(player->inputUnit); assert(status == noErr); player->firstInputSampleTime = -1; player->inToOutSampleTimeOffset = -1; printf("Finished CreateInputUnit()\n"); }
所以这是我的渲染回调函数,我正在访问各个缓冲区。 :
OSStatus GraphRenderProc(void * inRefCon, AudioUnitRenderActionFlags * ioActionFlags, const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) { MyAUGraphPlayer * player = (MyAUGraphPlayer *) inRefCon; if(player->firstOutputSampleTime < 0.0) { player->firstOutputSampleTime = inTimeStamp->mSampleTime; if((player->firstInputSampleTime > -1.0) && (player->inToOutSampleTimeOffset < 0.0)) { player->inToOutSampleTimeOffset = player->firstInputSampleTime - player->firstOutputSampleTime; } } //Copy samples out of ring buffer OSStatus outputProcErr = noErr; outputProcErr = player->ringBuffer->Fetch(ioData, inNumberFrames, inTimeStamp->mSampleTime + player->inToOutSampleTimeOffset); //BUT THIS IS NOT HOW IT IS SUPPOSED TO WORK Float32 * data = (Float32 *) ioData->mBuffers[0].mData; Float32 * data2 = (Float32 *) ioData->mBuffers[1].mData; for(int frame = 0; frame < inNumberFrames; frame++) { Float32 sample = data[frame] + data2[frame]; data[frame] = data2[frame] = sample; } return outputProcErr; }
I am learning CoreAudio and I am just going through some of the examples on Apple's documentation and figuring out how to set things up and what not. So far I am able to connect to the default connected audio input device and output it to the default output device. I connected a 2 channel interface and was able to output the input from it and output it as well.
However I was searching through their API references and examples, but could not find any thing substantial to access the individual input channels from my interface.
I was able to hack away and extract the samples from the AudioBufferList in my Render Callback function and manipulate it that way but I am wondering if there is a correct way or a more official way of accessing the data from each individual input channels.
EDIT:
This is the user data that I found from an example that I am using:
typedef struct MyAUGraphPlayer { AudioStreamBasicDescription streamFormat; AUGraph graph; AudioUnit inputUnit; AudioUnit outputUnit; AudioBufferList * inputBuffer; CARingBuffer * ringBuffer; Float64 firstInputSampleTime; Float64 firstOutputSampleTime; Float64 inToOutSampleTimeOffset; } MyAUGraphPlayer;
This is how i set up the input unit:
void CreateInputUnit(MyAUGraphPlayer * player) { //Generates a description that matches audio HAL AudioComponentDescription inputcd = {0}; inputcd.componentType = kAudioUnitType_Output; inputcd.componentSubType = kAudioUnitSubType_HALOutput; inputcd.componentManufacturer = kAudioUnitManufacturer_Apple; UInt32 deviceCount = AudioComponentCount ( &inputcd ); printf("Found %d devices\n", deviceCount); AudioComponent comp = AudioComponentFindNext(NULL, &inputcd); if(comp == NULL) { printf("Can't get output unit\n"); exit(1); } OSStatus status; status = AudioComponentInstanceNew(comp, &player->inputUnit); assert(status == noErr); //Explicitly enable Input and disable output UInt32 disableFlag = 0; UInt32 enableFlag = 1; AudioUnitScope outputBus = 0; AudioUnitScope inputBus = 1; status = AudioUnitSetProperty(player->inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, inputBus, &enableFlag, sizeof(enableFlag)) assert(status == noErr); status = AudioUnitSetProperty(player->inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, outputBus, &disableFlag, sizeof(enableFlag)); assert(status == noErr); printf("Finished enabling input and disabling output on an inputUnit\n"); //Get the default Audio input Device AudioDeviceID defaultDevice = kAudioObjectUnknown; UInt32 propertySize = sizeof(defaultDevice); AudioObjectPropertyAddress defaultDeviceProperty; defaultDeviceProperty.mSelector = kAudioHardwarePropertyDefaultInputDevice; defaultDeviceProperty.mScope = kAudioObjectPropertyScopeGlobal; defaultDeviceProperty.mElement = kAudioObjectPropertyElementMaster; status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultDeviceProperty, 0, NULL, &propertySize, &defaultDevice); assert(status == noErr); //Set the current device property of the AUHAL status = AudioUnitSetProperty(player->inputUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, outputBus, &defaultDevice, sizeof(defaultDevice)); assert(status == noErr); //Get the AudioStreamBasicDescription from Input AUHAL propertySize = sizeof(AudioStreamBasicDescription); status = AudioUnitGetProperty(player->inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &player->streamFormat, &propertySize); assert(status == noErr); //Adopt hardware input sample rate AudioStreamBasicDescription deviceFormat; status = AudioUnitGetProperty(player->inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, inputBus, &deviceFormat, &propertySize); assert(status == noErr); player->streamFormat.mSampleRate = deviceFormat.mSampleRate; printf("Sample Rate %f...\n", deviceFormat.mSampleRate); propertySize = sizeof(AudioStreamBasicDescription); status = AudioUnitSetProperty(player->inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &player->streamFormat, propertySize); assert(status == noErr); //Calculating Capture buffer size for an I/O unit UInt32 bufferSizeFrames = 0; propertySize = sizeof(UInt32); status = AudioUnitGetProperty(player->inputUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, &bufferSizeFrames, &propertySize); assert(status == noErr); UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32); //Create AudioBufferList to receive capture data UInt32 propSize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * player->streamFormat.mChannelsPerFrame); //Malloc buffer lists player->inputBuffer = (AudioBufferList *) malloc(propSize); player->inputBuffer->mNumberBuffers = player->streamFormat.mChannelsPerFrame; //Pre malloc buffers for AudioBufferLists for(UInt32 i = 0; i < player->inputBuffer->mNumberBuffers; i++){ player->inputBuffer->mBuffers[i].mNumberChannels = 1; player->inputBuffer->mBuffers[i].mDataByteSize = bufferSizeBytes; player->inputBuffer->mBuffers[i].mData = malloc(bufferSizeBytes); } //Create the ring buffer player->ringBuffer = new CARingBuffer(); player->ringBuffer->Allocate(player->streamFormat.mChannelsPerFrame, player->streamFormat.mBytesPerFrame, bufferSizeFrames * 3); printf("Number of channels: %d\n", player->streamFormat.mChannelsPerFrame); printf("Number of buffers: %d\n", player->inputBuffer->mNumberBuffers); //Set render proc to supply samples AURenderCallbackStruct callbackStruct; callbackStruct.inputProc = InputRenderProc; callbackStruct.inputProcRefCon = player; status = AudioUnitSetProperty(player->inputUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callbackStruct, sizeof(callbackStruct); assert(status == noErr); status = AudioUnitInitialize(player->inputUnit); assert(status == noErr); player->firstInputSampleTime = -1; player->inToOutSampleTimeOffset = -1; printf("Finished CreateInputUnit()\n"); }
So this is my render callback function where I am accessing the individual buffers. :
OSStatus GraphRenderProc(void * inRefCon, AudioUnitRenderActionFlags * ioActionFlags, const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) { MyAUGraphPlayer * player = (MyAUGraphPlayer *) inRefCon; if(player->firstOutputSampleTime < 0.0) { player->firstOutputSampleTime = inTimeStamp->mSampleTime; if((player->firstInputSampleTime > -1.0) && (player->inToOutSampleTimeOffset < 0.0)) { player->inToOutSampleTimeOffset = player->firstInputSampleTime - player->firstOutputSampleTime; } } //Copy samples out of ring buffer OSStatus outputProcErr = noErr; outputProcErr = player->ringBuffer->Fetch(ioData, inNumberFrames, inTimeStamp->mSampleTime + player->inToOutSampleTimeOffset); //BUT THIS IS NOT HOW IT IS SUPPOSED TO WORK Float32 * data = (Float32 *) ioData->mBuffers[0].mData; Float32 * data2 = (Float32 *) ioData->mBuffers[1].mData; for(int frame = 0; frame < inNumberFrames; frame++) { Float32 sample = data[frame] + data2[frame]; data[frame] = data2[frame] = sample; } return outputProcErr; }
原文:https://stackoverflow.com/questions/37606550
最满意答案
您应该将代码拆分为更多行以处理这些错误或特殊情况。
mysql_query
将返回0到n行,如果发生则返回错误。 因此,返回的资源仅在非错误查询时才为真。 这可用于处理如下情况。首先构建并执行查询,然后处理资源 。
$query="SELECT COUNT(user_id) FROM users WHERE username = ".$username; $result = mysql_query($query);
如果出现错误,您可以使用以下内容确定发生了什么:
if(!$result) die("SELECT failed: ".mysql_error());
或者这些想法来处理这个问题
if (!$result=mysql_query($query)) { return false; // or similar operation } if (mysql_num_rows($result)!=1){ return false; }else{ return true; }
You should split your code in some more lines to handle those errors or special cases.
mysql_query
will return zero to n rows or an error if it occurs. The returned resource will therefore only be true on non-error queries. This can be used to handle such situations like follows.At first build and execute query, next process the resource.
$query="SELECT COUNT(user_id) FROM users WHERE username = ".$username; $result = mysql_query($query);
u may use the following to determine what is going on in case of an error:
if(!$result) die("SELECT failed: ".mysql_error());
or these idea to handle the problem
if (!$result=mysql_query($query)) { return false; // or similar operation } if (mysql_num_rows($result)!=1){ return false; }else{ return true; }
相关问答
更多-
不,这不对。 如果查看手册 ,您将看到第二个参数是结果集中要获取的行。 在您的原始示例中,您仅从第一行获取数据 - 0 - 而不是其他任何内容。 在你的mysqli代码中,你在每次赋值之前获取一个新行,因此数据将是来自不同行的不同字段的值的混合。 正确的方法是这样的: // fetch the first row in the result set $row = mysqli_fetch_assoc($sql); $id_fabricante = $row['manufacturers_id']; $ce ...
-
在代码中用mysql_num_rows($results) == 0替换mysql_num_rows($results == 0) Replace mysql_num_rows($results == 0) with mysql_num_rows($results) == 0 in your code
-
不是有效的mysql资源(mysql_fetch_array() returns 'supplied argument is not a valid MySQL result resource')[2023-03-26]
您还没有选择数据库 - 使用mysql_select_db() 这将是这样的:警告:可以进行SQL注入。 看起来您的查询失败了。 替换这个: $mysql = mysql_query("SELECT * FROM news WHERE id='$id' ;"); 附: $mysql = mysql_query("SELECT * FROM news WHERE id='$id' ;") or die(mysql_error()); 您应该创建自己的错误处理函数,它可以显示错误消息,而不会立即退出。 Warning: SQL injection possible. It looks ...我突然发现两件事: 你确定那个结果的查询是什么? insert和delete等查询没有结果。 它们返回一个表示成功的布尔值。 您是否正在检查以确保查询成功? 在您调用mysql_query的行之后,请确保检查结果。 如果它是假的,你可以调用mysql_get_error来找出问题所在。 编辑:好的,你真正的问题是你正在混合mysql_*和mysqli_*命令。 你需要使用其中一个。 Two things jump out at me: Are you sure that's the query that g ...我认为下面部分问题的问题: inner join ratings b on b.a_id=a.id" 从您的查询中,我猜a_ [some_text]是表a的列,但您的查询从表b加入a_id。 我想,它应该如下: inner join ratings b on a.a_id=b.id" I think the issue in below part of query: inner join ratings b on b.a_id=a.id" From your query, i guess a_[som ...您希望传递mysql_num_rows()您的$query值而不是$results值。 (或者你想重构你的代码,将$query命名$query $query_result并将其传递给mysql_num_rows() 。) mysql_num_rows()需要MySQL结果资源,在您的情况下由mysql_query()返回,您已将其分配给$query 。 相反, $result只是一个表示结果的单行的数组。 (所以更好的重构可能是将$result重命名$result $row并将$query重命名$query ...为什么我得到的参数不是有效的MySQL结果资源错误(Why am I getting supplied argument is not a valid MySQL result resource error)[2021-12-14]
检查mysql_query的结果以查看您的SQL是否不包含错误。 例如,你可以打印这样的错误: // Check result if (!$result) { $message = 'Invalid query: ' . mysql_error() . "\n"; $message .= 'Whole query: ' . $query; die($message); } 查询字符串的“&&”部分看起来很可疑。 足够。 你为什么用引号呢? 现在它不是你的查询字符串的一部分。 检查 ...问题是mysql_query()返回一个布尔值而不是结果资源。 这可能发生的原因有两个: 您执行的查询返回成功/失败而不是结果集(例如UPDATE ) 您的查询失败 在你的情况下,查询失败。 它失败的原因是因为你已经逃过了PHP字符串中你不需要的背部勾号。 你的行看起来像这样: $siteTitle = mysql_result(mysql_query("SELECT \`siteTitle\` FROM siteSettings"), 0); 当他们应该只是这样的时候: $siteTitle = mys ...您应该将代码拆分为更多行以处理这些错误或特殊情况。 mysql_query将返回0到n行,如果发生则返回错误。 因此,返回的资源仅在非错误查询时才为真。 这可用于处理如下情况。 首先构建并执行查询,然后处理资源 。 $query="SELECT COUNT(user_id) FROM users WHERE username = ".$username; $result = mysql_query($query); 如果出现错误,您可以使用以下内容确定发生了什么: if(!$result) die(" ...相关文章
更多- HTML5 Audio元素【HTML5教程 - 第五篇】
- HTML5项目笔记4:使用Audio API设计绚丽的HTML5音乐播放器
- RFC2848--The PINT Service Protocol: Extensions to SIP and SDP for IP Access to Telephone Call Services
- ACCESS TOKEN
- solr启动时报错java.nio.channels.OverlappingFileLockException
- 微信开发第四篇:获取access_token
- Solr 4.6 | Setting Up an External ZooKeeper Ensemble | upgrade solr to Solr4.6
- 和小猪一起搞微信公众号开发—获取Access_token
- java微信接口之——获取access_token
- solr在Linux上配置多个core
最新问答
更多- 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
- 如何通过引用返回对象?(How is returning an object by reference possible?)
- 矩阵如何存储在内存中?(How are matrices stored in memory?)
- 每个请求的Java新会话?(Java New Session For Each Request?)
- css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
- 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
- xcode语法颜色编码解释?(xcode syntax color coding explained?)
- 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
- 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
- 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
- 西安哪有PLC可控制编程的培训
- 在Entity Framework中选择基类(Select base class in Entity Framework)
- 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
- 电脑二级VF有什么用
- Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
- 金华英语角.
- 手机软件如何制作
- 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
- 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
- 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
- Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
- 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
- python的访问器方法有哪些
- DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
- 在Ruby中对组合进行排序(Sorting a combination in Ruby)
- 网站开发的流程?
- 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
- 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
- 透明度错误IE11(Transparency bug IE11)
- linux的基本操作命令。。。