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), Chris@326: 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) { justin@327: m_phase = 0; justin@327: 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) { justin@327: levels[c] = gain * 0.5; // scale gain otherwise too loud compared to source Chris@313: } Chris@313: if (pan != 0.0 && m_channels == 2) { justin@327: levels[0] *= 1.0 - pan; justin@327: 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: justin@327: switch (m_wavetype) { Chris@326: case 1: Chris@326: harmonics = 1; Chris@326: break; Chris@326: case 2: Chris@326: break; Chris@326: case 3: Chris@326: break; Chris@326: default: Chris@326: harmonics = 3; Chris@326: break; justin@327: } rmb456@323: rmb456@323: Chris@318: for (int h = 0; h < harmonics; ++h) { rmb456@323: Chris@326: double v = 0; Chris@326: double hn = 0; Chris@326: double hp = 0; rmb456@323: Chris@326: switch (m_wavetype) { Chris@326: case 1: // single sinusoid Chris@326: v = sin(m_phase); Chris@326: break; Chris@326: case 2: // sawtooth Chris@326: if (h != 0) { justin@325: hn = h + 1; rmb456@323: hp = m_phase * hn; Chris@326: v = -(1.0 / M_PI) * sin(hp) / hn; Chris@326: } else { Chris@326: v = 0.5; Chris@326: } Chris@326: break; Chris@326: case 3: // square Chris@326: hn = h*2 + 1; Chris@326: hp = m_phase * hn; Chris@326: v = sin(hp) / hn; Chris@326: break; Chris@326: default: // 3 sinusoids Chris@326: hn = h + 1; Chris@326: hp = m_phase * hn; Chris@326: v = sin(hp) / hn; Chris@326: break; Chris@326: } 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: } justin@327: } Chris@313: Chris@313: m_prevF0 = f0; Chris@313: Chris@313: delete[] levels; Chris@313: } Chris@313: