Sophie

Sophie

distrib > Mageia > 7 > armv7hl > media > core-updates > by-pkgid > 845e36bb3ecce380666d628d88446962 > files > 209

qtdatavis3d5-doc-5.12.6-1.mga7.noarch.rpm

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- audiolevels.qdoc -->
  <title>Audiolevels Example | Qt Data Visualization 5.12.6</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td >Qt 5.12</td><td ><a href="qtdatavisualization-index.html">Qt Data Visualization</a></td><td >Audiolevels Example</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right"><a href="qtdatavisualization-index.html">Qt Data Visualization | Commercial or GPLv3</a></td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
<div class="sidebar">
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level1"><a href="#running-the-example">Running the Example</a></li>
<li class="level1"><a href="#visualizing-audio-levels">Visualizing Audio Levels</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Audiolevels Example</h1>
<span class="subtitle"></span>
<!-- $$$audiolevels-brief -->
<p>Simple application showing real time audio data.</p>
<!-- @@@audiolevels -->
<!-- $$$audiolevels-description -->
<div class="descr"> <a name="details"></a>
<p>The audiolevels example shows how feed real-time dynamic data to a graph using <a href="q3dbars.html">Q3DBars</a>.</p>
<p>This example reads the audio levels from a microphone and displays those levels in a bar graph. To increase the load for demonstration purposes, and to make the graph little fancier, slightly modified data is used to fill multiple rows.</p>
<p class="centerAlign"><img src="images/audiolevels-example.png" alt="" /></p><p>The interesting stuff happens in <code>AudioLevels</code> and <code>AudioLevelsIODevice</code> classes, so we concentrate on those and skip explaining the basic <a href="q3dbars.html">Q3DBars</a> functionality - for that see <a href="qtdatavisualization-bars-example.html">Bars Example</a>.</p>
<a name="running-the-example"></a>
<h2 id="running-the-example">Running the Example</h2>
<p>To run the example from Qt Creator, open the <b>Welcome</b> mode and select the example from <b>Examples</b>. For more information, visit Building and Running an Example.</p>
<a name="visualizing-audio-levels"></a>
<h2 id="visualizing-audio-levels">Visualizing Audio Levels</h2>
<p><code>AudioLevelsIODevice</code> subclasses QIODevice and is given as input device for QAudioInput class, so it receives microphone data.</p>
<p>In the header file for <code>AudioLevels</code> class we declare necessary members:</p>
<pre class="cpp">

  <span class="type"><a href="q3dbars.html">Q3DBars</a></span> <span class="operator">*</span>m_graph;
  AudioLevelsIODevice <span class="operator">*</span>m_device;
  <span class="type">QAudioInput</span> <span class="operator">*</span>m_audioInput;

