diff --git a/src/blacksound/soundgenerator.cpp b/src/blacksound/soundgenerator.cpp index bc9d51b08..222d9a5d8 100644 --- a/src/blacksound/soundgenerator.cpp +++ b/src/blacksound/soundgenerator.cpp @@ -63,22 +63,31 @@ namespace BlackSound while (lengthPerTone) { - const qreal x = qSin(2 * M_PI * t.m_frequencyHz * qreal(sampleIndexPerTone % format.sampleRate()) / format.sampleRate()); + // http://hyperphysics.phy-astr.gsu.edu/hbase/audio/sumdif.html + // http://math.stackexchange.com/questions/164369/how-do-you-calculate-the-frequency-perceived-by-humans-of-two-sinusoidal-waves-a + const double pseudoTime = double(sampleIndexPerTone % format.sampleRate()) / format.sampleRate(); + const double amplitude = t.m_secondaryFrequencyHz == 0 ? + qSin(2 * M_PI * t.m_frequencyHz * pseudoTime) : + qSin(M_PI * (t.m_frequencyHz + t.m_secondaryFrequencyHz) * pseudoTime) * + qCos(M_PI * (t.m_frequencyHz - t.m_secondaryFrequencyHz) * pseudoTime); + // the combination of two frequencies actually would have 2*amplitude, + // but I have to normalize with amplitude -1 -> +1 + for (int i = 0; i < format.channelCount(); ++i) { if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::UnSignedInt) { - const quint8 value = static_cast((1.0 + x) / 2 * 255); + const quint8 value = static_cast((1.0 + amplitude) / 2 * 255); *reinterpret_cast(bufferPointer) = value; } else if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::SignedInt) { - const qint8 value = static_cast(x * 127); + const qint8 value = static_cast(amplitude * 127); *reinterpret_cast(bufferPointer) = value; } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::UnSignedInt) { - quint16 value = static_cast((1.0 + x) / 2 * 65535); + quint16 value = static_cast((1.0 + amplitude) / 2 * 65535); if (format.byteOrder() == QAudioFormat::LittleEndian) qToLittleEndian(value, bufferPointer); else @@ -86,7 +95,7 @@ namespace BlackSound } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) { - qint16 value = static_cast(x * 32767); + qint16 value = static_cast(amplitude * 32767); if (format.byteOrder() == QAudioFormat::LittleEndian) qToLittleEndian(value, bufferPointer); else @@ -171,7 +180,7 @@ namespace BlackSound connect(generator, &CSoundGenerator::stopped, audioOutput, &QAudioOutput::stop); connect(generator, &CSoundGenerator::stopped, audioOutput, &QAudioOutput::deleteLater); - qreal vol = volume / 100.0; + double vol = volume / 100.0; audioOutput->setVolume(vol); generator->start(); audioOutput->start(generator); diff --git a/src/blacksound/soundgenerator.h b/src/blacksound/soundgenerator.h index 756cf53d5..2366fa95e 100644 --- a/src/blacksound/soundgenerator.h +++ b/src/blacksound/soundgenerator.h @@ -24,12 +24,19 @@ namespace BlackSound struct Tone { int m_frequencyHz; + int m_secondaryFrequencyHz; qint64 m_durationMs; /*! * \brief Play frequency f for t milliseconds */ - Tone(int frequencyHz, qint64 durationMs) : m_frequencyHz(frequencyHz), m_durationMs(durationMs) {} + Tone(int frequencyHz, qint64 durationMs) : m_frequencyHz(frequencyHz), m_secondaryFrequencyHz(0), m_durationMs(durationMs) {} + + /*! + * \brief Play 2 frequencies f for t milliseconds + */ + Tone(int frequencyHz, int secondaryFrequencyHz, qint64 durationMs) : m_frequencyHz(frequencyHz), m_secondaryFrequencyHz(secondaryFrequencyHz), m_durationMs(durationMs) {} + }; /*!