1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
/**
@page smpl_audio NiAudioSample.cpp - sample program
<b>Source file:</b> Click the following link to view the source code file:
- NiAudioSample.cpp
This section describes an OpenNI sample program for using the Audio interface.
The documentation describes the sample program's code from the top of the program file(s) to bottom.
This documentation item describes only OpenNI code features. Third party features, e.g., GL code, may be ignored. However, place holders as section headings appear in place of complete functions or large code blocks that are not OpenNI specific or key to understanding the logic of the sample program. These place holders are section headings with minimal text to enable the reader to identify the original program structure when studying the documentation.
Every OpenNI feature is described the first time it appears in this sample program. Further appearances of the same feature are not described again.
@section bkrec_macros Macro Declarations
At the top of the program is a macro utility declaration, which calls OpenNI methods. It is described below. However, for the sake of conciseness, the rest of this documentation skips calls to this macro.
The CHECK_RC() macro checks whether the most recent OpenNI operation was successful or returned an error result. On error, the @ref xn::xnGetStatusString "xnGetStatusString()" method converts the OpenNI error return code to the corresponding error string for printing, and the current function exits.
@code
#define CHECK_RC(rc, what) \
if (rc != XN_STATUS_OK) \
{ \
printf("%s failed: %s\n", what, xnGetStatusString(rc)); \
return rc; \
}
@endcode
@section rec_syn_sample_xml_path Declaration of File Path
In the following definitions, SAMPLE_XML_PATH is for the path to an OpenNI XML script input file for building a production graph. The <i>production graph</i> is a network of <i>production nodes</i> and is the principal OpenNI object model. See @ref prod_graph for more about the production graph.
@code
#define SAMPLE_XML_PATH "../../../../Data/SamplesConfig.xml"
@endcode
@section aud_glb_dcl_blk_ref "Declaration Block" section
The reader may find it convenient to study the global declaration block before continuing to study the code statements. The global declaration block is documented later in this section, corresponding to its position in the program file – see @ref aud_glb_dcl_blk.
@section aud_decl_mode enum Mode
The following declaration defines the program mode, whether whether it is recording an OpenNI data generation session or whether it is playing a recording.
@code
enum Mode
{
MODE_PLAY,
MODE_RECORD,
};
@endcode
This declaration is not OpenNI specific.
@section aud_printusage printUsage() method
This function is not OpenNI specific.
@section aud_play play() method - Play Audio
This routine gets an array of AudioGenerators, takes the first one, and constantly reads data from it and sends it to be played.
The following code block gets the first AudioGenerator node's wave output mode. It is received in an xn::XnWaveOutputMode, which comprises: bits per sample, channel, and sample rate. This information is then used for setting up the audio output buffers for collecting the generated play data and for setting up the hardware audio output channel.
@code
XnWaveOutputMode waveMode;
nRetVal = aGens[0].GetWaveOutputMode(waveMode);
CHECK_RC(nRetVal, "Failed getting wave output mode");
@endcode
The above completes the initialization. The following code is the main program loop.
The application calls an 'Update Data()' method, in this case the node's @ref xn::Generator::WaitAndUpdateData "WaitAndUpdateData", to make a new frame available for getting. The application can then get the data (for example, using a metadata GetData() method).
@code
nRetVal = aGens[0].WaitAndUpdateData();
@endcode
Assuming the above call succeeded, the application then gets the size of the audio data that was generated by the AudioGenerator node.
@code
XnUInt32 nBufferSize = aGens[0].GetDataSize();
@endcode
The next OpenNI statements copy the AudioGenerator node's data into a prepared buffer to be sent to the machine sound card. <code>xnOSMemCopy</code> is OpenNI memory copy routine.
@code
xnOSMemCopy(pHeader->lpData, aGens[0].GetAudioBuffer(), nBufferSize);
pHeader->dwBufferLength = nBufferSize;
@endcode
@section aud_record record() method - Record Audio
This method gets a list of audio generators, and records to a separate file the data generated by each generator .
The following code block creates files named with the names of the AudioGenerator nodes.
@code
XN_FILE_HANDLE aFiles[nSupportedNodes];
for (XnUInt32 i = 0; i < nNodes; ++i)
{
XnChar strFileName[XN_FILE_MAX_PATH];
sprintf(strFileName, "audio.%s.pcm", aGens[i].GetName());
nRetVal = xnOSOpenFile(strFileName, XN_OS_FILE_WRITE, &aFiles[i]);
CHECK_RC(nRetVal, "Open file");
}
@endcode
The application then calls an @ref conc_updating_data "'Update Data'" method, in this case xn::Context.WaitAnyUpdateAll(), to update all generator nodes in the context to the latest available data, first waiting for any of the nodes to have new data available. The first call is used just to flush the node.
@code
context.WaitAnyUpdateAll();
@endcode
The following loop checks which node has new data and writes it to a file. The IsDataNew() method returns whether a node's frame data was updated by the most recent call to the WaitAnyUpdateAll() method.
@code
XN_FILE_HANDLE aFiles[nSupportedNodes];
...
...
for (XnUInt32 i = 0; i < nNodes; ++i)
{
if (aGens[i].IsDataNew())
{
nRetVal = xnOSWriteFile(aFiles[i], aGens[i].GetAudioBuffer(), aGens[i].GetDataSize());
CHECK_RC(nRetVal, "Write to file");
}
}
@endcode
@section aud_mainprg Main Program
@subsection aud_glb_dcl_blk "Declaration Block" section
The declaration block at the top of the main program declares a @ref xn::Context object, an @ref xn::EnumerationErrors object, and an xn::ScriptNode object. The Context object is a workspace in which the application builds an OpenNI production graph. the @ref xn::EnumerationErrors object is for collecting errors from any of the OpenNI functions. Also declared is an OpenNI status flag for collecting return values from method calls. the @ref xn::ScriptNode object loads an XML script from a file or string, and then runs the XML script to build a production graph.
@code
XnStatus nRetVal = XN_STATUS_OK;
Context context;
EnumerationErrors errors;
...
ScriptNode scriptNode;
@endcode
@subsection aud_main_code Main Code Section
In the following, the InitFromXmlFile() method is a shorthand combination of two other initialization methods – Init() and then RunXmlScriptFromFile() – which initializes the context object and then creates a production graph from an XML file.
@code
nRetVal = context.InitFromXmlFile(SAMPLE_XML_PATH, scriptNode);
@endcode
The following code block tests whether a production graph was created. If not, the reason is reported as a list of one or more errors in the <code>errors</code> object.
@code
if (nRetVal == XN_STATUS_NO_NODE_PRESENT)
{
XnChar strError[1024];
errors.ToString(strError, 1024);
printf("%s\n", strError);
return (nRetVal);
}
@endcode
The following code block searches for xn::AudioGenerator nodes in the production graph. The nodes are returned in the @ref xn::NodeInfoList object. This object is a list xn::NodeInfo objects, each containing information about a node found in the above EnumerateExistingNodes() call.
@code
NodeInfoList list;
nRetVal = context.EnumerateExistingNodes(list, XN_NODE_TYPE_AUDIO);
CHECK_RC(nRetVal, "Enumerate audio nodes");
AudioGenerator gens[nSupportedNodes];
XnUInt32 nNodes = 0;
@endcode
The following declarations and statements get all the @ref xn::AudioGenerator nodes that were found by the EnumerateExistingNodes() call. The <code>gens</code> array receives all the nodes, and they are counted by the <code>nNodes</code> variable. (Currently, only a single AudioGenerator node is supported for playing at at once.)
@code
AudioGenerator gens[nSupportedNodes];
XnUInt32 nNodes = 0;
...
for (NodeInfoList::Iterator it = list.Begin(); it != list.End(); ++it)
{
NodeInfo info = *it;
nRetVal = info.GetInstance(gens[nNodes]);
CHECK_RC(nRetVal, "Get audio node");
nNodes++;
}
@endcode
*/
|