/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtDeclarative module 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 Nokia Corporation and its Subsidiary(-ies) 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 "voicegenerator.h" const int BufferSizeMilliseconds = 100; VoiceGenerator::VoiceGenerator(const QAudioFormat &format, qreal frequency, qreal amplitude, QObject *parent) : QIODevice(parent), m_format(format), m_amplitude(0.5) { Q_ASSERT(m_format.sampleSize() % 8 == 0); int sampleBytes = m_format.channels() * (m_format.sampleSize() / 8); // + 1 to round up, just to be sure that all samples fit. qint64 samplesInBuffer = m_format.sampleRate() * BufferSizeMilliseconds / 1000 + 1; qint64 length = samplesInBuffer * sampleBytes; m_buffer.resize(length); m_max_position = 0; m_position = 0; m_amplitude = amplitude; setFrequency(frequency); } VoiceGenerator::~VoiceGenerator() { } /** * Opens the parent QIODevice. */ void VoiceGenerator::start() { open(QIODevice::ReadOnly); } /** * Closes the parent QIODevice. Resets the m_position to zero. */ void VoiceGenerator::stop() { close(); m_position = 0; } /** * Sets the frequency to new frequency. */ void VoiceGenerator::setFrequency(qreal frequency) { Q_ASSERT(1 / frequency < BufferSizeMilliseconds); this->m_frequency = frequency; refreshData(); } /** * Sets the amplitude for the voice. */ void VoiceGenerator::setAmplitude(qreal amplitude) { Q_ASSERT(amplitude >= 0); m_amplitude = amplitude; refreshData(); } /** * Returns the current frequency. */ qreal VoiceGenerator::frequency() { return m_frequency; } /** * Generates voice data corresponding a sine voice with target frequency. * The number of data generated is calculated * and stored to m_max_position. */ void VoiceGenerator::refreshData() { const int channelBytes = m_format.sampleSize() / 8; const int sampleSize = m_format.channels() * channelBytes; const qint64 voiceOscillationsInBuffer = BufferSizeMilliseconds * m_frequency / 1000; const qint64 voiceSamplesInBuffer = voiceOscillationsInBuffer * m_format.sampleRate() / m_frequency; m_max_position = voiceSamplesInBuffer * sampleSize; qint64 dataGenerationLength = m_buffer.size(); Q_ASSERT(m_max_position % (sampleSize) == 0); Q_ASSERT(dataGenerationLength <= m_buffer.size()); short *t = (short*)m_buffer.data(); /* int te ; static float fpos = 0.0f; //dataGenerationLength>>=1; // in words for (int f=0; f(m_buffer.data()); int sampleIndex = 0; while (dataGenerationLength > 0) { qreal realValue = 0; if (sampleIndex < voiceSamplesInBuffer) { realValue = m_amplitude *qSin(2.0f * M_PI * m_frequency * qreal(sampleIndex % m_format.sampleRate()) / m_format.sampleRate()); } for (int i=0; i( qRound((1.0 + realValue) / 2 * M_MAX_AMPLITUDE_8BIT_UNSIGNED)); } else if (m_format.sampleType() == QAudioFormat::SignedInt) { value = static_cast( qRound(realValue * M_MAX_AMPLITUDE_8BIT_SIGNED)); } *reinterpret_cast(ptr) = value; } else if (m_format.sampleSize() == 16) { quint16 value = 0; if (m_format.sampleType() == QAudioFormat::UnSignedInt) { value = static_cast( qRound((1.0 + realValue) / 2 * M_MAX_AMPLITUDE_16BIT_UNSIGNED)); } else if (m_format.sampleType() == QAudioFormat::SignedInt) { value = static_cast( qRound(realValue * M_MAX_AMPLITUDE_16BIT_SIGNED)); } if (m_format.byteOrder() == QAudioFormat::LittleEndian) qToLittleEndian(value, ptr); else qToBigEndian(value, ptr); } } qint64 VoiceGenerator::bytesAvailable() const { return m_max_position + QIODevice::bytesAvailable(); } /** * Called by the QIODevice. Puts maxlen amount of voice * samples into the data array. */ qint64 VoiceGenerator::readData(char *data, qint64 maxlen) { qint64 total = 0; qint64 chunk = 0; while (total < maxlen) { if (maxlen - total >= m_max_position - m_position) { // the needed buffer is longer than the currently // available buffer from m_position to the m_max_position chunk = m_max_position - m_position; memcpy(data, m_buffer.constData() + m_position, chunk); m_position = 0; } else { // we can copy the needed data directly, and the loop will end chunk = maxlen - total; memcpy(data, m_buffer.constData() + m_position, chunk); m_position = (m_position + chunk) % m_max_position; } data += chunk; total += chunk; } return total; } /** * Empty implementation for writeData, since no data is provided * for the VoiceGenerator class. */ qint64 VoiceGenerator::writeData(const char *data, qint64 maxlen) { Q_UNUSED(data); Q_UNUSED(maxlen); return 0; }