svapp  1.9
ContinuousSynth.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     
00008     This program is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU General Public License as
00010     published by the Free Software Foundation; either version 2 of the
00011     License, or (at your option) any later version.  See the file
00012     COPYING included with this distribution for more information.
00013 */
00014 
00015 #include "ContinuousSynth.h"
00016 
00017 #include "base/Debug.h"
00018 #include "system/System.h"
00019 
00020 #include <cmath>
00021 
00022 ContinuousSynth::ContinuousSynth(int channels, int sampleRate, int blockSize, int waveType) :
00023     m_channels(channels),
00024     m_sampleRate(sampleRate),
00025     m_blockSize(blockSize),
00026     m_prevF0(-1.f),
00027     m_phase(0.0),
00028     m_wavetype(waveType) // 0: 3 sinusoids, 1: 1 sinusoid, 2: sawtooth, 3: square
00029 {
00030 }
00031 
00032 ContinuousSynth::~ContinuousSynth()
00033 {
00034 }
00035 
00036 void
00037 ContinuousSynth::reset()
00038 {
00039     m_phase = 0;
00040 }
00041 
00042 void
00043 ContinuousSynth::mix(float **toBuffers, float gain, float pan, float f0)
00044 {
00045     if (f0 == 0.f) f0 = m_prevF0;
00046 
00047     bool wasOn = (m_prevF0 > 0.f);
00048     bool nowOn = (f0 > 0.f);
00049 
00050     if (!nowOn && !wasOn) {
00051     m_phase = 0;
00052     return;
00053     }
00054 
00055     int fadeLength = 100; // samples
00056 
00057     float *levels = new float[m_channels];
00058     
00059     for (int c = 0; c < m_channels; ++c) {
00060     levels[c] = gain * 0.5; // scale gain otherwise too loud compared to source
00061     }
00062     if (pan != 0.0 && m_channels == 2) {
00063     levels[0] *= 1.0 - pan;
00064     levels[1] *= pan + 1.0;
00065     }
00066 
00067 //    cerr << "ContinuousSynth::mix: f0 = " << f0 << " (from " << m_prevF0 << "), phase = " << m_phase << endl;
00068 
00069     for (int i = 0; i < m_blockSize; ++i) {
00070 
00071         double fHere = (nowOn ? f0 : m_prevF0);
00072 
00073         if (wasOn && nowOn && (f0 != m_prevF0) && (i < fadeLength)) {
00074             // interpolate the frequency shift
00075             fHere = m_prevF0 + ((f0 - m_prevF0) * i) / fadeLength;
00076         }
00077 
00078         double phasor = (fHere * 2 * M_PI) / m_sampleRate;
00079     
00080         m_phase = m_phase + phasor;
00081 
00082         int harmonics = (m_sampleRate / 4) / fHere - 1;
00083         if (harmonics < 1) harmonics = 1;
00084 
00085         switch (m_wavetype) {
00086         case 1:
00087             harmonics = 1;
00088             break;
00089         case 2:
00090             break;
00091         case 3:
00092             break;
00093         default:
00094             harmonics = 3;
00095             break;
00096         }
00097 
00098 
00099         for (int h = 0; h < harmonics; ++h) {
00100 
00101             double v = 0;
00102             double hn = 0;
00103             double hp = 0;
00104 
00105             switch (m_wavetype) {
00106             case 1: // single sinusoid
00107                 v = sin(m_phase);
00108                 break;
00109             case 2: // sawtooth
00110                 if (h != 0) {
00111                     hn = h + 1;
00112                     hp = m_phase * hn;
00113                     v = -(1.0 / M_PI) * sin(hp) / hn;
00114                 } else {
00115                     v = 0.5;
00116                 }
00117                 break;
00118             case 3: // square
00119                 hn = h*2 + 1;
00120                 hp = m_phase * hn;
00121                 v = sin(hp) / hn;
00122                 break;
00123             default: // 3 sinusoids
00124                 hn = h + 1;
00125                 hp = m_phase * hn;
00126                 v = sin(hp) / hn;
00127                 break;
00128             }
00129 
00130             if (!wasOn && i < fadeLength) {
00131                 // fade in
00132                 v = v * (i / double(fadeLength));
00133             } else if (!nowOn) {
00134                 // fade out
00135                 if (i > fadeLength) v = 0;
00136                 else v = v * (1.0 - (i / double(fadeLength)));
00137             }
00138 
00139             for (int c = 0; c < m_channels; ++c) {
00140                 toBuffers[c][i] += levels[c] * v;
00141             }
00142         }
00143     }    
00144 
00145     m_prevF0 = f0;
00146 
00147     delete[] levels;
00148 }
00149