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: rmb456@323: ContinuousSynth::ContinuousSynth(int channels, int sampleRate, int blockSize, int waveType) : Chris@313: m_channels(channels), Chris@313: m_sampleRate(sampleRate), Chris@313: m_blockSize(blockSize), Chris@313: m_prevF0(-1.f), rmb456@323: m_phase(0.0), rmb456@323: m_wavetype(waveType) // 0: 3 sinusoids, 1: 1 sinusoid, 2: sawtooth, 3: square 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: rmb456@323: 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: rmb456@323: switch (m_wavetype) { rmb456@323: case 1: rmb456@323: harmonics = 1; rmb456@323: break; rmb456@323: case 2: rmb456@323: break; rmb456@323: case 3: rmb456@323: break; rmb456@323: default: rmb456@323: harmonics = 3; rmb456@323: break; rmb456@323: } rmb456@323: rmb456@323: Chris@318: for (int h = 0; h < harmonics; ++h) { rmb456@323: rmb456@323: double v = 0; rmb456@323: double hn = 0; rmb456@323: double hp = 0; rmb456@323: rmb456@323: switch (m_wavetype) { rmb456@323: case 1: // single sinusoid rmb456@323: v = sin(m_phase); rmb456@323: break; rmb456@323: case 2: // sawtooth rmb456@323: if (h != 0) { rmb456@323: hn = h + 1; rmb456@323: hp = m_phase * hn; rmb456@323: v = -(1.0 / M_PI) * sin(hp) / hn; rmb456@323: } else { rmb456@323: v = 0.5; rmb456@323: } rmb456@323: break; rmb456@323: case 3: // square rmb456@323: hn = h*2 + 1; rmb456@323: hp = m_phase * hn; rmb456@323: v = sin(hp) / hn; rmb456@323: break; rmb456@323: default: // 3 sinusoids rmb456@323: hn = h*2 + 1; rmb456@323: hp = m_phase * hn; rmb456@323: v = sin(hp) / hn; rmb456@323: break; rmb456@323: } 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: