Update copyright headers
[qt:qt.git] / demos / mobile / guitartuner / src / guitartuner.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of The Qt Company Ltd nor the names of its
21 **     contributors may be used to endorse or promote products derived
22 **     from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "guitartuner.h"
42
43 #ifdef Q_OS_SYMBIAN
44 #include <SoundDevice.h>
45 #endif // Q_OS_SYMBIAN
46
47 #if defined(Q_OS_SYMBIAN) && defined(ORIENTATIONLOCK)
48 #include <eikenv.h>
49 #include <eikappui.h>
50 #include <aknenv.h>
51 #include <aknappui.h>
52 #endif // Q_OS_SYMBIAN && ORIENTATIONLOCK
53
54 GuitarTuner::GuitarTuner(QWidget *parent) :
55     QMainWindow(parent)
56 {
57
58     // Set up the QML.
59     m_guitarTunerUI = new QDeclarativeView(QUrl("qrc:/src/application.qml"), this);
60     setCentralWidget(m_guitarTunerUI);
61     m_guitarTunerUI->setResizeMode(QDeclarativeView::SizeRootObjectToView);
62     qmlObject = m_guitarTunerUI->rootObject();
63
64     // Init audio output and input.
65     initAudioOutput();
66     initAudioInput();
67
68     // Connect the quit signal of m_guitarTunerUI
69     // into the close slot of this.
70     connect(m_guitarTunerUI->engine(), SIGNAL(quit()), SLOT(close()));
71
72     // Connect the signals from qmlObject into proper slots
73     // of this and m_voicegenerator.
74     connect(qmlObject, SIGNAL(muteStateChanged(bool)),
75             SLOT(muteStateChanged(bool)));
76     connect(qmlObject, SIGNAL(volumeChanged(qreal)),
77             m_voicegenerator, SLOT(setAmplitude(qreal)));
78     connect(qmlObject, SIGNAL(volumeChanged(qreal)),
79             SLOT(setMaxVolumeLevel(qreal)));
80
81     // Connect the modeChanged signal from qmlObject
82     // into modeChanged slot of this class.
83     connect(qmlObject, SIGNAL(modeChanged(bool)),
84             SLOT(modeChanged(bool)));
85
86     // Connect the microphoneSensitivityChanged signal from
87     // m_guitarTunerUI into setCutOffPercentage slot of m_analyzer class.
88     connect(qmlObject, SIGNAL(microphoneSensitivityChanged(qreal)),
89             m_analyzer, SLOT(setCutOffPercentage(qreal)));
90
91     // Connect the signals from m_analyzer into slots of qmlObject.
92     connect(m_analyzer, SIGNAL(lowVoice()),
93             qmlObject, SLOT(lowVoice()));
94     connect(m_analyzer, SIGNAL(correctFrequency()),
95             qmlObject, SLOT(correctFrequencyObtained()));
96     connect(m_analyzer, SIGNAL(voiceDifference(QVariant)),
97             qmlObject, SLOT(voiceDifferenceChanged(QVariant)));
98
99     // Initialise the MaximumVoiceDifference
100     // value of qmlObject with the value obtained from m_analyzer.
101     qmlObject->setProperty("maxVoiceDifference",
102                            m_analyzer->getMaximumVoiceDifference());
103
104     // Connect the targetFrequencyChanged signal of qmlObject
105     // into targetFrequencyChanged slot of this class.
106     connect(qmlObject, SIGNAL(targetFrequencyChanged(qreal)),
107             SLOT(targetFrequencyChanged(qreal)));
108
109     // Start voice output or input by using the modeChanged function,
110     // depending of the current mode.
111     modeChanged(qmlObject->property("isInput").toBool());
112
113 }
114
115 /**
116   * Inits audio output.
117   */
118 void GuitarTuner::initAudioOutput()
119 {
120     // Set up the output format.
121     m_format_output.setFrequency(DataFrequencyHzOutput);
122     m_format_output.setCodec("audio/pcm");
123     m_format_output.setSampleSize(16);
124     m_format_output.setChannels(1);
125     m_format_output.setByteOrder(QAudioFormat::LittleEndian);
126     m_format_output.setSampleType(QAudioFormat::SignedInt);
127
128     // Obtain a default output device, and if the format is not
129     // supported, find the nearest format available.
130     QAudioDeviceInfo outputDeviceInfo(
131                 QAudioDeviceInfo::defaultOutputDevice());
132     if (!outputDeviceInfo.isFormatSupported(m_format_output)) {
133         m_format_output = outputDeviceInfo.nearestFormat(m_format_output);
134     }
135
136     // Create new QAudioOutput and VoiceGenerator instances, and store
137     // them in m_audioOutput and m_voicegenerator, respectively.
138     m_audioOutput = new QAudioOutput(outputDeviceInfo,
139                                      m_format_output, this);
140     m_voicegenerator = new VoiceGenerator(m_format_output,
141                                           qmlObject->property("frequency").toReal(),
142                                           qmlObject->property("volume").toReal(),
143                                           this);
144
145     // Connect m_audioOutput stateChanged signal to outputStateChanged.
146     connect(m_audioOutput, SIGNAL(stateChanged(QAudio::State)),
147             SLOT(outputStateChanged(QAudio::State)));
148 }
149
150 /**
151   * Inits audio input.
152   */
153 void GuitarTuner::initAudioInput()
154 {
155     // Set up the input format.
156     m_format_input.setFrequency(DataFrequencyHzInput);
157     m_format_input.setCodec("audio/pcm");
158     m_format_input.setSampleSize(16);
159     m_format_input.setChannels(1);
160     m_format_input.setByteOrder(QAudioFormat::LittleEndian);
161     m_format_input.setSampleType(QAudioFormat::SignedInt);
162
163     // Obtain a default input device, and if the format is not
164     // supported, find the nearest format available.
165     QAudioDeviceInfo inputDeviceInfo(
166                 QAudioDeviceInfo::defaultInputDevice());
167     if (!inputDeviceInfo.isFormatSupported(m_format_input)) {
168         m_format_input = inputDeviceInfo.nearestFormat(m_format_input);
169     }
170
171     // Create new QAudioInput and VoiceAnalyzer instances, and store
172     // them in m_audioInput and m_analyzer, respectively.
173     // Remember to set the cut-off percentage for voice analyzer.
174     m_audioInput = new QAudioInput(inputDeviceInfo, m_format_input, this);
175     m_analyzer = new VoiceAnalyzer(m_format_input, this);
176     m_analyzer->setCutOffPercentage(qmlObject->property("sensitivity").toReal());
177
178 }
179
180 /**
181   * Receives a mode changed signal.
182   */
183 void GuitarTuner::modeChanged(bool isInput)
184 {
185
186
187
188     // If the mode must be changed to input mode:
189     if (isInput) {
190
191         // Stop audio output and audio generator.
192         m_audioOutput->stop();
193         m_voicegenerator->stop();
194         // Start the audio analyzer and then the audio input.
195         m_analyzer->start(qmlObject->property("frequency").toReal());
196         m_audioInput->start(m_analyzer);
197
198     }
199     // Else:
200     else {
201
202         // Stop audio input and audio analyzer.
203         m_audioInput->stop();
204         m_analyzer->stop();
205
206         // Set up the audio output.
207
208         // If the current frequency of voice generator
209         // is not the same as the target frequency selected in the UI,
210         // update voice generator's frequency.
211         if (m_voicegenerator->frequency() != qmlObject->property("frequency").toReal()) {
212             m_voicegenerator->setFrequency(qmlObject->property("frequency").toReal());
213         }
214
215         // Start the voice generator and then the audio output.
216         m_voicegenerator->start();
217         m_audioOutput->start(m_voicegenerator);
218         // Call setMaxVolumeLevel(1) to set the maximum volume louder.
219         setMaxVolumeLevel(qmlObject->property("volume").toReal());
220
221         // If the voice is muted, the voice is suspended
222         // in the outputStateChanged slot.
223
224     }
225 }
226
227 /**
228   * Receives a output state changed signal.
229   * Suspends the audio output, if the state is ActiveState
230   * and the voice is muted.
231   */
232 void GuitarTuner::outputStateChanged(QAudio::State state)
233 {
234     if (QAudio::ActiveState == state && qmlObject->property("isMuted").toBool()) {
235         // If the voice is muted, suspend the voice.
236         m_audioOutput->suspend();
237     }
238 }
239
240 /**
241   * Receives a mute state changed signal.
242   * Suspends the audio output or resumes it, depending of the
243   * isMuted parameter.
244   */
245 void GuitarTuner::muteStateChanged(bool isMuted)
246 {
247     if (isMuted) {
248         m_audioOutput->suspend();
249     }
250     else {
251         m_audioOutput->resume();
252     }
253 }
254
255 /**
256   * Receives a target frequency signal.
257   */
258 void GuitarTuner::targetFrequencyChanged(qreal targetFrequency)
259 {
260     // If the output mode is active:
261     if (!qmlObject->property("isInput").toBool()) {
262         // Stop the audio output and voice generator.
263         m_audioOutput->stop();
264         m_voicegenerator->stop();
265         // Set the voice generator's frequency to the target frequency.
266         m_voicegenerator->setFrequency(targetFrequency);
267         // Start the voice generator and audio output.
268         m_voicegenerator->start();
269         m_audioOutput->start(m_voicegenerator);
270         // Call setMaxVolumeLevel(1) to set the maximum volume louder.
271         setMaxVolumeLevel(qmlObject->property("volume").toReal());
272
273         // If the voice is muted, the voice is suspended
274         // in the outputStateChanged slot.
275
276     }
277     // Else:
278     else {
279
280         // Stop the audio input and voice analyzer.
281         m_audioInput->stop();
282         m_analyzer->stop();
283         // Start the voice analyzer with new frequency and audio input.
284         m_analyzer->start(targetFrequency);
285         m_audioInput->start(m_analyzer);
286
287     }
288 }
289
290 /**
291   * This method provides a hack to set the maximum volume level in
292   * Symbian.
293   */
294 void GuitarTuner::setMaxVolumeLevel(qreal percent)
295 {
296     if (percent >= 1.0) {
297         percent = 1.0;
298     }
299     else if (percent <= 0.0) {
300         percent = 0.0;
301     }
302     percent = percent*0.5 + 0.5;
303     // Warning! This is a hack, which can break when the QtMobility
304     // changes. Use at your own risk.
305 #ifdef Q_OS_SYMBIAN
306     unsigned int *pointer_to_abstract_audio
307             = (unsigned int*)( (unsigned char*)m_audioOutput + 8 );
308     unsigned int *dev_sound_wrapper
309             = (unsigned int*)(*pointer_to_abstract_audio) + 16;
310     unsigned int *temp
311             = ((unsigned int*)(*dev_sound_wrapper) + 6);
312     CMMFDevSound *dev_sound = (CMMFDevSound*)(*temp);
313     dev_sound->SetVolume((unsigned int)
314                          (percent*(float)dev_sound->MaxVolume()));
315 #endif
316 }
317
318 /**
319   * A function used to lock the orientation.
320   */
321 void GuitarTuner::setOrientation(Orientation orientation)
322 {
323 #ifdef Q_OS_SYMBIAN
324     if (orientation != Auto) {
325 #if defined(ORIENTATIONLOCK)
326         const CAknAppUiBase::TAppUiOrientation uiOrientation =
327                 (orientation == LockPortrait)
328                     ? CAknAppUi::EAppUiOrientationPortrait
329                     : CAknAppUi::EAppUiOrientationLandscape;
330         CAknAppUi* appUi = dynamic_cast<CAknAppUi*>
331                 (CEikonEnv::Static()->AppUi());
332         TRAPD(error,
333             if (appUi)
334                 appUi->SetOrientationL(uiOrientation);
335         );
336 #else // ORIENTATIONLOCK
337         qWarning(QString("'ORIENTATIONLOCK' needs to be defined on")
338                  +QString(" Symbian when locking the orientation."));
339 #endif // ORIENTATIONLOCK
340     }
341 #elif defined(Q_WS_MAEMO_5)
342     Qt::WidgetAttribute attribute;
343     switch (orientation) {
344     case LockPortrait:
345         attribute = Qt::WA_Maemo5PortraitOrientation;
346         break;
347     case LockLandscape:
348         attribute = Qt::WA_Maemo5LandscapeOrientation;
349         break;
350     case Auto:
351     default:
352         attribute = Qt::WA_Maemo5AutoOrientation;
353         break;
354     }
355     setAttribute(attribute, true);
356 #else // Q_OS_SYMBIAN
357     Q_UNUSED(orientation);
358 #endif // Q_OS_SYMBIAN
359 }