</pre>
<p>And initialize the microphone listening in the source:</p>
<pre class="cpp">

  <span class="type">QAudioDeviceInfo</span> inputDevice <span class="operator">=</span> <span class="type">QAudioDeviceInfo</span><span class="operator">::</span>defaultInputDevice();

  <span class="keyword">if</span> (inputDevice<span class="operator">.</span>supportedSampleRates()<span class="operator">.</span>size() <span class="operator">&gt;</span> <span class="number">0</span>
          <span class="operator">&amp;</span><span class="operator">&amp;</span> inputDevice<span class="operator">.</span>supportedChannelCounts()<span class="operator">.</span>size() <span class="operator">&gt;</span> <span class="number">0</span>
          <span class="operator">&amp;</span><span class="operator">&amp;</span> inputDevice<span class="operator">.</span>supportedSampleSizes()<span class="operator">.</span>size() <span class="operator">&gt;</span> <span class="number">0</span>
          <span class="operator">&amp;</span><span class="operator">&amp;</span> inputDevice<span class="operator">.</span>supportedCodecs()<span class="operator">.</span>size() <span class="operator">&gt;</span> <span class="number">0</span>) {
      <span class="type">QAudioFormat</span> formatAudio;
      formatAudio<span class="operator">.</span>setSampleRate(inputDevice<span class="operator">.</span>supportedSampleRates()<span class="operator">.</span>at(<span class="number">0</span>));
      formatAudio<span class="operator">.</span>setChannelCount(inputDevice<span class="operator">.</span>supportedChannelCounts()<span class="operator">.</span>at(<span class="number">0</span>));
      formatAudio<span class="operator">.</span>setSampleSize(inputDevice<span class="operator">.</span>supportedSampleSizes()<span class="operator">.</span>at(<span class="number">0</span>));
      formatAudio<span class="operator">.</span>setCodec(inputDevice<span class="operator">.</span>supportedCodecs()<span class="operator">.</span>at(<span class="number">0</span>));
      formatAudio<span class="operator">.</span>setByteOrder(<span class="type">QAudioFormat</span><span class="operator">::</span>LittleEndian);
      formatAudio<span class="operator">.</span>setSampleType(<span class="type">QAudioFormat</span><span class="operator">::</span>UnSignedInt);

      m_audioInput <span class="operator">=</span> <span class="keyword">new</span> <span class="type">QAudioInput</span>(inputDevice<span class="operator">,</span> formatAudio<span class="operator">,</span> <span class="keyword">this</span>);
  <span class="preprocessor">#ifdef Q_OS_MAC</span>
      <span class="comment">// OS X seems to wait for entire buffer to fill before calling writeData, so use smaller buffer</span>
      m_audioInput<span class="operator">-</span><span class="operator">&gt;</span>setBufferSize(<span class="number">256</span>);
  <span class="preprocessor">#else</span>
      m_audioInput<span class="operator">-</span><span class="operator">&gt;</span>setBufferSize(<span class="number">1024</span>);
  <span class="preprocessor">#endif</span>

      m_device <span class="operator">=</span> <span class="keyword">new</span> AudioLevelsIODevice(m_graph<span class="operator">-</span><span class="operator">&gt;</span>seriesList()<span class="operator">.</span>at(<span class="number">0</span>)<span class="operator">-</span><span class="operator">&gt;</span>dataProxy()<span class="operator">,</span> <span class="keyword">this</span>);
      m_device<span class="operator">-</span><span class="operator">&gt;</span>open(<span class="type">QIODevice</span><span class="operator">::</span>WriteOnly);

      m_audioInput<span class="operator">-</span><span class="operator">&gt;</span>start(m_device);
  } <span class="keyword">else</span> {
      <span class="comment">// No graph content can be shown, so add a custom warning label</span>
      QCustom3DLabel <span class="operator">*</span>titleLabel <span class="operator">=</span> <span class="keyword">new</span> QCustom3DLabel(<span class="string">&quot;No valid audio input device found&quot;</span><span class="operator">,</span>
                                                      <span class="type">QFont</span>()<span class="operator">,</span>
                                                      QVector3D(<span class="number">0.2f</span><span class="operator">,</span> <span class="number">0.2f</span><span class="operator">,</span> <span class="number">0.0f</span>)<span class="operator">,</span>
                                                      QVector3D(<span class="number">1.0f</span><span class="operator">,</span> <span class="number">1.0f</span><span class="operator">,</span> <span class="number">0.0f</span>)<span class="operator">,</span>
                                                      <span class="type">QQuaternion</span>());
      titleLabel<span class="operator">-</span><span class="operator">&gt;</span>setPositionAbsolute(<span class="keyword">true</span>);
      titleLabel<span class="operator">-</span><span class="operator">&gt;</span>setFacingCamera(<span class="keyword">true</span>);
      m_graph<span class="operator">-</span><span class="operator">&gt;</span>addCustomItem(titleLabel);
  }

</pre>
<p>In the header file for <code>AudioLevelsIODevice</code> class we store pointers to the data proxy and also the data array we give to the proxy, because we reuse the same array to keep memory reallocations to the minimum:</p>
<pre class="cpp">

  <span class="type"><a href="qbardataproxy.html">QBarDataProxy</a></span> <span class="operator">*</span>m_proxy;
  <span class="type"><a href="qbardataproxy.html#QBarDataArray-typedef">QBarDataArray</a></span> <span class="operator">*</span>m_array;

</pre>
<p>In the source file we define some static constants to define size of the data array and the middle row index, as well as the resolution of the visualization. You may need to adjust these values to get decent performance in low-end devices:</p>
<pre class="cpp">

  <span class="keyword">static</span> <span class="keyword">const</span> <span class="type">int</span> resolution <span class="operator">=</span> <span class="number">8</span>;
  <span class="keyword">static</span> <span class="keyword">const</span> <span class="type">int</span> rowSize <span class="operator">=</span> <span class="number">800</span>;
  <span class="keyword">static</span> <span class="keyword">const</span> <span class="type">int</span> rowCount <span class="operator">=</span> <span class="number">7</span>; <span class="comment">// Must be odd number</span>
  <span class="keyword">static</span> <span class="keyword">const</span> <span class="type">int</span> middleRow <span class="operator">=</span> rowCount <span class="operator">/</span> <span class="number">2</span>;

