| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. |
| 4 | ** Contact: http://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the QtFeedback module of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at http://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** GNU Lesser General Public License Usage |
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
| 19 | ** General Public License version 3 as published by the Free Software |
| 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
| 21 | ** packaging of this file. Please review the following information to |
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements |
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
| 24 | ** |
| 25 | ** GNU General Public License Usage |
| 26 | ** Alternatively, this file may be used under the terms of the GNU |
| 27 | ** General Public License version 2.0 or later as published by the Free |
| 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
| 29 | ** the packaging of this file. Please review the following information to |
| 30 | ** ensure the GNU General Public License version 2.0 requirements will be |
| 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
| 32 | ** |
| 33 | ** $QT_END_LICENSE$ |
| 34 | ** |
| 35 | ****************************************************************************/ |
| 36 | |
| 37 | #include "qfeedbackeffect.h" |
| 38 | #include "qfeedbackeffect_p.h" |
| 39 | #include "qfeedbackplugininterfaces.h" |
| 40 | |
| 41 | #include <QtCore> |
| 42 | #include <QDebug> |
| 43 | |
| 44 | |
| 45 | QT_BEGIN_NAMESPACE |
| 46 | |
| 47 | /*! |
| 48 | \class QFeedbackEffect |
| 49 | \brief The QFeedbackEffect class is the abstract base class for feedback effects. |
| 50 | \ingroup feedback |
| 51 | \inmodule QtFeedback |
| 52 | |
| 53 | It represents an effect to provide feedback to a person (i.e., an effect that |
| 54 | affect human senses). The technology available today usually only |
| 55 | provides haptic effects, which deal with the sense of touch, and audio effects. The |
| 56 | QFeedbackHapticsEffect and QFeedbackFileEffect are implementations |
| 57 | of haptic effects and can be used to control a mobile device's |
| 58 | vibrator. In addition, the QFeedbackFileEffect can also be used to play |
| 59 | audio feedback. |
| 60 | |
| 61 | Feedback effects have a duration, which is measured in |
| 62 | milliseconds. Subclasses reimplement duration() to inform how long |
| 63 | the effect lasts. The duration is the total time the effect will |
| 64 | last, and thus includes any envelope modifiers (attack and fade). |
| 65 | |
| 66 | At any given time, a feedback effect is in one of four states: |
| 67 | Loading, Stopped, Running, or Paused. See the |
| 68 | \l{QFeedbackEffect::}{State} enum documentation for further |
| 69 | details. Subclasses must reimplement state() to report which |
| 70 | state an effect is in, and setState() to receive state change |
| 71 | requests. The start(), pause(), and stop() slots calls |
| 72 | setState() with the corresponding new \l{QFeedbackEffect::}{State}. Changes |
| 73 | in state are reported through the stateChanged() signal and may happen |
| 74 | asynchronously some time after the state change request. |
| 75 | |
| 76 | A system often has a set of standard feedback effects for user |
| 77 | interface interaction (e.g., button clicks). The |
| 78 | \l{QFeedbackEffect::}{Effect} describes the standard effects |
| 79 | that QFeedbackEffect supports. It is named so because the effects |
| 80 | often depend on the theme of the user interface. You can play |
| 81 | these effects using the playThemeEffect() function. |
| 82 | |
| 83 | \code |
| 84 | QFeedbackEffect::playThemeEffect(QFeedbackEffect::Press); |
| 85 | \endcode |
| 86 | |
| 87 | The playThemeEffect() function returns true if the effect was |
| 88 | played successfully. An effect may not be played if the system does |
| 89 | not support it or if an error occurred. |
| 90 | */ |
| 91 | |
| 92 | /*! |
| 93 | \fn void QFeedbackEffect::error(QFeedbackEffect::ErrorType error) const |
| 94 | |
| 95 | This signal is emitted by subclasses if an \a error occurred during |
| 96 | playback of an effect. The \l{QFeedbackEffect::}{ErrorType} enum |
| 97 | describes the errors that can be reported. |
| 98 | */ |
| 99 | |
| 100 | /*! |
| 101 | \fn void QFeedbackEffect::stateChanged() |
| 102 | |
| 103 | This signal is emitted by subclasses when the \l State of the |
| 104 | effect changes. |
| 105 | |
| 106 | \sa state() |
| 107 | */ |
| 108 | |
| 109 | /*! |
| 110 | \enum QFeedbackEffect::State |
| 111 | |
| 112 | This enum describes the state of the effect. An effect will be in |
| 113 | one of these states. |
| 114 | |
| 115 | \value Stopped The effect is not running. This is the initial |
| 116 | state. The state changes to either Loading when loading an effect |
| 117 | or to Running when the effect is started by calling start(). When |
| 118 | an effect has finished playing, it will enter the Stopped state |
| 119 | again. |
| 120 | |
| 121 | \value Paused The effect is paused. Calling start() will resume it. |
| 122 | |
| 123 | \value Running The effect is running. You can control the current state |
| 124 | by calling the stop() or pause() functions. |
| 125 | |
| 126 | \value Loading The effect is loading. That can happen when loading |
| 127 | is done asynchronously. When the effect has loaded, the state will change |
| 128 | to either Running (if start() has been called) or Stopped. |
| 129 | |
| 130 | \sa state() |
| 131 | */ |
| 132 | |
| 133 | |
| 134 | /*! |
| 135 | \enum QFeedbackEffect::ErrorType |
| 136 | |
| 137 | This enum describes the possible errors happening on the effect. |
| 138 | |
| 139 | \value UnknownError An unknown error occurred. |
| 140 | |
| 141 | \value DeviceBusy The feedback could not start because the device is busy. |
| 142 | |
| 143 | \sa error() |
| 144 | */ |
| 145 | |
| 146 | /*! |
| 147 | \enum QFeedbackEffect::Effect |
| 148 | |
| 149 | This enum describes all possible effect types. Effects might |
| 150 | be tactile, or audio or visual. |
| 151 | |
| 152 | Not all platforms and devices have distinct effects for each type. |
| 153 | |
| 154 | \value Effect.Undefined - Undefined feedback. No feedback is given. |
| 155 | \value Effect.Press - Feedback for when the screen is pressed. |
| 156 | \value Effect.Release - Feedback for touch release. |
| 157 | \value Effect.PressWeak - A weak feedback for press. |
| 158 | \value Effect.ReleaseWeak - A weak feedback for release. |
| 159 | \value Effect.PressStrong - A strong feedback for press. |
| 160 | \value Effect.ReleaseStrong - A strong feedback for release. |
| 161 | \value Effect.DragStart - Feedback for when dragging starts. |
| 162 | \value Effect.DragDropInZone - Feedback for when dragging ends and touch is released inside a drop zone. |
| 163 | \value Effect.DragDropOutOfZone - Feedback for when dragging ends and touch is released outside a drop zone. |
| 164 | \value Effect.DragCrossBoundary - Feedback for when crossing a boundary while dragging. |
| 165 | \value Effect.Appear - Feedback for when an item is shown. |
| 166 | \value Effect.Disappear - Feedback for when an item is closed. |
| 167 | \value Effect.Move - Feedback for dragging on screen. |
| 168 | \value NumberOfEffects The number of built-in effects. |
| 169 | \value UserEffect The starting point for any user defined effects, where supported. |
| 170 | */ |
| 171 | |
| 172 | /*! |
| 173 | \enum QFeedbackEffect::Duration |
| 174 | This enum describes the possible effect predefined duration types. Generally a specific |
| 175 | milliseconds value can be supplied instead of one of these values. |
| 176 | |
| 177 | \value Infinite Infinite effect duration |
| 178 | */ |
| 179 | |
| 180 | /*! |
| 181 | \property QFeedbackEffect::state |
| 182 | \brief state of the feedback effect. |
| 183 | |
| 184 | This returns the state of the feedback effect. The \l State enumeration reports |
| 185 | the possible states. |
| 186 | */ |
| 187 | |
| 188 | /*! |
| 189 | \property QFeedbackEffect::duration |
| 190 | \brief duration of the feedback effect, in milliseconds. |
| 191 | |
| 192 | In some cases the duration will be unknown, which will be reported as 0. If the duration |
| 193 | is infinite, QFeedbackEffect::Infinite will be returned. Some subclasses may have |
| 194 | more than one type of duration (for example, \l QFeedbackHapticsEffect), and this |
| 195 | property will return the total duration of the effect. |
| 196 | */ |
| 197 | |
| 198 | /*! |
| 199 | Constructs the QFeedbackEffect base class, and passes \a parent to |
| 200 | QObject's constructor. This is called by the classes that inherit |
| 201 | from this class. |
| 202 | */ |
| 203 | QFeedbackEffect::QFeedbackEffect(QObject *parent) : QObject(parent) |
| 204 | { |
| 205 | } |
| 206 | |
| 207 | /*! |
| 208 | \fn void QFeedbackEffect::start() |
| 209 | |
| 210 | Starts playing the effect. If an error occurs the |
| 211 | error() signal will be emitted. |
| 212 | |
| 213 | \sa stop() |
| 214 | */ |
| 215 | void QFeedbackEffect::start() |
| 216 | { |
| 217 | setState(Running); |
| 218 | } |
| 219 | |
| 220 | /*! |
| 221 | \fn void QFeedbackEffect::stop() |
| 222 | |
| 223 | Stops a playing effect. If an error occurs the |
| 224 | error() signal will be emitted. |
| 225 | |
| 226 | \sa start(), pause(), setState() |
| 227 | */ |
| 228 | void QFeedbackEffect::stop() |
| 229 | { |
| 230 | setState(Stopped); |
| 231 | } |
| 232 | |
| 233 | /*! |
| 234 | \fn void QFeedbackEffect::pause() |
| 235 | |
| 236 | Pauses a playing effect. If an error occurs the |
| 237 | error() signal will be emitted. Not all systems |
| 238 | support pausing an effect during playback. |
| 239 | */ |
| 240 | void QFeedbackEffect::pause() |
| 241 | { |
| 242 | setState(Paused); |
| 243 | } |
| 244 | |
| 245 | /*! |
| 246 | \fn QFeedbackEffect::playThemeEffect(Effect effect) |
| 247 | |
| 248 | This function plays \a effect instantly and returns true if the |
| 249 | effect could be played; otherwise, returns false. |
| 250 | */ |
| 251 | bool QFeedbackEffect::playThemeEffect(Effect effect) |
| 252 | { |
| 253 | if (QFeedbackThemeInterface *iface = QFeedbackThemeInterface::instance()) |
| 254 | return iface->play(effect); |
| 255 | return false; |
| 256 | } |
| 257 | |
| 258 | /*! |
| 259 | \fn QFeedbackEffect::supportsThemeEffect() |
| 260 | |
| 261 | Returns true if playing themed feedback is available. |
| 262 | |
| 263 | */ |
| 264 | bool QFeedbackEffect::supportsThemeEffect() |
| 265 | { |
| 266 | return QFeedbackThemeInterface::instance() != 0; |
| 267 | } |
| 268 | |
| 269 | /*! |
| 270 | \class QFeedbackHapticsEffect |
| 271 | \ingroup feedback |
| 272 | \inmodule QtFeedback |
| 273 | \brief The QFeedbackHapticsEffect class allows you to play a haptics effect. |
| 274 | |
| 275 | A haptics effect is an effect that takes advantage of the sense of |
| 276 | touch. Most mobile devices today supports one such effect, |
| 277 | vibration, which will then be the default when you create a |
| 278 | QFeedbackHapticsEffect. |
| 279 | |
| 280 | A haptics effect has a few parameters that must be set up before |
| 281 | it can be played: |
| 282 | |
| 283 | \list |
| 284 | \li duration(): The total duration of the effect in milliseconds. |
| 285 | \li intensity(): The intensity, e.g., how hard the device will vibrate. |
| 286 | \endlist |
| 287 | |
| 288 | An effect can, for example, be set up as follows: |
| 289 | |
| 290 | \omit I'm right that this is all that is required to be set? \endomit |
| 291 | \code |
| 292 | QFeedbackHapticsEffect rumble; |
| 293 | rumble.setIntensity(1.0); |
| 294 | rumble.setDuration(100); |
| 295 | \endcode |
| 296 | |
| 297 | You can now start() the effect. |
| 298 | |
| 299 | \code |
| 300 | rumble.start(); |
| 301 | \endcode |
| 302 | |
| 303 | At any given time, the effect is in one of four states: |
| 304 | \l{QFeedbackEffect::}{Stopped}, \l{QFeedbackEffect::}{Paused}, |
| 305 | \l{QFeedbackEffect::}{Running}, or \l{QFeedbackEffect::}{Loading}. |
| 306 | You can request a state change by calling start(), pause(), or |
| 307 | stop(). The state is queried with state(). |
| 308 | |
| 309 | The haptics effect also supports a fade-in of the effect. For |
| 310 | vibration, this means that the vibration will grow (or sink) in |
| 311 | intensity from when the effect starts until intensity() is |
| 312 | reached. You can set that up as follows: |
| 313 | |
| 314 | \code |
| 315 | rumble.setAttackIntensity(0.0); |
| 316 | rumble.setAttackTime(250); |
| 317 | \endcode |
| 318 | |
| 319 | Attack intensity is the start intensity and attack time is the |
| 320 | duration of the fade-in. We have a similar fade-out: |
| 321 | |
| 322 | \code |
| 323 | rumble.setFadeTime(250); |
| 324 | rumble.setFadeIntensity(0.0); |
| 325 | \endcode |
| 326 | |
| 327 | When using fade-in and fade-out the total duration of the haptics |
| 328 | effect will be: duration(); the main intensity() will be played for |
| 329 | (duration() - (attackTime() + fadeTime())) milliseconds. |
| 330 | |
| 331 | A QFeedbackHapticsEffect is played on an |
| 332 | \l{QFeedbackHapticsEffect::}{actuator()}, which is the physical component that |
| 333 | performs the effect. You can query if other actuators are |
| 334 | available - see the QFeedbackActuator::actuators() function |
| 335 | documentation for details. |
| 336 | |
| 337 | Errors occurring during playback are notified through the |
| 338 | error() signal. |
| 339 | |
| 340 | \sa QFeedbackActuator |
| 341 | */ |
| 342 | |
| 343 | /*! |
| 344 | \fn virtual void QFeedbackEffect::setState(State state) = 0 |
| 345 | |
| 346 | Requests the effect to change its State to change to the specified \a state. |
| 347 | |
| 348 | Subclasses reimplement this function to handle state change requests |
| 349 | for the effect. |
| 350 | */ |
| 351 | |
| 352 | /*! |
| 353 | Constructs the QFeedbackHapticsEffect class, and passes \a parent to |
| 354 | QObject's constructor. The default QFeedbackActuator will be used. |
| 355 | |
| 356 | \sa QFeedbackActuator::actuators() |
| 357 | */ |
| 358 | QFeedbackHapticsEffect::QFeedbackHapticsEffect(QObject *parent) : QFeedbackEffect(parent), priv(new QFeedbackHapticsEffectPrivate) |
| 359 | { |
| 360 | setActuator(0); |
| 361 | } |
| 362 | |
| 363 | |
| 364 | /*! |
| 365 | Destroys this effect and stops the feedback if it is running. |
| 366 | */ |
| 367 | QFeedbackHapticsEffect::~QFeedbackHapticsEffect() |
| 368 | { |
| 369 | stop(); |
| 370 | } |
| 371 | |
| 372 | /*! |
| 373 | \property QFeedbackHapticsEffect::duration |
| 374 | \brief the expected duration of the effect. |
| 375 | |
| 376 | This property defines the total duration of the feedback effect, in milliseconds. |
| 377 | It includes the duration of any fade-in or fade-out parts, if any, in non-periodic |
| 378 | effects, and includes all repetitions of the period in periodic-effects, if any. |
| 379 | |
| 380 | If the duration is set to a value less than attackTime() + fadeTime(), or less |
| 381 | than the period() of the effect, the waveform which will result is |
| 382 | backend-specific. |
| 383 | |
| 384 | \sa fadeTime(), attackTime(), period() |
| 385 | */ |
| 386 | int QFeedbackHapticsEffect::duration() const |
| 387 | { |
| 388 | return priv->duration; |
| 389 | } |
| 390 | void QFeedbackHapticsEffect::setDuration(int msecs) |
| 391 | { |
| 392 | if (priv->duration == msecs) |
| 393 | return; |
| 394 | priv->duration = msecs; |
| 395 | QFeedbackHapticsInterface::instance()->updateEffectProperty(this, QFeedbackHapticsInterface::Duration); |
| 396 | } |
| 397 | |
| 398 | /*! |
| 399 | \property QFeedbackHapticsEffect::intensity |
| 400 | \brief the intensity of the effect. |
| 401 | |
| 402 | This property defines the intensity of the feedback effect. |
| 403 | The value can be between 0 and 1. |
| 404 | |
| 405 | For non-periodic effects, the effect will be at this intensity for |
| 406 | (duration() - (attackTime() + fadeTime())) milliseconds. |
| 407 | For periodic effects, the effect will be at this intensity once per |
| 408 | period for (period() - (attackTime() + fadeTime())) milliseconds. |
| 409 | */ |
| 410 | qreal QFeedbackHapticsEffect::intensity() const |
| 411 | { |
| 412 | return priv->intensity; |
| 413 | } |
| 414 | void QFeedbackHapticsEffect::setIntensity(qreal intensity) |
| 415 | { |
| 416 | if (priv->intensity == intensity) |
| 417 | return; |
| 418 | priv->intensity = intensity; |
| 419 | QFeedbackHapticsInterface::instance()->updateEffectProperty(this, QFeedbackHapticsInterface::Intensity); |
| 420 | } |
| 421 | |
| 422 | /*! |
| 423 | \property QFeedbackHapticsEffect::attackTime |
| 424 | \brief the duration of the fade-in effect. |
| 425 | |
| 426 | This property defines the duration of the fade-in effect in milliseconds. |
| 427 | The effect will ramp up (or down) from attackIntensity() to intensity() in attackTime() milliseconds. |
| 428 | |
| 429 | If the attack time is set to a value such that attackTime() + fadeTime() |
| 430 | is greater than duration() for non-periodic effects, or greater than |
| 431 | period() for periodic effects, the waveform which will result is |
| 432 | backend-specific. |
| 433 | |
| 434 | \sa duration(), period() |
| 435 | */ |
| 436 | int QFeedbackHapticsEffect::attackTime() const |
| 437 | { |
| 438 | return priv->attackTime; |
| 439 | } |
| 440 | void QFeedbackHapticsEffect::setAttackTime(int msecs) |
| 441 | { |
| 442 | if (priv->attackTime == msecs) |
| 443 | return; |
| 444 | priv->attackTime = msecs; |
| 445 | QFeedbackHapticsInterface::instance()->updateEffectProperty(this, QFeedbackHapticsInterface::AttackTime); |
| 446 | } |
| 447 | |
| 448 | /*! |
| 449 | \property QFeedbackHapticsEffect::attackIntensity |
| 450 | \brief the initial intensity of the effect. |
| 451 | |
| 452 | This property defines the initial intensity of the effect, before it fades in. |
| 453 | It is usually lower than \l intensity. The effect will ramp up (or down) from |
| 454 | attackIntensity() to intensity() in attackTime() milliseconds. |
| 455 | */ |
| 456 | qreal QFeedbackHapticsEffect::attackIntensity() const |
| 457 | { |
| 458 | return priv->attackIntensity; |
| 459 | } |
| 460 | void QFeedbackHapticsEffect::setAttackIntensity(qreal intensity) |
| 461 | { |
| 462 | if (priv->attackIntensity == intensity) |
| 463 | return; |
| 464 | priv->attackIntensity = intensity; |
| 465 | QFeedbackHapticsInterface::instance()->updateEffectProperty(this, QFeedbackHapticsInterface::AttackIntensity); |
| 466 | } |
| 467 | |
| 468 | /*! |
| 469 | \property QFeedbackHapticsEffect::fadeTime |
| 470 | \brief the duration of the fade-out effect. |
| 471 | |
| 472 | This property defines the duration of the fade-out effect in milliseconds. |
| 473 | The effect will ramp down (or up) from intensity() to fadeIntensity() in fadeTime() milliseconds. |
| 474 | |
| 475 | If the fade time is set to a value such that attackTime() + fadeTime() |
| 476 | is greater than duration() for non-periodic effects, or greater than |
| 477 | period() for periodic effects, the waveform which will result is |
| 478 | backend-specific. |
| 479 | |
| 480 | \sa duration(), period() |
| 481 | */ |
| 482 | int QFeedbackHapticsEffect::fadeTime() const |
| 483 | { |
| 484 | return priv->fadeTime; |
| 485 | } |
| 486 | void QFeedbackHapticsEffect::setFadeTime(int msecs) |
| 487 | { |
| 488 | if (priv->fadeTime == msecs) |
| 489 | return; |
| 490 | priv->fadeTime = msecs; |
| 491 | QFeedbackHapticsInterface::instance()->updateEffectProperty(this, QFeedbackHapticsInterface::FadeTime); |
| 492 | } |
| 493 | |
| 494 | /*! |
| 495 | \property QFeedbackHapticsEffect::fadeIntensity |
| 496 | \brief the final intensity of the effect. |
| 497 | |
| 498 | This property defines the final intensity of the effect, after it fades out. |
| 499 | It is usually lower than \l intensity. |
| 500 | The effect will ramp down (or up) from intensity() to fadeIntensity() in fadeTime() milliseconds. |
| 501 | */ |
| 502 | qreal QFeedbackHapticsEffect::fadeIntensity() const |
| 503 | { |
| 504 | return priv->fadeIntensity; |
| 505 | } |
| 506 | void QFeedbackHapticsEffect::setFadeIntensity(qreal intensity) |
| 507 | { |
| 508 | if (priv->fadeIntensity == intensity) |
| 509 | return; |
| 510 | priv->fadeIntensity = intensity; |
| 511 | QFeedbackHapticsInterface::instance()->updateEffectProperty(this, QFeedbackHapticsInterface::FadeIntensity); |
| 512 | } |
| 513 | |
| 514 | /*! |
| 515 | \property QFeedbackHapticsEffect::actuator |
| 516 | \brief the actuator on which the effect operates. |
| 517 | |
| 518 | This property defines the actuator on which the effect operates. You can only |
| 519 | change the actuator used when the effect is stopped. Setting a null actuator |
| 520 | resets the effect to use the default actuator. |
| 521 | */ |
| 522 | QFeedbackActuator* QFeedbackHapticsEffect::actuator() const |
| 523 | { |
| 524 | return priv->actuator; |
| 525 | } |
| 526 | void QFeedbackHapticsEffect::setActuator(QFeedbackActuator *actuator) |
| 527 | { |
| 528 | if (state() != Stopped) { |
| 529 | qWarning(msg: "QFeedbackHapticsEffect::setActuator: The effect is not stopped" ); |
| 530 | return; |
| 531 | } |
| 532 | |
| 533 | if (actuator) { |
| 534 | priv->actuator = actuator; |
| 535 | } else { |
| 536 | QList<QFeedbackActuator*> list = QFeedbackActuator::actuators(); |
| 537 | if (!list.isEmpty()) { |
| 538 | priv->actuator = list.first(); |
| 539 | } else { |
| 540 | priv->actuator = new QFeedbackActuator(this); |
| 541 | } |
| 542 | } |
| 543 | } |
| 544 | |
| 545 | /*! |
| 546 | \property QFeedbackHapticsEffect::period |
| 547 | \brief set the period for the effect. |
| 548 | |
| 549 | It has a default value of -1, which means that it is not a periodic effect. |
| 550 | You can only change the period when the effect is stopped. |
| 551 | The duration of the effect should be set to a value larger than the |
| 552 | period of the effect if you wish the periodicity to be discernable. |
| 553 | \note Not all actuators support periodic effects |
| 554 | |
| 555 | The period defines the total length of the periodic envelope, which will |
| 556 | be repeated up until duration() milliseconds has elapsed. For a periodic |
| 557 | effect, the intensity will start at attackIntensity(), ramp to intensity() |
| 558 | (where it stays for (period() - (attackTime() + fadeTime())) milliseconds), |
| 559 | then ramp to fadeIntensity(). This waveform will be repeated as many times |
| 560 | as required until the duration() has elapsed. |
| 561 | |
| 562 | If the period is set to a value which is less than attackTime() + fadeTime(), |
| 563 | the waveform which will result is backend-specific. |
| 564 | */ |
| 565 | int QFeedbackHapticsEffect::period() const |
| 566 | { |
| 567 | return priv->period; |
| 568 | } |
| 569 | void QFeedbackHapticsEffect::setPeriod(int msecs) |
| 570 | { |
| 571 | if (state() != Stopped) { |
| 572 | qWarning(msg: "QFeedbackHapticsEffect::setPeriod: the period can only be changed if the effect is stopped" ); |
| 573 | return; |
| 574 | } |
| 575 | priv->period = msecs; |
| 576 | } |
| 577 | |
| 578 | /*! |
| 579 | \internal |
| 580 | */ |
| 581 | void QFeedbackHapticsEffect::setState(State state) |
| 582 | { |
| 583 | State oldState = this->state(); |
| 584 | if (oldState != state) { |
| 585 | QFeedbackHapticsInterface::instance()->setEffectState(this, state); |
| 586 | emit stateChanged(); |
| 587 | } |
| 588 | } |
| 589 | |
| 590 | /*! |
| 591 | \internal |
| 592 | */ |
| 593 | QFeedbackEffect::State QFeedbackHapticsEffect::state() const |
| 594 | { |
| 595 | return QFeedbackHapticsInterface::instance()->effectState(this); |
| 596 | } |
| 597 | |
| 598 | /*! |
| 599 | \internal |
| 600 | \class QFeedbackFileEffect |
| 601 | \ingroup feedback |
| 602 | \inmodule QtFeedback |
| 603 | \brief The QFeedbackFileEffect class allows to play feedback from a file. |
| 604 | |
| 605 | Several different mime types may be supported on a system, including |
| 606 | both haptic data files, and audio files. |
| 607 | |
| 608 | The files containing haptics data are usually suffixed \c .ivt. |
| 609 | The feedback is usually varying in |
| 610 | \l{QFeedbackHapticsEffect::}{intensity()}, and is for that reason |
| 611 | often referred to as a "haptic tune". They are created, for |
| 612 | instance, from music files where the feedback is based on a |
| 613 | specific feature in the audio data. For example, you could have a |
| 614 | phone vibrating along with the bass of a rock song. |
| 615 | |
| 616 | Although Qt Feedback does not let you record \c .ivt files, it lets |
| 617 | you play them back using the QFeedbackFileEffect class. Setting |
| 618 | up a QFeedbackFileEffect and starting it is done as follows: |
| 619 | |
| 620 | \code |
| 621 | QFeedbackFileEffect hapticTune; |
| 622 | hapticTune.setSource(QUrl::fromLocalFile("mySavedRumble.ivt")); |
| 623 | hapticTune.load(); |
| 624 | hapticTune.start(); |
| 625 | \endcode |
| 626 | |
| 627 | As with other \l{QFeedbackEffect}s, QFeedbackFileEffect is at any |
| 628 | given time in one of four states: \l{QFeedbackEffect::}{Loading}, |
| 629 | \l{QFeedbackEffect::}{Running}, \l{QFeedbackEffect::}{Paused}, or |
| 630 | \l{QFeedbackEffect::}{Stopped}. You request state changes with |
| 631 | start(), pause(), and stop(). |
| 632 | |
| 633 | You can load() and unload() the file at will to free resources or |
| 634 | be as fast as possible. The file must be loaded before it can be |
| 635 | started, and it cannot be unloaded while playing. After the file is |
| 636 | loaded, you can query its duration(). Some mime types may not |
| 637 | support duration information - in these cases, 0 will be returned. |
| 638 | |
| 639 | QFeedbackFileEffect reports errors through the error() signal. |
| 640 | |
| 641 | \sa QFeedbackHapticsEffect |
| 642 | */ |
| 643 | |
| 644 | |
| 645 | /*! |
| 646 | \internal |
| 647 | */ |
| 648 | void QFeedbackFileEffectPrivate::loadFinished(bool success) |
| 649 | { |
| 650 | loaded = success; |
| 651 | if( !success) |
| 652 | backendUsed = -1; |
| 653 | } |
| 654 | |
| 655 | |
| 656 | /*! |
| 657 | \internal |
| 658 | Constructs the QFeedbackFileEffect class, and passes \a parent to |
| 659 | QObject's constructor. |
| 660 | */ |
| 661 | QFeedbackFileEffect::QFeedbackFileEffect(QObject *parent) : QFeedbackEffect(parent), priv(new QFeedbackFileEffectPrivate(this)) |
| 662 | { |
| 663 | } |
| 664 | |
| 665 | /*! |
| 666 | \internal |
| 667 | Stops the feedback and unloads the file if necessary. |
| 668 | */ |
| 669 | QFeedbackFileEffect::~QFeedbackFileEffect() |
| 670 | { |
| 671 | setLoaded(false); //ensures we unload the file and frees resources |
| 672 | } |
| 673 | |
| 674 | /*! |
| 675 | \reimp |
| 676 | */ |
| 677 | int QFeedbackFileEffect::duration() const |
| 678 | { |
| 679 | return QFeedbackFileInterface::instance()->effectDuration(this); |
| 680 | } |
| 681 | |
| 682 | /*! |
| 683 | \internal |
| 684 | \property QFeedbackFileEffect::source |
| 685 | \brief the url of the file that is loaded. |
| 686 | |
| 687 | Setting that property will automatically unload the previous file (if any) and load the new one. |
| 688 | Some backends may not support all URL schemes - for example, they may only support |
| 689 | local files. |
| 690 | |
| 691 | You can only change the source of an effect when it is stopped. |
| 692 | */ |
| 693 | QUrl QFeedbackFileEffect::source() const |
| 694 | { |
| 695 | return priv->url; |
| 696 | } |
| 697 | void QFeedbackFileEffect::setSource(const QUrl &source) |
| 698 | { |
| 699 | if (state() != QFeedbackEffect::Stopped) { |
| 700 | qWarning(msg: "QFeedbackFileEffect::setSource: can't set the file while the feedback is running" ); |
| 701 | return; |
| 702 | } |
| 703 | if (source != priv->url) { |
| 704 | setLoaded(false); |
| 705 | priv->url = source; |
| 706 | setLoaded(true); |
| 707 | } |
| 708 | } |
| 709 | |
| 710 | /*! |
| 711 | \internal |
| 712 | \property QFeedbackFileEffect::loaded |
| 713 | \brief reports if the file has been successfully loaded. |
| 714 | */ |
| 715 | bool QFeedbackFileEffect::isLoaded() const |
| 716 | { |
| 717 | return priv->loaded; |
| 718 | } |
| 719 | void QFeedbackFileEffect::setLoaded(bool load) |
| 720 | { |
| 721 | if (priv->loaded == load) |
| 722 | return; |
| 723 | |
| 724 | if (state() != QFeedbackEffect::Stopped) { |
| 725 | qWarning() << "QFeedbackFileEffect::setLoaded: can't load/unload a file while the effect is not stopped" ; |
| 726 | return; |
| 727 | } |
| 728 | |
| 729 | QFeedbackFileInterface::instance()->setLoaded(this, load); |
| 730 | } |
| 731 | |
| 732 | |
| 733 | /*! |
| 734 | \internal |
| 735 | \fn void QFeedbackFileEffect::load() |
| 736 | |
| 737 | Makes sure that the file associated with the feedback object is loaded. |
| 738 | It will be automatically loaded when the setSource() or start() functions |
| 739 | are called. |
| 740 | */ |
| 741 | void QFeedbackFileEffect::load() |
| 742 | { |
| 743 | setLoaded(true); |
| 744 | } |
| 745 | |
| 746 | /*! |
| 747 | \internal |
| 748 | \fn void QFeedbackFileEffect::unload() |
| 749 | |
| 750 | makes sure that the file associated with the feedback object is unloaded. |
| 751 | It will be automatically unloaded when the setSource function is called with |
| 752 | another file or the object is destroyed. |
| 753 | */ |
| 754 | void QFeedbackFileEffect::unload() |
| 755 | { |
| 756 | setLoaded(false); |
| 757 | } |
| 758 | |
| 759 | |
| 760 | /*! |
| 761 | \internal |
| 762 | \fn QStringList QFeedbackFileEffect::supportedMimeTypes() |
| 763 | |
| 764 | returns the MIME types supported for playing effects from file. |
| 765 | */ |
| 766 | QStringList QFeedbackFileEffect::supportedMimeTypes() |
| 767 | { |
| 768 | return QFeedbackFileInterface::instance()->supportedMimeTypes(); |
| 769 | } |
| 770 | |
| 771 | |
| 772 | /*! |
| 773 | \reimp |
| 774 | */ |
| 775 | void QFeedbackFileEffect::setState(State newState) |
| 776 | { |
| 777 | State oldState = state(); |
| 778 | if (oldState != newState) { |
| 779 | if (newState != Stopped && state() == Stopped) |
| 780 | load(); // makes sure the file is loaded |
| 781 | QFeedbackFileInterface::instance()->setEffectState(this, newState); |
| 782 | emit stateChanged(); |
| 783 | } |
| 784 | } |
| 785 | |
| 786 | /*! |
| 787 | \reimp |
| 788 | */ |
| 789 | QFeedbackEffect::State QFeedbackFileEffect::state() const |
| 790 | { |
| 791 | return QFeedbackFileInterface::instance()->effectState(this); |
| 792 | } |
| 793 | |
| 794 | QT_END_NAMESPACE |
| 795 | |