QSoundEffect() Play a .wav on Rasperry pi: I hear nothing. (sound generator example does work)
Unsolved
General and Desktop
-
Hi All,
I'm trying to play a wav file on a rasperry pi. I can't get it to work, I hear nothing. The same program works on windows 10.
I've also tried the example program "oudio output". This works, i do hear a beep, when I select "default:CARD=ALSA".
What did I miss?
Cheers,
CedricHere's my program:
soundloop.h#ifndef SOUNDLOOP_H #define SOUNDLOOP_H #include <QObject> #include <QAudioDeviceInfo> //needs QT += multimedia in the .pro file #include <QSoundEffect> class SoundLoop : public QObject { Q_OBJECT //marker for moc public: SoundLoop(); public slots: void slotStart(void); void slotLastLoop(void); signals: private: QString getFilenameFromSettings(void); void getAudioDeviceFromSettings(void); }; #endif // SOUNDLOOP_H
soundloop.cpp
#include "soundloop.h" #include <QSettings> #include <QDir> #include <QDebug> QSoundEffect *myEffect; QAudioDeviceInfo *myDevice; #define KEY_FILENAME "filename" #define DEFAULT_FILENAME "sound.wav" #define KEY_AUDIODEVICE "audiodevice" #define DEFAULT_AUDIODEVICE "non_existing_audiocard_name" //is replaced to be the default audio device SoundLoop::SoundLoop() { qDebug()<<Q_FUNC_INFO; QString filename; filename = getFilenameFromSettings(); QFile file; if (file.exists(filename)) { qDebug()<<"loading " <<filename; } else { qDebug()<< filename << " not found"; } myDevice = new QAudioDeviceInfo(); getAudioDeviceFromSettings(); //updates *myDevice myEffect = new QSoundEffect(); myEffect->setSource(QUrl::fromLocalFile(filename)); myEffect->setLoopCount(QSoundEffect::Infinite); myEffect->setVolume(1.00f); myEffect->play(); qDebug()<<myEffect->isPlaying(); } void SoundLoop::slotStart() { qDebug()<<Q_FUNC_INFO; if (myEffect) { myEffect->play(); } else { qDebug()<<"no sound loaded"; } } void SoundLoop::slotLastLoop() { qDebug()<<Q_FUNC_INFO; if (myEffect) { myEffect->setLoopCount(1); } else { qDebug()<<"no sound loaded"; } } QString SoundLoop::getFilenameFromSettings() { QSettings * settings = new QSettings; QString filename; settings->beginGroup("Soundloop"); if (settings->contains(KEY_FILENAME)) { filename=settings->value(KEY_FILENAME,DEFAULT_FILENAME).toString(); } else { filename=QDir::homePath(); filename.append("/"); filename.append(DEFAULT_FILENAME); settings->setValue(KEY_FILENAME,filename); } settings->endGroup(); delete settings; return filename; } void SoundLoop::getAudioDeviceFromSettings() { QAudioDeviceInfo deviceinfos; QList<QAudioDeviceInfo> devicelist = deviceinfos.availableDevices(QAudio::AudioOutput); QStringList list; qDebug()<<"Available sound devices:"; for (int i=0;i<devicelist.size();i++) { list.append(devicelist.at(i).deviceName()); qDebug()<<devicelist.at(i).deviceName(); } QSettings * settings = new QSettings; QString nameinsettings; settings->beginGroup("Soundloop"); if (settings->contains(KEY_AUDIODEVICE)) { nameinsettings=settings->value(KEY_AUDIODEVICE,DEFAULT_AUDIODEVICE).toString(); int index = list.indexOf(nameinsettings); if (index == -1) //sound card not found in settings { qDebug()<<"soundcard from settings: "<<nameinsettings<<" not found, choosing default soundcard"; *myDevice = QAudioDeviceInfo::defaultOutputDevice(); settings->setValue(KEY_AUDIODEVICE,myDevice->deviceName()); } else { qDebug()<<"soundcard from settings: "<<nameinsettings<<"found"; *myDevice = devicelist.at(index); } } else { qDebug()<<"no soundcard specified in settings, choosing default soundcard"; *myDevice = QAudioDeviceInfo::defaultOutputDevice(); settings->setValue(KEY_AUDIODEVICE,myDevice->deviceName()); } qDebug()<<"using soundcard: " << myDevice->deviceName(); }
And the output of my program:
Debugging starts [..] SoundLoop::SoundLoop() loading "/home/pi/untitled.wav" PulseAudioService: pa_context_connect() failed Available sound devices: "default" "default:CARD=ALSA" "sysdefault:CARD=ALSA" "dmix:CARD=ALSA,DEV=0" "dmix:CARD=ALSA,DEV=1" "dmix:CARD=ALSA,DEV=2" "dsnoop:CARD=ALSA,DEV=0" "dsnoop:CARD=ALSA,DEV=1" "dsnoop:CARD=ALSA,DEV=2" "hw:CARD=ALSA,DEV=0" "hw:CARD=ALSA,DEV=1" "hw:CARD=ALSA,DEV=2" "plughw:CARD=ALSA,DEV=0" "plughw:CARD=ALSA,DEV=1" "plughw:CARD=ALSA,DEV=2" "" soundcard from settings: "default:CARD=ALSA" found using soundcard: "default:CARD=ALSA" PulseAudioService: pa_context_connect() failed true [..]
Here's the working example program:
audiooutput.cpp/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include <QAudioDeviceInfo> #include <QAudioOutput> #include <QDebug> #include <QVBoxLayout> #include <qmath.h> #include <qendian.h> #include "audiooutput.h" #define PUSH_MODE_LABEL "Enable push mode" #define PULL_MODE_LABEL "Enable pull mode" #define SUSPEND_LABEL "Suspend playback" #define RESUME_LABEL "Resume playback" #define VOLUME_LABEL "Volume:" const int DurationSeconds = 1; const int ToneSampleRateHz = 600; const int DataSampleRateHz = 44100; const int BufferSize = 32768; Generator::Generator(const QAudioFormat &format, qint64 durationUs, int sampleRate, QObject *parent) : QIODevice(parent) , m_pos(0) { if (format.isValid()) generateData(format, durationUs, sampleRate); } Generator::~Generator() { } void Generator::start() { open(QIODevice::ReadOnly); } void Generator::stop() { m_pos = 0; close(); } void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int sampleRate) { const int channelBytes = format.sampleSize() / 8; const int sampleBytes = format.channelCount() * channelBytes; qint64 length = (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8)) * durationUs / 100000; Q_ASSERT(length % sampleBytes == 0); Q_UNUSED(sampleBytes) // suppress warning in release builds m_buffer.resize(length); unsigned char *ptr = reinterpret_cast<unsigned char *>(m_buffer.data()); int sampleIndex = 0; while (length) { const qreal x = qSin(2 * M_PI * sampleRate * qreal(sampleIndex % format.sampleRate()) / format.sampleRate()); for (int i=0; i<format.channelCount(); ++i) { if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::UnSignedInt) { const quint8 value = static_cast<quint8>((1.0 + x) / 2 * 255); *reinterpret_cast<quint8*>(ptr) = value; } else if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::SignedInt) { const qint8 value = static_cast<qint8>(x * 127); *reinterpret_cast<quint8*>(ptr) = value; } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::UnSignedInt) { quint16 value = static_cast<quint16>((1.0 + x) / 2 * 65535); if (format.byteOrder() == QAudioFormat::LittleEndian) qToLittleEndian<quint16>(value, ptr); else qToBigEndian<quint16>(value, ptr); } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) { qint16 value = static_cast<qint16>(x * 32767); if (format.byteOrder() == QAudioFormat::LittleEndian) qToLittleEndian<qint16>(value, ptr); else qToBigEndian<qint16>(value, ptr); } ptr += channelBytes; length -= channelBytes; } ++sampleIndex; } } qint64 Generator::readData(char *data, qint64 len) { qint64 total = 0; if (!m_buffer.isEmpty()) { while (len - total > 0) { const qint64 chunk = qMin((m_buffer.size() - m_pos), len - total); memcpy(data + total, m_buffer.constData() + m_pos, chunk); m_pos = (m_pos + chunk) % m_buffer.size(); total += chunk; } } return total; } qint64 Generator::writeData(const char *data, qint64 len) { Q_UNUSED(data); Q_UNUSED(len); return 0; } qint64 Generator::bytesAvailable() const { return m_buffer.size() + QIODevice::bytesAvailable(); } AudioTest::AudioTest() : m_pushTimer(new QTimer(this)) , m_modeButton(0) , m_suspendResumeButton(0) , m_deviceBox(0) , m_device(QAudioDeviceInfo::defaultOutputDevice()) , m_generator(0) , m_audioOutput(0) , m_output(0) , m_pullMode(true) , m_buffer(BufferSize, 0) { initializeWindow(); initializeAudio(); } void AudioTest::initializeWindow() { QScopedPointer<QWidget> window(new QWidget); QScopedPointer<QVBoxLayout> layout(new QVBoxLayout); m_deviceBox = new QComboBox(this); const QAudioDeviceInfo &defaultDeviceInfo = QAudioDeviceInfo::defaultOutputDevice(); m_deviceBox->addItem(defaultDeviceInfo.deviceName(), qVariantFromValue(defaultDeviceInfo)); foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { if (deviceInfo != defaultDeviceInfo) m_deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo)); } connect(m_deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int))); layout->addWidget(m_deviceBox); m_modeButton = new QPushButton(this); m_modeButton->setText(tr(PUSH_MODE_LABEL)); connect(m_modeButton, SIGNAL(clicked()), SLOT(toggleMode())); layout->addWidget(m_modeButton); m_suspendResumeButton = new QPushButton(this); m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); layout->addWidget(m_suspendResumeButton); QHBoxLayout *volumeBox = new QHBoxLayout; m_volumeLabel = new QLabel; m_volumeLabel->setText(tr(VOLUME_LABEL)); m_volumeSlider = new QSlider(Qt::Horizontal); m_volumeSlider->setMinimum(0); m_volumeSlider->setMaximum(100); m_volumeSlider->setSingleStep(10); connect(m_volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); volumeBox->addWidget(m_volumeLabel); volumeBox->addWidget(m_volumeSlider); layout->addLayout(volumeBox); window->setLayout(layout.data()); layout.take(); // ownership transferred setCentralWidget(window.data()); QWidget *const windowPtr = window.take(); // ownership transferred windowPtr->show(); } void AudioTest::initializeAudio() { connect(m_pushTimer, SIGNAL(timeout()), SLOT(pushTimerExpired())); m_format.setSampleRate(DataSampleRateHz); m_format.setChannelCount(1); m_format.setSampleSize(16); m_format.setCodec("audio/pcm"); m_format.setByteOrder(QAudioFormat::LittleEndian); m_format.setSampleType(QAudioFormat::SignedInt); QAudioDeviceInfo info(m_device); if (!info.isFormatSupported(m_format)) { qWarning() << "Default format not supported - trying to use nearest"; m_format = info.nearestFormat(m_format); } if (m_generator) delete m_generator; m_generator = new Generator(m_format, DurationSeconds*1000000, ToneSampleRateHz, this); createAudioOutput(); } void AudioTest::createAudioOutput() { delete m_audioOutput; m_audioOutput = 0; m_audioOutput = new QAudioOutput(m_device, m_format, this); m_generator->start(); m_audioOutput->start(m_generator); m_volumeSlider->setValue(int(m_audioOutput->volume()*100.0f)); } AudioTest::~AudioTest() { } void AudioTest::deviceChanged(int index) { m_pushTimer->stop(); m_generator->stop(); m_audioOutput->stop(); m_audioOutput->disconnect(this); m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>(); initializeAudio(); } void AudioTest::volumeChanged(int value) { if (m_audioOutput) m_audioOutput->setVolume(qreal(value/100.0f)); } void AudioTest::pushTimerExpired() { if (m_audioOutput && m_audioOutput->state() != QAudio::StoppedState) { int chunks = m_audioOutput->bytesFree()/m_audioOutput->periodSize(); while (chunks) { const qint64 len = m_generator->read(m_buffer.data(), m_audioOutput->periodSize()); if (len) m_output->write(m_buffer.data(), len); if (len != m_audioOutput->periodSize()) break; --chunks; } } } void AudioTest::toggleMode() { /* m_pushTimer->stop(); m_audioOutput->stop();*/ mySound = new QSound("/home/pi/untitled.wav"); mySound->setLoops(QSound::Infinite); mySound->play(); /* if (m_pullMode) { //switch to push mode (periodically push to QAudioOutput using a timer) m_modeButton->setText(tr(PULL_MODE_LABEL)); m_output = m_audioOutput->start(); m_pullMode = false; m_pushTimer->start(20); } else { //switch to pull mode (QAudioOutput pulls from Generator as needed) m_modeButton->setText(tr(PUSH_MODE_LABEL)); m_pullMode = true; m_audioOutput->start(m_generator); } */ m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); } void AudioTest::toggleSuspendResume() { if (m_audioOutput->state() == QAudio::SuspendedState) { m_audioOutput->resume(); m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); } else if (m_audioOutput->state() == QAudio::ActiveState) { m_audioOutput->suspend(); m_suspendResumeButton->setText(tr(RESUME_LABEL)); } else if (m_audioOutput->state() == QAudio::StoppedState) { m_audioOutput->resume(); m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); } else if (m_audioOutput->state() == QAudio::IdleState) { // no-op } }
audiooutput.h
/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef AUDIOOUTPUT_H #define AUDIOOUTPUT_H #include <math.h> #include <QAudioOutput> #include <QByteArray> #include <QComboBox> #include <QIODevice> #include <QLabel> #include <QMainWindow> #include <QObject> #include <QPushButton> #include <QSlider> #include <QTimer> #include <QSound> class Generator : public QIODevice { Q_OBJECT public: Generator(const QAudioFormat &format, qint64 durationUs, int sampleRate, QObject *parent); ~Generator(); void start(); void stop(); qint64 readData(char *data, qint64 maxlen); qint64 writeData(const char *data, qint64 len); qint64 bytesAvailable() const; private: void generateData(const QAudioFormat &format, qint64 durationUs, int sampleRate); private: qint64 m_pos; QByteArray m_buffer; }; class AudioTest : public QMainWindow { Q_OBJECT public: AudioTest(); ~AudioTest(); private: void initializeWindow(); void initializeAudio(); void createAudioOutput(); private: QTimer *m_pushTimer; QSound *mySound; // Owned by layout QPushButton *m_modeButton; QPushButton *m_suspendResumeButton; QComboBox *m_deviceBox; QLabel *m_volumeLabel; QSlider *m_volumeSlider; QAudioDeviceInfo m_device; Generator *m_generator; QAudioOutput *m_audioOutput; QIODevice *m_output; // not owned QAudioFormat m_format; bool m_pullMode; QByteArray m_buffer; private slots: void pushTimerExpired(); void toggleMode(); void toggleSuspendResume(); void deviceChanged(int index); void volumeChanged(int); }; #endif // AUDIOOUTPUT_H
output from the example program:
Debugging starts libEGL warning: DRI2: failed to authenticate PulseAudioService: pa_context_connect() failed Default format not supported - trying to use nearest using null output device, none available
Here are my versions:
$ uname -a Linux raspberrypi 4.19.66-v7+ #1253 SMP Thu Aug 15 11:49:46 BST 2019 armv7l GNU/Linux $ qtcreator -version libEGL warning: DRI2: failed to authenticate Qt Creator 4.2.0 based on Qt 5.7.1 Android 4.2.0 Support for deployment to and execution on Android Devices. AutoTest 4.2.0 Auto Test plugin. AutotoolsProjectManager 4.2.0 Autotools project integration. BareMetal 4.2.0 This plugin adds a target for bare metal development. Bazaar 4.2.0 Bazaar integration. Beautifier 4.2.0 Format source files with the help of beautifiers like AStyle, uncrustify or clang-format. BinEditor 4.2.0 Binary editor component. Bookmarks 4.2.0 Bookmarks in text editors. CMakeProjectManager 4.2.0 CMake support. CVS 4.2.0 CVS integration. ClangStaticAnalyzer 4.2.0 ClangStaticAnalyzer Plugin. ClassView 4.2.0 Class View component. ClearCase 4.2.0 ClearCase integration. CodePaster 4.2.0 Codepaster plugin for pushing/fetching diff from server. Core 4.2.0 The core plugin for the Qt IDE. CppEditor 4.2.0 C/C++ editor component. CppTools 4.2.0 Tools for analyzing C/C++ code. Debugger 4.2.0 Debugger integration. Designer 4.2.0 Qt Designer integration. DiffEditor 4.2.0 Diff editor component. EmacsKeys 4.2.0 The main idea behind this plugin is to provide additional actions a typical emacs user would expect. It doesn't claim to provide full emacs emulation. The following actions are available: - Movement [C-f, C-b, C-n, C-p, M-f, M-b, C-a, C-e, M-<, M->] - Mark-based selection [C-SPC, C-x C-x] - Cut/copy/yank (doesn't provide kill ring feature) [M-w, C-w, C-y] - Kill actions, which interact properly with clipboard [C-k, M-d, C-d] - Scrolling (half of the screen, keeps cursor visible) [C-v, M-v] - Insert new line and indent [C-j] IMPORTANT: Actions are not bound to any key combinations by default. You can find them under 'EmacsKeys' section in keyboard shortcuts settings. Also it's worth mentioning that EmacsKeys plugin forces disabling of menu mnemonics by calling Qt's qt_set_sequence_auto_mnemonic function with false argument. Many of the english menu mnemonics get into the way of typical emacs keys, this includes: Alt+F (File), Alt+B (Build), Alt+W (Window). It's a temporary solution, it remains until there is a better one. FakeVim 4.2.0 VI-style keyboard navigation. GLSLEditor 4.2.0 Editor for GLSL. GenericProjectManager 4.2.0 Generic support. Git 4.2.0 Git integration. Help 4.2.0 Help system. ImageViewer 4.2.0 Image Viewer component. Ios 4.2.0 Support for deployment to and execution on iOS Devices. Macros 4.2.0 Macros in text editors. Mercurial 4.2.0 Mercurial integration. ModelEditor 4.2.0 Graphical modeling with structured diagrams. Nim 4.2.0 Plugin for supporting the Nim programming language. Perforce 4.2.0 Perforce integration. ProjectExplorer 4.2.0 ProjectExplorer framework that can be extended with different kind of project types. PythonEditor 4.2.0 Editor and file creation wizards for Python. Example plugin for QtCreator API demonstration. QbsProjectManager 4.2.0 QBS support. QmakeAndroidSupport 4.2.0 Android support for qmake project manager. QmakeProjectManager 4.2.0 Provides project type for Qt/QMake .pro files and tools. QmlDesigner 4.2.0 Visual Designer for QML files. QmlJSEditor 4.2.0 Editor for QML and JavaScript. QmlJSTools 4.2.0 Tools for analyzing Qml/JS code. QmlProfiler 4.2.0 Qml Profiler Plugin. QmlProjectManager 4.2.0 Qt Quick support Qnx 4.2.0 Adds support for QNX to Qt Creator. QtSupport 4.2.0 Provides support code for build systems. RemoteLinux 4.2.0 Support for deployment to and execution on a remote Linux host. ResourceEditor 4.2.0 Editor for qrc files. ScxmlEditor 4.2.0 Visual Editor for SCXML (State Chart XML) files. Subversion 4.2.0 Subversion integration. TaskList 4.2.0 Use .tasks-files to populate the Issues view. TextEditor 4.2.0 Text editor framework and the implementation of the basic text editor. Todo 4.2.0 Adds pane that lists all TODO, FIXME, etc. entries in comments. UpdateInfo 4.2.0 Displays Update-Infos for Qt Installer Framework-based Updaters. Valgrind 4.2.0 Valgrind Plugin. VcsBase 4.2.0 Version Control System Base Plugin. Welcome 4.2.0 Default Welcome Screen Plugin. WinRt 4.2.0 Helper for Windows Runtime projects. (C) 2016 The Qt Company Ltd