</pre>
<p>The <code>resolution</code> constant indicates the sample rate, for example, value 8 means every eighth byte from audio input is visualized. This is necessary to make the data readable, as it would otherwise make the graph scroll too fast.</p>
<p>In the <code>AudioLevelsIODevice</code> class constructor we initialize the data array:</p>
<pre class="cpp">

  m_array<span class="operator">-</span><span class="operator">&gt;</span>reserve(rowCount);
  <span class="keyword">for</span> (<span class="type">int</span> i <span class="operator">=</span> <span class="number">0</span>; i <span class="operator">&lt;</span> rowCount; i<span class="operator">+</span><span class="operator">+</span>)
      m_array<span class="operator">-</span><span class="operator">&gt;</span>append(<span class="keyword">new</span> <span class="type"><a href="qbardataproxy.html#QBarDataRow-typedef">QBarDataRow</a></span>(rowSize));

</pre>
<p>The <code>AudioLevelsIODevice::writeData</code> function is called whenever there is new audio data available to be visualized. There we move the old data along the rows and insert new data in the beginning of the rows:</p>
<pre class="cpp">

  <span class="type">qint64</span> AudioLevelsIODevice<span class="operator">::</span>writeData(<span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>data<span class="operator">,</span> <span class="type">qint64</span> maxSize)
  {
      <span class="comment">// The amount of new data available.</span>
      <span class="type">int</span> newDataSize <span class="operator">=</span> maxSize <span class="operator">/</span> resolution;

      <span class="comment">// If we get more data than array size, we need to adjust the start index for new data.</span>
      <span class="type">int</span> newDataStartIndex <span class="operator">=</span> qMax(<span class="number">0</span><span class="operator">,</span> (newDataSize <span class="operator">-</span> rowSize));

      <span class="comment">// Move the old data ahead in the rows (only do first half of rows + middle one now).</span>
      <span class="comment">// If the amount of new data was larger than row size, skip copying.</span>
      <span class="keyword">if</span> (<span class="operator">!</span>newDataStartIndex) {
          <span class="keyword">for</span> (<span class="type">int</span> i <span class="operator">=</span> <span class="number">0</span>; i <span class="operator">&lt;</span><span class="operator">=</span> middleRow; i<span class="operator">+</span><span class="operator">+</span>) {
              <span class="type"><a href="qbardataitem.html">QBarDataItem</a></span> <span class="operator">*</span>srcPos <span class="operator">=</span> m_array<span class="operator">-</span><span class="operator">&gt;</span>at(i)<span class="operator">-</span><span class="operator">&gt;</span>data();
              <span class="type"><a href="qbardataitem.html">QBarDataItem</a></span> <span class="operator">*</span>dstPos <span class="operator">=</span> srcPos <span class="operator">+</span> newDataSize;
              memmove((<span class="type">void</span> <span class="operator">*</span>)dstPos<span class="operator">,</span> (<span class="type">void</span> <span class="operator">*</span>)srcPos<span class="operator">,</span> (rowSize <span class="operator">-</span> newDataSize) <span class="operator">*</span> <span class="keyword">sizeof</span>(<span class="type"><a href="qbardataitem.html">QBarDataItem</a></span>));
          }
      }

      <span class="comment">// Insert data in reverse order, so that newest data is always at the front of the row.</span>
      <span class="type">int</span> index <span class="operator">=</span> <span class="number">0</span>;
      <span class="keyword">for</span> (<span class="type">int</span> i <span class="operator">=</span> newDataSize <span class="operator">-</span> <span class="number">1</span>; i <span class="operator">&gt;</span><span class="operator">=</span> newDataStartIndex; i<span class="operator">-</span><span class="operator">-</span>) {
          <span class="comment">// Add 0.01 to the value to avoid gaps in the graph (i.e. zero height bars).</span>
          <span class="comment">// Also, scale to 0...100</span>
          <span class="type">float</span> value <span class="operator">=</span> <span class="type">float</span>(<span class="type">quint8</span>(data<span class="operator">[</span>resolution <span class="operator">*</span> i<span class="operator">]</span>) <span class="operator">-</span> <span class="number">128</span>) <span class="operator">/</span> <span class="number">1.28f</span> <span class="operator">+</span> <span class="number">0.01f</span>;
          (<span class="operator">*</span>m_array<span class="operator">-</span><span class="operator">&gt;</span>at(middleRow))<span class="operator">[</span>index<span class="operator">]</span><span class="operator">.</span>setValue(value);
          <span class="comment">// Insert a fractional value into front half of the rows.</span>
          <span class="keyword">for</span> (<span class="type">int</span> j <span class="operator">=</span> <span class="number">1</span>; j <span class="operator">&lt;</span><span class="operator">=</span> middleRow; j<span class="operator">+</span><span class="operator">+</span>) {
              <span class="type">float</span> fractionalValue <span class="operator">=</span> value <span class="operator">/</span> <span class="type">float</span>(j <span class="operator">+</span> <span class="number">1</span>);
              (<span class="operator">*</span>m_array<span class="operator">-</span><span class="operator">&gt;</span>at(middleRow <span class="operator">-</span> j))<span class="operator">[</span>index<span class="operator">]</span><span class="operator">.</span>setValue(fractionalValue);
          }
          index<span class="operator">+</span><span class="operator">+</span>;
      }

      <span class="comment">// Copy the front half of rows to the back half for symmetry.</span>
      index <span class="operator">=</span> <span class="number">0</span>;
      <span class="keyword">for</span> (<span class="type">int</span> i <span class="operator">=</span> rowCount <span class="operator">-</span> <span class="number">1</span>; i <span class="operator">&gt;</span> middleRow; i<span class="operator">-</span><span class="operator">-</span>) {
          <span class="type"><a href="qbardataitem.html">QBarDataItem</a></span> <span class="operator">*</span>srcPos <span class="operator">=</span> m_array<span class="operator">-</span><span class="operator">&gt;</span>at(index<span class="operator">+</span><span class="operator">+</span>)<span class="operator">-</span><span class="operator">&gt;</span>data();
          <span class="type"><a href="qbardataitem.html">QBarDataItem</a></span> <span class="operator">*</span>dstPos <span class="operator">=</span> m_array<span class="operator">-</span><span class="operator">&gt;</span>at(i)<span class="operator">-</span><span class="operator">&gt;</span>data();
          memcpy((<span class="type">void</span> <span class="operator">*</span>)dstPos<span class="operator">,</span> (<span class="type">void</span> <span class="operator">*</span>)srcPos<span class="operator">,</span> rowSize <span class="operator">*</span> <span class="keyword">sizeof</span>(<span class="type"><a href="qbardataitem.html">QBarDataItem</a></span>));
      }

      <span class="comment">// Reset the proxy array now that data has been updated to trigger a redraw.</span>
      m_proxy<span class="operator">-</span><span class="operator">&gt;</span>resetArray(m_array);

      <span class="keyword">return</span> maxSize;
  }

