Chris@313: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@313: Chris@313: /* Chris@313: Sonic Visualiser Chris@313: An audio file viewer and annotation editor. Chris@313: Centre for Digital Music, Queen Mary, University of London. Chris@313: Chris@313: This program is free software; you can redistribute it and/or Chris@313: modify it under the terms of the GNU General Public License as Chris@313: published by the Free Software Foundation; either version 2 of the Chris@313: License, or (at your option) any later version. See the file Chris@313: COPYING included with this distribution for more information. Chris@313: */ Chris@313: Chris@313: #include "ContinuousSynth.h" Chris@313: Chris@313: #include "base/Debug.h" Chris@318: #include "system/System.h" Chris@313: Chris@313: #include Chris@313: Chris@313: ContinuousSynth::ContinuousSynth(int channels, int sampleRate, int blockSize) : Chris@313: m_channels(channels), Chris@313: m_sampleRate(sampleRate), Chris@313: m_blockSize(blockSize), Chris@313: m_prevF0(-1.f), Chris@313: m_phase(0.0) Chris@313: { Chris@313: } Chris@313: Chris@313: ContinuousSynth::~ContinuousSynth() Chris@313: { Chris@313: } Chris@313: Chris@313: void Chris@313: ContinuousSynth::reset() Chris@313: { Chris@313: m_phase = 0; Chris@313: } Chris@313: Chris@313: void Chris@313: ContinuousSynth::mix(float **toBuffers, float gain, float pan, float f0) Chris@313: { Chris@313: if (f0 == 0.f) f0 = m_prevF0; Chris@313: Chris@313: bool wasOn = (m_prevF0 > 0.f); Chris@313: bool nowOn = (f0 > 0.f); Chris@313: Chris@313: if (!nowOn && !wasOn) { Chris@313: m_phase = 0; Chris@313: return; Chris@313: } Chris@313: Chris@315: int fadeLength = 100; // samples Chris@313: Chris@313: float *levels = new float[m_channels]; Chris@313: Chris@313: for (int c = 0; c < m_channels; ++c) { Chris@313: levels[c] = gain; Chris@313: } Chris@313: if (pan != 0.0 && m_channels == 2) { Chris@313: levels[0] *= 1.0 - pan; Chris@313: levels[1] *= pan + 1.0; Chris@313: } Chris@313: Chris@315: // cerr << "ContinuousSynth::mix: f0 = " << f0 << " (from " << m_prevF0 << "), phase = " << m_phase << endl; Chris@313: Chris@313: for (int i = 0; i < m_blockSize; ++i) { Chris@313: Chris@315: double fHere = (nowOn ? f0 : m_prevF0); Chris@315: Chris@315: if (wasOn && nowOn && (f0 != m_prevF0) && (i < fadeLength)) { Chris@315: // interpolate the frequency shift Chris@315: fHere = m_prevF0 + ((f0 - m_prevF0) * i) / fadeLength; Chris@315: } Chris@315: Chris@315: double phasor = (fHere * 2 * M_PI) / m_sampleRate; Chris@315: Chris@315: m_phase = m_phase + phasor; Chris@313: Chris@318: int harmonics = (m_sampleRate / 4) / fHere - 1; Chris@318: if (harmonics < 1) harmonics = 1; Chris@313: Chris@318: for (int h = 0; h < harmonics; ++h) { Chris@318: Chris@318: double hn = h*2 + 1; Chris@318: double hp = m_phase * hn; Chris@318: double v = sin(hp) / hn; Chris@318: Chris@318: if (!wasOn && i < fadeLength) { Chris@318: // fade in Chris@318: v = v * (i / double(fadeLength)); Chris@318: } else if (!nowOn) { Chris@318: // fade out Chris@318: if (i > fadeLength) v = 0; Chris@318: else v = v * (1.0 - (i / double(fadeLength))); Chris@318: } Chris@318: Chris@318: for (int c = 0; c < m_channels; ++c) { Chris@318: toBuffers[c][i] += levels[c] * v; Chris@318: } Chris@318: } Chris@313: } Chris@313: Chris@313: m_prevF0 = f0; Chris@313: Chris@313: delete[] levels; Chris@313: } Chris@313: