| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ | 
| 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 https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General | 
| 28 | ** Public license version 3 or any later version approved by the KDE Free | 
| 29 | ** Qt Foundation. The licenses are as published by the Free Software | 
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
| 31 | ** included in the packaging of this file. Please review the following | 
| 32 | ** information to ensure the GNU General Public License requirements will | 
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
| 35 | ** | 
| 36 | ** $QT_END_LICENSE$ | 
| 37 | ** | 
| 38 | ****************************************************************************/ | 
| 39 |  | 
| 40 | #include "qaudiobuffer.h" | 
| 41 | #include "qaudiobuffer_p.h" | 
| 42 |  | 
| 43 | #include <QObject> | 
| 44 | #include <QDebug> | 
| 45 |  | 
| 46 | QT_BEGIN_NAMESPACE | 
| 47 |  | 
| 48 |  | 
| 49 | static void qRegisterAudioBufferMetaTypes() | 
| 50 | { | 
| 51 |     qRegisterMetaType<QAudioBuffer>(); | 
| 52 | } | 
| 53 |  | 
| 54 | Q_CONSTRUCTOR_FUNCTION(qRegisterAudioBufferMetaTypes) | 
| 55 |  | 
| 56 |  | 
| 57 | class QAudioBufferPrivate : public QSharedData | 
| 58 | { | 
| 59 | public: | 
| 60 |     QAudioBufferPrivate(QAbstractAudioBuffer *provider) | 
| 61 |         : mProvider(provider) | 
| 62 |         , mCount(1) | 
| 63 |     { | 
| 64 |     } | 
| 65 |  | 
| 66 |     ~QAudioBufferPrivate() | 
| 67 |     { | 
| 68 |         if (mProvider) | 
| 69 |             mProvider->release(); | 
| 70 |     } | 
| 71 |  | 
| 72 |     void ref() | 
| 73 |     { | 
| 74 |         mCount.ref(); | 
| 75 |     } | 
| 76 |  | 
| 77 |     void deref() | 
| 78 |     { | 
| 79 |         if (!mCount.deref()) | 
| 80 |             delete this; | 
| 81 |     } | 
| 82 |  | 
| 83 |     QAudioBufferPrivate *clone(); | 
| 84 |  | 
| 85 |     static QAudioBufferPrivate *acquire(QAudioBufferPrivate *other) | 
| 86 |     { | 
| 87 |         if (!other) | 
| 88 |             return nullptr; | 
| 89 |  | 
| 90 |         // Ref the other (if there are extant data() pointers, they will | 
| 91 |         // also point here - it's a feature, not a bug, like QByteArray) | 
| 92 |         other->ref(); | 
| 93 |         return other; | 
| 94 |     } | 
| 95 |  | 
| 96 |     QAbstractAudioBuffer *mProvider; | 
| 97 |     QAtomicInt mCount; | 
| 98 | }; | 
| 99 |  | 
| 100 | // Private class to go in .cpp file | 
| 101 | class QMemoryAudioBufferProvider : public QAbstractAudioBuffer { | 
| 102 | public: | 
| 103 |     QMemoryAudioBufferProvider(const void *data, int frameCount, const QAudioFormat &format, qint64 startTime) | 
| 104 |         : mStartTime(startTime) | 
| 105 |         , mFrameCount(frameCount) | 
| 106 |         , mFormat(format) | 
| 107 |     { | 
| 108 |         int numBytes = format.bytesForFrames(frameCount); | 
| 109 |         if (numBytes > 0) { | 
| 110 |             mBuffer = malloc(size: numBytes); | 
| 111 |             if (!mBuffer) { | 
| 112 |                 // OOM, if that's likely | 
| 113 |                 mStartTime = -1; | 
| 114 |                 mFrameCount = 0; | 
| 115 |                 mFormat = QAudioFormat(); | 
| 116 |             } else { | 
| 117 |                 // Allocated, see if we have data to copy | 
| 118 |                 if (data) { | 
| 119 |                     memcpy(dest: mBuffer, src: data, n: numBytes); | 
| 120 |                 } else { | 
| 121 |                     // We have to fill with the zero value.. | 
| 122 |                     switch (format.sampleType()) { | 
| 123 |                         case QAudioFormat::SignedInt: | 
| 124 |                             // Signed int means 0x80, 0x8000 is zero | 
| 125 |                             // XXX this is not right for > 8 bits(0x8080 vs 0x8000) | 
| 126 |                             memset(s: mBuffer, c: 0x80, n: numBytes); | 
| 127 |                             break; | 
| 128 |                         default: | 
| 129 |                             memset(s: mBuffer, c: 0x0, n: numBytes); | 
| 130 |                     } | 
| 131 |                 } | 
| 132 |             } | 
| 133 |         } else | 
| 134 |             mBuffer = nullptr; | 
| 135 |     } | 
| 136 |  | 
| 137 |     ~QMemoryAudioBufferProvider() | 
| 138 |     { | 
| 139 |         if (mBuffer) | 
| 140 |             free(ptr: mBuffer); | 
| 141 |     } | 
| 142 |  | 
| 143 |     void release() override {delete this;} | 
| 144 |     QAudioFormat format() const override {return mFormat;} | 
| 145 |     qint64 startTime() const override {return mStartTime;} | 
| 146 |     int frameCount() const override {return mFrameCount;} | 
| 147 |  | 
| 148 |     void *constData() const override {return mBuffer;} | 
| 149 |  | 
| 150 |     void *writableData() override {return mBuffer;} | 
| 151 |     QAbstractAudioBuffer *clone() const override | 
| 152 |     { | 
| 153 |         return new QMemoryAudioBufferProvider(mBuffer, mFrameCount, mFormat, mStartTime); | 
| 154 |     } | 
| 155 |  | 
| 156 |     void *mBuffer; | 
| 157 |     qint64 mStartTime; | 
| 158 |     int mFrameCount; | 
| 159 |     QAudioFormat mFormat; | 
| 160 | }; | 
| 161 |  | 
| 162 | QAudioBufferPrivate *QAudioBufferPrivate::clone() | 
| 163 | { | 
| 164 |     // We want to create a single bufferprivate with a | 
| 165 |     // single qaab | 
| 166 |     // This should only be called when the count is > 1 | 
| 167 |     Q_ASSERT(mCount.loadRelaxed() > 1); | 
| 168 |  | 
| 169 |     if (mProvider) { | 
| 170 |         QAbstractAudioBuffer *abuf = mProvider->clone(); | 
| 171 |  | 
| 172 |         if (!abuf) { | 
| 173 |             abuf = new QMemoryAudioBufferProvider(mProvider->constData(), mProvider->frameCount(), mProvider->format(), mProvider->startTime()); | 
| 174 |         } | 
| 175 |  | 
| 176 |         if (abuf) { | 
| 177 |             return new QAudioBufferPrivate(abuf); | 
| 178 |         } | 
| 179 |     } | 
| 180 |  | 
| 181 |     return nullptr; | 
| 182 | } | 
| 183 |  | 
| 184 | /*! | 
| 185 |     \class QAbstractAudioBuffer | 
| 186 |     \internal | 
| 187 | */ | 
| 188 |  | 
| 189 | /*! | 
| 190 |     \class QAudioBuffer | 
| 191 |     \inmodule QtMultimedia | 
| 192 |     \ingroup multimedia | 
| 193 |     \ingroup multimedia_audio | 
| 194 |     \brief The QAudioBuffer class represents a collection of audio samples with a specific format and sample rate. | 
| 195 | */ | 
| 196 | // ^ Mostly useful with probe or decoder | 
| 197 |  | 
| 198 | /*! | 
| 199 |     Create a new, empty, invalid buffer. | 
| 200 |  */ | 
| 201 | QAudioBuffer::QAudioBuffer() | 
| 202 |     : d(nullptr) | 
| 203 | { | 
| 204 | } | 
| 205 |  | 
| 206 | /*! | 
| 207 |     \internal | 
| 208 |     Create a new audio buffer from the supplied \a provider.  This | 
| 209 |     constructor is typically only used when handling certain hardware | 
| 210 |     or media framework specific buffers, and generally isn't useful | 
| 211 |     in application code. | 
| 212 |  */ | 
| 213 | QAudioBuffer::QAudioBuffer(QAbstractAudioBuffer *provider) | 
| 214 |     : d(new QAudioBufferPrivate(provider)) | 
| 215 | { | 
| 216 | } | 
| 217 | /*! | 
| 218 |     Creates a new audio buffer from \a other.  Generally | 
| 219 |     this will have copy-on-write semantics - a copy will | 
| 220 |     only be made when it has to be. | 
| 221 |  */ | 
| 222 | QAudioBuffer::QAudioBuffer(const QAudioBuffer &other) | 
| 223 | { | 
| 224 |     d = QAudioBufferPrivate::acquire(other: other.d); | 
| 225 | } | 
| 226 |  | 
| 227 | /*! | 
| 228 |     Creates a new audio buffer from the supplied \a data, in the | 
| 229 |     given \a format.  The format will determine how the number | 
| 230 |     and sizes of the samples are interpreted from the \a data. | 
| 231 |  | 
| 232 |     If the supplied \a data is not an integer multiple of the | 
| 233 |     calculated frame size, the excess data will not be used. | 
| 234 |  | 
| 235 |     This audio buffer will copy the contents of \a data. | 
| 236 |  | 
| 237 |     \a startTime (in microseconds) indicates when this buffer | 
| 238 |     starts in the stream. | 
| 239 |     If this buffer is not part of a stream, set it to -1. | 
| 240 |  */ | 
| 241 | QAudioBuffer::QAudioBuffer(const QByteArray &data, const QAudioFormat &format, qint64 startTime) | 
| 242 | { | 
| 243 |     if (format.isValid()) { | 
| 244 |         int frameCount = format.framesForBytes(byteCount: data.size()); | 
| 245 |         d = new QAudioBufferPrivate(new QMemoryAudioBufferProvider(data.constData(), frameCount, format, startTime)); | 
| 246 |     } else | 
| 247 |         d = nullptr; | 
| 248 | } | 
| 249 |  | 
| 250 | /*! | 
| 251 |     Creates a new audio buffer with space for \a numFrames frames of | 
| 252 |     the given \a format.  The individual samples will be initialized | 
| 253 |     to the default for the format. | 
| 254 |  | 
| 255 |     \a startTime (in microseconds) indicates when this buffer | 
| 256 |     starts in the stream. | 
| 257 |     If this buffer is not part of a stream, set it to -1. | 
| 258 |  */ | 
| 259 | QAudioBuffer::QAudioBuffer(int numFrames, const QAudioFormat &format, qint64 startTime) | 
| 260 | { | 
| 261 |     if (format.isValid()) | 
| 262 |         d = new QAudioBufferPrivate(new QMemoryAudioBufferProvider(nullptr, numFrames, format, startTime)); | 
| 263 |     else | 
| 264 |         d = nullptr; | 
| 265 | } | 
| 266 |  | 
| 267 | /*! | 
| 268 |     Assigns the \a other buffer to this. | 
| 269 |  */ | 
| 270 | QAudioBuffer &QAudioBuffer::operator =(const QAudioBuffer &other) | 
| 271 | { | 
| 272 |     if (this->d != other.d) { | 
| 273 |         if (d) | 
| 274 |             d->deref(); | 
| 275 |         d = QAudioBufferPrivate::acquire(other: other.d); | 
| 276 |     } | 
| 277 |     return *this; | 
| 278 | } | 
| 279 |  | 
| 280 | /*! | 
| 281 |     Destroys this audio buffer. | 
| 282 |  */ | 
| 283 | QAudioBuffer::~QAudioBuffer() | 
| 284 | { | 
| 285 |     if (d) | 
| 286 |         d->deref(); | 
| 287 | } | 
| 288 |  | 
| 289 | /*! | 
| 290 |     Returns true if this is a valid buffer.  A valid buffer | 
| 291 |     has more than zero frames in it and a valid format. | 
| 292 |  */ | 
| 293 | bool QAudioBuffer::isValid() const | 
| 294 | { | 
| 295 |     if (!d || !d->mProvider) | 
| 296 |         return false; | 
| 297 |     return d->mProvider->format().isValid() && (d->mProvider->frameCount() > 0); | 
| 298 | } | 
| 299 |  | 
| 300 | /*! | 
| 301 |     Returns the \l {QAudioFormat}{format} of this buffer. | 
| 302 |  | 
| 303 |     Several properties of this format influence how | 
| 304 |     the \l duration() or \l byteCount() are calculated | 
| 305 |     from the \l frameCount(). | 
| 306 |  */ | 
| 307 | QAudioFormat QAudioBuffer::format() const | 
| 308 | { | 
| 309 |     if (!isValid()) | 
| 310 |         return QAudioFormat(); | 
| 311 |     return d->mProvider->format(); | 
| 312 | } | 
| 313 |  | 
| 314 | /*! | 
| 315 |     Returns the number of complete audio frames in this buffer. | 
| 316 |  | 
| 317 |     An audio frame is an interleaved set of one sample per channel | 
| 318 |     for the same instant in time. | 
| 319 | */ | 
| 320 | int QAudioBuffer::frameCount() const | 
| 321 | { | 
| 322 |     if (!isValid()) | 
| 323 |         return 0; | 
| 324 |     return d->mProvider->frameCount(); | 
| 325 | } | 
| 326 |  | 
| 327 | /*! | 
| 328 |     Returns the number of samples in this buffer. | 
| 329 |  | 
| 330 |     If the format of this buffer has multiple channels, | 
| 331 |     then this count includes all channels.  This means | 
| 332 |     that a stereo buffer with 1000 samples in total will | 
| 333 |     have 500 left samples and 500 right samples (interleaved), | 
| 334 |     and this function will return 1000. | 
| 335 |  | 
| 336 |     \sa frameCount() | 
| 337 | */ | 
| 338 | int QAudioBuffer::sampleCount() const | 
| 339 | { | 
| 340 |     if (!isValid()) | 
| 341 |         return 0; | 
| 342 |  | 
| 343 |     return frameCount() * format().channelCount(); | 
| 344 | } | 
| 345 |  | 
| 346 | /*! | 
| 347 |     Returns the size of this buffer, in bytes. | 
| 348 |  */ | 
| 349 | int QAudioBuffer::byteCount() const | 
| 350 | { | 
| 351 |     const QAudioFormat f(format()); | 
| 352 |     return format().bytesForFrames(frameCount: frameCount()); | 
| 353 | } | 
| 354 |  | 
| 355 | /*! | 
| 356 |     Returns the duration of audio in this buffer, in microseconds. | 
| 357 |  | 
| 358 |     This depends on the \l format(), and the \l frameCount(). | 
| 359 | */ | 
| 360 | qint64 QAudioBuffer::duration() const | 
| 361 | { | 
| 362 |     return format().durationForFrames(frameCount: frameCount()); | 
| 363 | } | 
| 364 |  | 
| 365 | /*! | 
| 366 |     Returns the time in a stream that this buffer starts at (in microseconds). | 
| 367 |  | 
| 368 |     If this buffer is not part of a stream, this will return -1. | 
| 369 |  */ | 
| 370 | qint64 QAudioBuffer::startTime() const | 
| 371 | { | 
| 372 |     if (!isValid()) | 
| 373 |         return -1; | 
| 374 |     return d->mProvider->startTime(); | 
| 375 | } | 
| 376 |  | 
| 377 | /*! | 
| 378 |     Returns a pointer to this buffer's data.  You can only read it. | 
| 379 |  | 
| 380 |     This method is preferred over the const version of \l data() to | 
| 381 |     prevent unnecessary copying. | 
| 382 |  | 
| 383 |     There is also a templatized version of this constData() function that | 
| 384 |     allows you to retrieve a specific type of read-only pointer to | 
| 385 |     the data.  Note that there is no checking done on the format of | 
| 386 |     the audio buffer - this is simply a convenience function. | 
| 387 |  | 
| 388 |     \code | 
| 389 |     // With a 16bit sample buffer: | 
| 390 |     const quint16 *data = buffer->constData<quint16>(); | 
| 391 |     \endcode | 
| 392 |  | 
| 393 | */ | 
| 394 | const void* QAudioBuffer::constData() const | 
| 395 | { | 
| 396 |     if (!isValid()) | 
| 397 |         return nullptr; | 
| 398 |     return d->mProvider->constData(); | 
| 399 | } | 
| 400 |  | 
| 401 | /*! | 
| 402 |     Returns a pointer to this buffer's data.  You can only read it. | 
| 403 |  | 
| 404 |     You should use the \l constData() function rather than this | 
| 405 |     to prevent accidental deep copying. | 
| 406 |  | 
| 407 |     There is also a templatized version of this data() function that | 
| 408 |     allows you to retrieve a specific type of read-only pointer to | 
| 409 |     the data.  Note that there is no checking done on the format of | 
| 410 |     the audio buffer - this is simply a convenience function. | 
| 411 |  | 
| 412 |     \code | 
| 413 |     // With a 16bit sample const buffer: | 
| 414 |     const quint16 *data = buffer->data<quint16>(); | 
| 415 |     \endcode | 
| 416 | */ | 
| 417 | const void* QAudioBuffer::data() const | 
| 418 | { | 
| 419 |     if (!isValid()) | 
| 420 |         return nullptr; | 
| 421 |     return d->mProvider->constData(); | 
| 422 | } | 
| 423 |  | 
| 424 |  | 
| 425 | /* | 
| 426 |     Template data/constData functions caused override problems with qdoc, | 
| 427 |     so moved their docs into the non template versions. | 
| 428 | */ | 
| 429 |  | 
| 430 | /*! | 
| 431 |     Returns a pointer to this buffer's data.  You can modify the | 
| 432 |     data through the returned pointer. | 
| 433 |  | 
| 434 |     Since QAudioBuffers can share the actual sample data, calling | 
| 435 |     this function will result in a deep copy being made if there | 
| 436 |     are any other buffers using the sample.  You should avoid calling | 
| 437 |     this unless you really need to modify the data. | 
| 438 |  | 
| 439 |     This pointer will remain valid until the underlying storage is | 
| 440 |     detached.  In particular, if you obtain a pointer, and then | 
| 441 |     copy this audio buffer, changing data through this pointer may | 
| 442 |     change both buffer instances.  Calling \l data() on either instance | 
| 443 |     will again cause a deep copy to be made, which may invalidate | 
| 444 |     the pointers returned from this function previously. | 
| 445 |  | 
| 446 |     There is also a templatized version of data() allows you to retrieve | 
| 447 |     a specific type of pointer to the data.  Note that there is no | 
| 448 |     checking done on the format of the audio buffer - this is | 
| 449 |     simply a convenience function. | 
| 450 |  | 
| 451 |     \code | 
| 452 |     // With a 16bit sample buffer: | 
| 453 |     quint16 *data = buffer->data<quint16>(); // May cause deep copy | 
| 454 |     \endcode | 
| 455 | */ | 
| 456 | void *QAudioBuffer::data() | 
| 457 | { | 
| 458 |     if (!isValid()) | 
| 459 |         return nullptr; | 
| 460 |  | 
| 461 |     if (d->mCount.loadRelaxed() != 1) { | 
| 462 |         // Can't share a writable buffer | 
| 463 |         // so we need to detach | 
| 464 |         QAudioBufferPrivate *newd = d->clone(); | 
| 465 |  | 
| 466 |         // This shouldn't happen | 
| 467 |         if (!newd) | 
| 468 |             return nullptr; | 
| 469 |  | 
| 470 |         d->deref(); | 
| 471 |         d = newd; | 
| 472 |     } | 
| 473 |  | 
| 474 |     // We're (now) the only user of this qaab, so | 
| 475 |     // see if it's writable directly | 
| 476 |     void *buffer = d->mProvider->writableData(); | 
| 477 |     if (buffer) { | 
| 478 |         return buffer; | 
| 479 |     } | 
| 480 |  | 
| 481 |     // Wasn't writable, so turn it into a memory provider | 
| 482 |     QAbstractAudioBuffer *memBuffer = new QMemoryAudioBufferProvider(constData(), frameCount(), format(), startTime()); | 
| 483 |  | 
| 484 |     if (memBuffer) { | 
| 485 |         d->mProvider->release(); | 
| 486 |         d->mCount.storeRelaxed(newValue: 1); | 
| 487 |         d->mProvider = memBuffer; | 
| 488 |  | 
| 489 |         return memBuffer->writableData(); | 
| 490 |     } | 
| 491 |  | 
| 492 |     return nullptr; | 
| 493 | } | 
| 494 |  | 
| 495 | // Template helper classes worth documenting | 
| 496 |  | 
| 497 | /*! | 
| 498 |     \class QAudioBuffer::StereoFrameDefault | 
| 499 |     \internal | 
| 500 |  | 
| 501 |     Just a trait class for the default value. | 
| 502 | */ | 
| 503 |  | 
| 504 | /*! | 
| 505 |     \class QAudioBuffer::StereoFrame | 
| 506 |     \brief The StereoFrame class provides a simple wrapper for a stereo audio frame. | 
| 507 |     \inmodule QtMultimedia | 
| 508 |     \ingroup multimedia | 
| 509 |     \ingroup multimedia_audio | 
| 510 |  | 
| 511 |     This templatized structure lets you treat a block of individual samples as an | 
| 512 |     interleaved stereo stream frame.  This is most useful when used with the templatized | 
| 513 |     \l {QAudioBuffer::data()}{data()} functions of QAudioBuffer.  Generally the data | 
| 514 |     is accessed as a pointer, so no copying should occur. | 
| 515 |  | 
| 516 |     There are some predefined instantiations of this template for working with common | 
| 517 |     stereo sample depths in a convenient way. | 
| 518 |  | 
| 519 |     This frame structure has \e left and \e right members for accessing individual channel data. | 
| 520 |  | 
| 521 |     For example: | 
| 522 |     \code | 
| 523 |     // Assuming 'buffer' is an unsigned 16 bit stereo buffer.. | 
| 524 |     QAudioBuffer::S16U *frames = buffer->data<QAudioBuffer::S16U>(); | 
| 525 |     for (int i=0; i < buffer->frameCount(); i++) { | 
| 526 |         qSwap(frames[i].left, frames[i].right); | 
| 527 |     } | 
| 528 |     \endcode | 
| 529 |  | 
| 530 |     \sa QAudioBuffer::S8U, QAudioBuffer::S8S, QAudioBuffer::S16S, QAudioBuffer::S16U, QAudioBuffer::S32F | 
| 531 | */ | 
| 532 |  | 
| 533 | /*! | 
| 534 |     \fn template <typename T> QAudioBuffer::StereoFrame<T>::StereoFrame() | 
| 535 |  | 
| 536 |     Constructs a new frame with the "silent" value for this | 
| 537 |     sample format (0 for signed formats and floats, 0x8* for unsigned formats). | 
| 538 | */ | 
| 539 |  | 
| 540 | /*! | 
| 541 |     \fn template <typename T> QAudioBuffer::StereoFrame<T>::StereoFrame(T leftSample, T rightSample) | 
| 542 |  | 
| 543 |     Constructs a new frame with the supplied \a leftSample and \a rightSample values. | 
| 544 | */ | 
| 545 |  | 
| 546 | /*! | 
| 547 |     \fn template <typename T> QAudioBuffer::StereoFrame<T>::operator=(const StereoFrame &other) | 
| 548 |  | 
| 549 |     Assigns \a other to this frame. | 
| 550 |  */ | 
| 551 |  | 
| 552 |  | 
| 553 | /*! | 
| 554 |     \fn template <typename T> QAudioBuffer::StereoFrame<T>::average() const | 
| 555 |  | 
| 556 |     Returns the arithmetic average of the left and right samples. | 
| 557 |  */ | 
| 558 |  | 
| 559 | /*! \fn template <typename T> QAudioBuffer::StereoFrame<T>::clear() | 
| 560 |  | 
| 561 |     Sets the values of this frame to the "silent" value. | 
| 562 | */ | 
| 563 |  | 
| 564 | /*! | 
| 565 |     \variable QAudioBuffer::StereoFrame::left | 
| 566 |     \brief the left sample | 
| 567 | */ | 
| 568 |  | 
| 569 | /*! | 
| 570 |     \variable QAudioBuffer::StereoFrame::right | 
| 571 |     \brief the right sample | 
| 572 | */ | 
| 573 |  | 
| 574 | /*! | 
| 575 |     \typedef QAudioBuffer::S8U | 
| 576 |  | 
| 577 |     This is a predefined specialization for an unsigned stereo 8 bit sample.  Each | 
| 578 |     channel is an \e {unsigned char}. | 
| 579 | */ | 
| 580 | /*! | 
| 581 |     \typedef QAudioBuffer::S8S | 
| 582 |  | 
| 583 |     This is a predefined specialization for a signed stereo 8 bit sample.  Each | 
| 584 |     channel is a \e {signed char}. | 
| 585 | */ | 
| 586 | /*! | 
| 587 |     \typedef QAudioBuffer::S16U | 
| 588 |  | 
| 589 |     This is a predefined specialization for an unsigned stereo 16 bit sample.  Each | 
| 590 |     channel is an \e {unsigned short}. | 
| 591 | */ | 
| 592 | /*! | 
| 593 |     \typedef QAudioBuffer::S16S | 
| 594 |  | 
| 595 |     This is a predefined specialization for a signed stereo 16 bit sample.  Each | 
| 596 |     channel is a \e {signed short}. | 
| 597 | */ | 
| 598 | /*! | 
| 599 |     \typedef QAudioBuffer::S32F | 
| 600 |  | 
| 601 |     This is a predefined specialization for an 32 bit float sample.  Each | 
| 602 |     channel is a \e float. | 
| 603 | */ | 
| 604 |  | 
| 605 | QT_END_NAMESPACE | 
| 606 |  |