</pre>
<p>We use a couple of techniques here to improve performance. First, we reuse the existing data array, as this allows us to avoid any extra memory allocations in our application code. This also means the data array dimensions do not change, which further improves efficiency in the bar graph renderer. Secondly, since each row is a QVector of bar data items, which do not allocate any data that needs deletion, we can utilize <code>memmove</code> and <code>memcpy</code> functions to quickly move and copy data around.</p>
<p><b>Note: </b>In the future versions of Qt Data Visualization, <a href="qbardataitem.html">QBarDataItem</a> might get extended so that it does allocate some memory to store other optional bar properties besides the value. In use cases where those optional properties are used, using <code>memmove</code> and <code>memcpy</code> could lead to memory leaks, so use them with care.</p><p>Files:</p>
<ul>
<li><a href="qtdatavisualization-audiolevels-audiolevels-cpp.html">audiolevels/audiolevels.cpp</a></li>
<li><a href="qtdatavisualization-audiolevels-audiolevels-h.html">audiolevels/audiolevels.h</a></li>
<li><a href="qtdatavisualization-audiolevels-audiolevels-pro.html">audiolevels/audiolevels.pro</a></li>
<li><a href="qtdatavisualization-audiolevels-audiolevelsiodevice-cpp.html">audiolevels/audiolevelsiodevice.cpp</a></li>
<li><a href="qtdatavisualization-audiolevels-audiolevelsiodevice-h.html">audiolevels/audiolevelsiodevice.h</a></li>
<li><a href="qtdatavisualization-audiolevels-main-cpp.html">audiolevels/main.cpp</a></li>
</ul>
</div>
<!-- @@@audiolevels -->
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2019 The Qt Company Ltd.
   Documentation contributions included herein are the copyrights of
   their respective owners.<br/>    The documentation provided herein is licensed under the terms of the    <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation    License version 1.3</a> as published by the Free Software Foundation.<br/>    Qt and respective logos are trademarks of The Qt Company Ltd.     in Finland and/or other countries worldwide. All other trademarks are property
   of their respective owners. </p>
</div>
</body>
</html>