1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
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
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.
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."
39 ****************************************************************************/
41 #include "voicegenerator.h"
43 const int BufferSizeMilliseconds = 100;
45 VoiceGenerator::VoiceGenerator(const QAudioFormat &format,
46 qreal frequency, qreal amplitude,
52 Q_ASSERT(m_format.sampleSize() % 8 == 0);
53 int sampleBytes = m_format.channels() * (m_format.sampleSize() / 8);
54 // + 1 to round up, just to be sure that all samples fit.
55 qint64 samplesInBuffer = m_format.sampleRate()
56 * BufferSizeMilliseconds / 1000 + 1;
57 qint64 length = samplesInBuffer * sampleBytes;
58 m_buffer.resize(length);
61 m_amplitude = amplitude;
62 setFrequency(frequency);
65 VoiceGenerator::~VoiceGenerator()
70 * Opens the parent QIODevice.
72 void VoiceGenerator::start()
74 open(QIODevice::ReadOnly);
78 * Closes the parent QIODevice. Resets the m_position to zero.
80 void VoiceGenerator::stop()
87 * Sets the frequency to new frequency.
89 void VoiceGenerator::setFrequency(qreal frequency)
91 Q_ASSERT(1 / frequency < BufferSizeMilliseconds);
92 this->m_frequency = frequency;
97 * Sets the amplitude for the voice.
99 void VoiceGenerator::setAmplitude(qreal amplitude)
101 Q_ASSERT(amplitude >= 0);
102 m_amplitude = amplitude;
107 * Returns the current frequency.
109 qreal VoiceGenerator::frequency()
115 * Generates voice data corresponding a sine voice with target frequency.
116 * The number of data generated is calculated
117 * and stored to m_max_position.
119 void VoiceGenerator::refreshData()
121 const int channelBytes = m_format.sampleSize() / 8;
122 const int sampleSize = m_format.channels() * channelBytes;
123 const qint64 voiceOscillationsInBuffer = BufferSizeMilliseconds
124 * m_frequency / 1000;
125 const qint64 voiceSamplesInBuffer = voiceOscillationsInBuffer
126 * m_format.sampleRate() / m_frequency;
127 m_max_position = voiceSamplesInBuffer * sampleSize;
128 qint64 dataGenerationLength = m_buffer.size();
131 Q_ASSERT(m_max_position % (sampleSize) == 0);
132 Q_ASSERT(dataGenerationLength <= m_buffer.size());
134 short *t = (short*)m_buffer.data();
139 static float fpos = 0.0f;
140 //dataGenerationLength>>=1; // in words
141 for (int f=0; f<dataGenerationLength; f++) {
142 te = (short)((sinf(fpos))* (65536.0f/2.0f));
143 fpos += m_frequency/2000.0f;
147 m_amplitude = 1.0f; */
148 uchar *ptr = reinterpret_cast<uchar *>(m_buffer.data());
150 while (dataGenerationLength > 0) {
152 if (sampleIndex < voiceSamplesInBuffer) {
153 realValue = m_amplitude
154 *qSin(2.0f * M_PI * m_frequency
155 * qreal(sampleIndex % m_format.sampleRate())
156 / m_format.sampleRate());
158 for (int i=0; i<m_format.channels(); ++i) {
159 setValue(ptr, realValue);
161 dataGenerationLength -= channelBytes;
168 * Stores the realValue into bytes pointed by ptr as an int value.
171 void VoiceGenerator::setValue(uchar *ptr, qreal realValue) {
172 if (m_format.sampleSize() == 8)
175 if (m_format.sampleType() == QAudioFormat::UnSignedInt) {
176 value = static_cast<quint8>(
177 qRound((1.0 + realValue) / 2
178 * M_MAX_AMPLITUDE_8BIT_UNSIGNED));
179 } else if (m_format.sampleType() == QAudioFormat::SignedInt) {
180 value = static_cast<qint8>(
182 * M_MAX_AMPLITUDE_8BIT_SIGNED));
184 *reinterpret_cast<quint8*>(ptr) = value;
185 } else if (m_format.sampleSize() == 16) {
187 if (m_format.sampleType() == QAudioFormat::UnSignedInt) {
188 value = static_cast<quint16>(
189 qRound((1.0 + realValue) / 2
190 * M_MAX_AMPLITUDE_16BIT_UNSIGNED));
191 } else if (m_format.sampleType() == QAudioFormat::SignedInt) {
192 value = static_cast<qint16>(
194 * M_MAX_AMPLITUDE_16BIT_SIGNED));
196 if (m_format.byteOrder() == QAudioFormat::LittleEndian)
197 qToLittleEndian<qint16>(value, ptr);
199 qToBigEndian<qint16>(value, ptr);
203 qint64 VoiceGenerator::bytesAvailable() const
205 return m_max_position + QIODevice::bytesAvailable();
209 * Called by the QIODevice. Puts maxlen amount of voice
210 * samples into the data array.
212 qint64 VoiceGenerator::readData(char *data, qint64 maxlen)
216 while (total < maxlen) {
217 if (maxlen - total >= m_max_position - m_position) {
218 // the needed buffer is longer than the currently
219 // available buffer from m_position to the m_max_position
220 chunk = m_max_position - m_position;
221 memcpy(data, m_buffer.constData() + m_position, chunk);
225 // we can copy the needed data directly, and the loop will end
226 chunk = maxlen - total;
227 memcpy(data, m_buffer.constData() + m_position, chunk);
228 m_position = (m_position + chunk) % m_max_position;
237 * Empty implementation for writeData, since no data is provided
238 * for the VoiceGenerator class.
240 qint64 VoiceGenerator::writeData(const char *data, qint64 maxlen)