summaryrefslogtreecommitdiffstats
path: root/examples/datavisualization/audiolevels
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2014-02-13 09:59:52 +0200
committerMiikka Heikkinen <miikka.heikkinen@digia.com>2014-02-13 10:09:17 +0200
commit88cd10aa7b3559b092cf5575b0a17d002dc100ae (patch)
tree9d6e7efdec49419558bb4ef4a9bc02ae3cb1cfc4 /examples/datavisualization/audiolevels
parentecabd51692b476567dc42a745f51996ec665b385 (diff)
Fix examples installation
Had to add one folder to the examples structure so installation works correctly. Change-Id: Ic92dfe9997413a6243abcf5eeba12744ba9e938c Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
Diffstat (limited to 'examples/datavisualization/audiolevels')
-rw-r--r--examples/datavisualization/audiolevels/audiolevels.cpp89
-rw-r--r--examples/datavisualization/audiolevels/audiolevels.h45
-rw-r--r--examples/datavisualization/audiolevels/audiolevels.pro14
-rw-r--r--examples/datavisualization/audiolevels/audiolevelsiodevice.cpp103
-rw-r--r--examples/datavisualization/audiolevels/audiolevelsiodevice.h44
-rw-r--r--examples/datavisualization/audiolevels/doc/images/audiolevels-example.pngbin0 -> 120978 bytes
-rw-r--r--examples/datavisualization/audiolevels/doc/src/audiolevels.qdoc85
-rw-r--r--examples/datavisualization/audiolevels/main.cpp39
8 files changed, 419 insertions, 0 deletions
diff --git a/examples/datavisualization/audiolevels/audiolevels.cpp b/examples/datavisualization/audiolevels/audiolevels.cpp
new file mode 100644
index 00000000..18c1342a
--- /dev/null
+++ b/examples/datavisualization/audiolevels/audiolevels.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "audiolevelsiodevice.h"
+#include "audiolevels.h"
+
+#include <QtDataVisualization/qbardataproxy.h>
+#include <QtDataVisualization/qvalue3daxis.h>
+#include <QtDataVisualization/q3dscene.h>
+#include <QtDataVisualization/q3dcamera.h>
+#include <QtDataVisualization/qbar3dseries.h>
+#include <QtDataVisualization/q3dtheme.h>
+
+#include <QAudioDeviceInfo>
+#include <QAudioInput>
+
+using namespace QtDataVisualization;
+
+AudioLevels::AudioLevels(Q3DBars *graph, QObject *parent)
+ : QObject(parent),
+ m_graph(graph),
+ m_device(0),
+ m_audioInput(0)
+{
+ // Set up the graph
+ m_graph->setBarThickness(0.5f);
+ m_graph->setBarSpacing(QSizeF(0.0, 1.0));
+ m_graph->valueAxis()->setRange(-100.0f, 100.0f);
+ m_graph->valueAxis()->setSegmentCount(20);
+ m_graph->valueAxis()->setLabelFormat(QStringLiteral("%d%%"));
+ m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
+ m_graph->setSelectionMode(QAbstract3DGraph::SelectionNone);
+ m_graph->scene()->activeCamera()->setCameraPosition(-25.0f, 10.0f, 190.0f);
+ m_graph->activeTheme()->setType(Q3DTheme::ThemeIsabelle);
+ m_graph->activeTheme()->setGridEnabled(true);
+ m_graph->activeTheme()->setBackgroundEnabled(false);
+ QFont font = m_graph->activeTheme()->font();
+ font.setPointSize(10);
+ m_graph->activeTheme()->setFont(font);
+ QBar3DSeries *series = new QBar3DSeries;
+ series->setMesh(QAbstract3DSeries::MeshBar);
+ m_graph->addSeries(series);
+
+ //! [0]
+ QAudioDeviceInfo inputDevice = QAudioDeviceInfo::defaultInputDevice();
+
+ QAudioFormat formatAudio;
+ formatAudio.setSampleRate(inputDevice.supportedSampleRates().at(0));
+ formatAudio.setChannelCount(inputDevice.supportedChannelCounts().at(0));
+ formatAudio.setSampleSize(inputDevice.supportedSampleSizes().at(0));
+ formatAudio.setCodec(inputDevice.supportedCodecs().at(0));
+ formatAudio.setByteOrder(QAudioFormat::LittleEndian);
+ formatAudio.setSampleType(QAudioFormat::UnSignedInt);
+
+ m_audioInput = new QAudioInput(inputDevice, formatAudio, this);
+#ifdef Q_OS_MAC
+ // Mac seems to wait for entire buffer to fill before calling writeData, so use smaller buffer
+ m_audioInput->setBufferSize(256);
+#else
+ m_audioInput->setBufferSize(1024);
+#endif
+
+ m_device = new AudioLevelsIODevice(m_graph->seriesList().at(0)->dataProxy(), this);
+ m_device->open(QIODevice::WriteOnly);
+
+ m_audioInput->start(m_device);
+ //! [0]
+}
+
+AudioLevels::~AudioLevels()
+{
+ m_audioInput->stop();
+ m_device->close();
+}
diff --git a/examples/datavisualization/audiolevels/audiolevels.h b/examples/datavisualization/audiolevels/audiolevels.h
new file mode 100644
index 00000000..84d9b4c4
--- /dev/null
+++ b/examples/datavisualization/audiolevels/audiolevels.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#ifndef AUDIOLEVELS_H
+#define AUDIOLEVELS_H
+
+#include <QtDataVisualization/q3dbars.h>
+
+using namespace QtDataVisualization;
+
+class AudioLevelsIODevice;
+class QAudioInput;
+
+class AudioLevels : public QObject
+{
+ Q_OBJECT
+
+public:
+ AudioLevels(Q3DBars *graph, QObject *parent = 0);
+ ~AudioLevels();
+
+private:
+ //! [0]
+ Q3DBars *m_graph;
+ AudioLevelsIODevice *m_device;
+ QAudioInput *m_audioInput;
+ //! [0]
+};
+
+#endif
diff --git a/examples/datavisualization/audiolevels/audiolevels.pro b/examples/datavisualization/audiolevels/audiolevels.pro
new file mode 100644
index 00000000..46f01635
--- /dev/null
+++ b/examples/datavisualization/audiolevels/audiolevels.pro
@@ -0,0 +1,14 @@
+!include( ../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+TARGET = audiolevels
+
+QT += multimedia
+
+SOURCES += main.cpp \
+ audiolevels.cpp \
+ audiolevelsiodevice.cpp
+
+HEADERS += audiolevels.h \
+ audiolevelsiodevice.h
diff --git a/examples/datavisualization/audiolevels/audiolevelsiodevice.cpp b/examples/datavisualization/audiolevels/audiolevelsiodevice.cpp
new file mode 100644
index 00000000..c0cd70e3
--- /dev/null
+++ b/examples/datavisualization/audiolevels/audiolevelsiodevice.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "audiolevelsiodevice.h"
+#include <QDebug>
+
+using namespace QtDataVisualization;
+
+//! [1]
+static const int resolution = 8;
+static const int rowSize = 800;
+static const int rowCount = 7; // Must be odd number
+static const int middleRow = rowCount / 2;
+//! [1]
+
+AudioLevelsIODevice::AudioLevelsIODevice(QBarDataProxy *proxy, QObject *parent)
+ : QIODevice(parent),
+ m_proxy(proxy),
+ m_array(new QBarDataArray)
+{
+ // We reuse the existing array for maximum performance, so construct the array here
+ //! [0]
+ m_array->reserve(rowCount);
+ for (int i = 0; i < rowCount; i++)
+ m_array->append(new QBarDataRow(rowSize));
+ //! [0]
+
+ qDebug() << "Total of" << (rowSize * rowCount) << "items in the array.";
+}
+
+// Implementation required for this pure virtual function
+qint64 AudioLevelsIODevice::readData(char *data, qint64 maxSize)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(maxSize)
+ return -1;
+}
+
+//! [2]
+qint64 AudioLevelsIODevice::writeData(const char *data, qint64 maxSize)
+{
+ // The amount of new data available.
+ int newDataSize = maxSize / resolution;
+
+ // If we get more data than array size, we need to adjust the start index for new data.
+ int newDataStartIndex = qMax(0, (newDataSize - rowSize));
+
+ // Move the old data ahead in the rows (only do first half of rows + middle one now).
+ // If the amount of new data was larger than row size, skip copying.
+ if (!newDataStartIndex) {
+ for (int i = 0; i <= middleRow; i++) {
+ QBarDataItem *srcPos = m_array->at(i)->data();
+ QBarDataItem *dstPos = srcPos + newDataSize;
+ memmove((void *)dstPos, (void *)srcPos, (rowSize - newDataSize) * sizeof(QBarDataItem));
+ }
+ }
+
+ // Insert data in reverse order, so that newest data is always at the front of the row.
+ int index = 0;
+ for (int i = newDataSize - 1; i >= newDataStartIndex; i--) {
+ // Add 0.01 to the value to avoid gaps in the graph (i.e. zero height bars).
+ // Also, scale to 0...100
+ float value = float(quint8(data[resolution * i]) - 128) / 1.28f + 0.01f;
+ (*m_array->at(middleRow))[index].setValue(value);
+ // Insert a fractional value into front half of the rows.
+ for (int j = 1; j <= middleRow; j++) {
+ float fractionalValue = value / float(j + 1);
+ (*m_array->at(middleRow - j))[index].setValue(fractionalValue);
+ }
+ index++;
+ }
+
+ // Copy the front half of rows to the back half for symmetry.
+ index = 0;
+ for (int i = rowCount - 1; i > middleRow; i--) {
+ QBarDataItem *srcPos = m_array->at(index++)->data();
+ QBarDataItem *dstPos = m_array->at(i)->data();
+ memcpy((void *)dstPos, (void *)srcPos, rowSize * sizeof(QBarDataItem));
+ }
+
+ // Reset the proxy array now that data has been updated to trigger a redraw.
+ m_proxy->resetArray(m_array);
+
+ return maxSize;
+}
+//! [2]
+
+
diff --git a/examples/datavisualization/audiolevels/audiolevelsiodevice.h b/examples/datavisualization/audiolevels/audiolevelsiodevice.h
new file mode 100644
index 00000000..45f17626
--- /dev/null
+++ b/examples/datavisualization/audiolevels/audiolevelsiodevice.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#ifndef AUDIOLEVELSIODEVICE_H
+#define AUDIOLEVELSIODEVICE_H
+
+#include <QtDataVisualization/qbardataproxy.h>
+#include <QIODevice>
+
+using namespace QtDataVisualization;
+
+class AudioLevelsIODevice : public QIODevice
+{
+ Q_OBJECT
+public:
+ explicit AudioLevelsIODevice(QBarDataProxy *proxy, QObject *parent = 0);
+
+protected:
+ qint64 readData(char *data, qint64 maxSize);
+ qint64 writeData(const char *data, qint64 maxSize);
+
+private:
+ //! [0]
+ QBarDataProxy *m_proxy;
+ QBarDataArray *m_array;
+ //! [0]
+};
+
+#endif
diff --git a/examples/datavisualization/audiolevels/doc/images/audiolevels-example.png b/examples/datavisualization/audiolevels/doc/images/audiolevels-example.png
new file mode 100644
index 00000000..ec79eb5a
--- /dev/null
+++ b/examples/datavisualization/audiolevels/doc/images/audiolevels-example.png
Binary files differ
diff --git a/examples/datavisualization/audiolevels/doc/src/audiolevels.qdoc b/examples/datavisualization/audiolevels/doc/src/audiolevels.qdoc
new file mode 100644
index 00000000..ad87ecc0
--- /dev/null
+++ b/examples/datavisualization/audiolevels/doc/src/audiolevels.qdoc
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+/*!
+ \example audiolevels
+ \title Audiolevels Example
+ \ingroup qtdatavisualization_examples
+ \brief Simple application showing real time audio data.
+
+ The audiolevels example shows how feed real-time dynamic data to a graph using Q3DBars.
+
+ 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.
+
+ \image audiolevels-example.png
+
+ The interesting stuff happens in \c AudioLevels and \c AudioLevelsIODevice classes, so we
+ concentrate on those and skip explaining the basic Q3DBars functionality - for that see
+ \l{Bars Example}.
+
+ \c AudioLevelsIODevice subclasses QIODevice and is given as input device for QAudioInput
+ class, so it receives microphone data.
+
+ In the header file for \c AudioLevels class we declare necessary members:
+
+ \snippet ../examples/audiolevels/audiolevels.h 0
+
+ And initialize the microphone listening in the source:
+
+ \snippet ../examples/audiolevels/audiolevels.cpp 0
+
+ In the header file for \c AudioLevelsIODevice 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:
+
+ \snippet ../examples/audiolevels/audiolevelsiodevice.h 0
+
+ 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:
+
+ \snippet ../examples/audiolevels/audiolevelsiodevice.cpp 1
+
+ The \c resolution 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.
+
+ In the \c AudioLevelsIODevice class constructor we initialize the data array:
+
+ \snippet ../examples/audiolevels/audiolevelsiodevice.cpp 0
+
+ The \c AudioLevelsIODevice::writeData 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:
+
+ \snippet ../examples/audiolevels/audiolevelsiodevice.cpp 2
+
+ 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 \c memmove and \c memcpy functions to quickly move and copy data around.
+
+ \note In the future versions of Qt Data Visualization, QBarDataItem 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 \c memmove and \c memcpy could lead to
+ memory leaks, so use them with care.
+*/
diff --git a/examples/datavisualization/audiolevels/main.cpp b/examples/datavisualization/audiolevels/main.cpp
new file mode 100644
index 00000000..9dd07b1b
--- /dev/null
+++ b/examples/datavisualization/audiolevels/main.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "audiolevels.h"
+
+#include <QGuiApplication>
+#include <QAudio>
+
+using namespace QtDataVisualization;
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ Q3DBars window;
+ window.setFlags(window.flags() ^ Qt::FramelessWindowHint);
+ window.resize(800, 500);
+ window.setTitle("Qt Data Visualization - Microphone audio levels visualizer");
+ window.show();
+
+ AudioLevels audioLevels(&window);
+
+ return app.exec();
+}