drumstick  1.0.2
synthengine.cpp
00001 /*
00002     Drumstick RT (realtime MIDI In/Out)
00003     Copyright (C) 2009-2015 Pedro Lopez-Cabanillas <plcl@users.sf.net>
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 3 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License along
00016     with this program; If not, see <http://www.gnu.org/licenses/>.
00017 */
00018 
00019 #include <QDir>
00020 #include <QFileInfo>
00021 #include <QSettings>
00022 #include <QStandardPaths>
00023 #include <QCoreApplication>
00024 #include <QDebug>
00025 #include "synthengine.h"
00026 
00027 const QString QSTR_PREFERENCES("FluidSynth");
00028 const QString QSTR_INSTRUMENTSDEFINITION("InstrumentsDefinition");
00029 const QString QSTR_DATADIR("soundfonts");
00030 const QString QSTR_SOUNDFONT("default.sf2");
00031 
00032 const QString QSTR_AUDIODRIVER("AudioDriver");
00033 const QString QSTR_PERIODSIZE("PeriodSize");
00034 const QString QSTR_PERIODS("Periods");
00035 const QString QSTR_SAMPLERATE("SampleRate");
00036 const QString QSTR_CHORUS("Chorus");
00037 const QString QSTR_REVERB("Reverb");
00038 const QString QSTR_GAIN("Gain");
00039 const QString QSTR_POLYPHONY("Polyphony");
00040 
00041 const QString QSTR_DEFAULT_AUDIODRIVER =
00042 #if defined(Q_OS_LINUX)
00043     QLatin1Literal("alsa");
00044 #elif defined(Q_OS_WIN)
00045     QLatin1Literal("dsound");
00046 #elif defined(Q_OS_OSX)
00047     QLatin1Literal("coreaudio");
00048 #else
00049     QLatin1Literal("oss");
00050 #endif
00051 const int DEFAULT_PERIODS =
00052 #if defined(Q_OS_WIN)
00053     4;
00054 #else
00055     3;
00056 #endif
00057 const int DEFAULT_PERIODSIZE = 512;
00058 const double DEFAULT_SAMPLERATE = 48000.0;
00059 const int DEFAULT_CHORUS = 0;
00060 const int DEFAULT_REVERB = 0;
00061 const double DEFAULT_GAIN = .4;
00062 const int DEFAULT_POLYPHONY = 32;
00063 
00064 SynthEngine::SynthEngine(QObject *parent)
00065     : QObject(parent),
00066       m_settings(0),
00067       m_synth(0),
00068       m_driver(0)
00069 { }
00070 
00071 SynthEngine::~SynthEngine()
00072 {
00073     uninitialize();
00074 }
00075 
00076 void SynthEngine::uninitialize()
00077 {
00078     if (m_driver != 0) {
00079         ::delete_fluid_audio_driver(m_driver);
00080         m_driver = 0;
00081     }
00082     if (m_synth != 0) {
00083         ::delete_fluid_synth(m_synth);
00084         m_synth = 0;
00085     }
00086     if (m_settings != 0) {
00087         ::delete_fluid_settings(m_settings);
00088         m_settings = 0;
00089     }
00090 }
00091 
00092 void SynthEngine::initializeSynth(QSettings* settings)
00093 {
00094     QString fs_audiodriver = QSTR_DEFAULT_AUDIODRIVER;
00095     int fs_periodSize = DEFAULT_PERIODSIZE;
00096     int fs_periods = DEFAULT_PERIODS;
00097     double fs_sampleRate = DEFAULT_SAMPLERATE;
00098     int fs_chorus = DEFAULT_CHORUS;
00099     int fs_reverb = DEFAULT_REVERB;
00100     double fs_gain = DEFAULT_GAIN;
00101     int fs_polyphony = DEFAULT_POLYPHONY;
00102     if (settings != 0) {
00103         settings->beginGroup(QSTR_PREFERENCES);
00104         fs_audiodriver = settings->value(QSTR_AUDIODRIVER, QSTR_DEFAULT_AUDIODRIVER).toString();
00105         fs_periodSize = settings->value(QSTR_PERIODSIZE, DEFAULT_PERIODSIZE).toInt();
00106         fs_periods = settings->value(QSTR_PERIODS, DEFAULT_PERIODS).toInt();
00107         fs_sampleRate = settings->value(QSTR_SAMPLERATE, DEFAULT_SAMPLERATE).toDouble();
00108         fs_chorus = settings->value(QSTR_CHORUS, DEFAULT_CHORUS).toInt();
00109         fs_reverb = settings->value(QSTR_REVERB, DEFAULT_REVERB).toInt();
00110         fs_gain = settings->value(QSTR_GAIN, DEFAULT_GAIN).toDouble();
00111         fs_polyphony = settings->value(QSTR_POLYPHONY, DEFAULT_POLYPHONY).toInt();
00112         settings->endGroup();
00113     }
00114     uninitialize();
00115     m_settings = ::new_fluid_settings();
00116     ::fluid_settings_setstr(m_settings, "audio.driver", qPrintable(fs_audiodriver));
00117     ::fluid_settings_setint(m_settings, "audio.period-size", fs_periodSize);
00118     ::fluid_settings_setint(m_settings, "audio.periods", fs_periods);
00119     ::fluid_settings_setnum(m_settings, "synth.sample-rate", fs_sampleRate);
00120     ::fluid_settings_setint(m_settings, "synth.chorus.active", fs_chorus);
00121     ::fluid_settings_setint(m_settings, "synth.reverb.active", fs_reverb);
00122     ::fluid_settings_setnum(m_settings, "synth.gain", fs_gain);
00123     ::fluid_settings_setint(m_settings, "synth.polyphony", fs_polyphony);
00124     m_synth = ::new_fluid_synth(m_settings);
00125     m_driver = ::new_fluid_audio_driver(m_settings, m_synth);
00126 }
00127 
00128 void SynthEngine::setInstrument(int channel, int pgm)
00129 {
00130     ::fluid_synth_program_change(m_synth, channel, pgm);
00131 }
00132 
00133 void SynthEngine::noteOn(int channel, int midiNote, int velocity)
00134 {
00135     ::fluid_synth_noteon(m_synth, channel, midiNote, velocity);
00136 }
00137 
00138 void SynthEngine::noteOff(int channel, int midiNote, int /*velocity*/)
00139 {
00140     ::fluid_synth_noteoff(m_synth, channel, midiNote);
00141 }
00142 
00143 void SynthEngine::loadSoundFont()
00144 {
00145     if (m_sfid != -1) {
00146         ::fluid_synth_sfunload(m_synth, unsigned(m_sfid), 1);
00147     }
00148     m_sfid = ::fluid_synth_sfload(m_synth, qPrintable(m_soundFont), 1);
00149 }
00150 
00151 void SynthEngine::initialize(QSettings *settings)
00152 {
00153     initializeSynth(settings);
00154     scanSoundFonts();
00155     loadSoundFont();
00156     if (m_sfid < 0) {
00157         m_soundFont = m_defSoundFont;
00158         loadSoundFont();
00159     }
00160 }
00161 
00162 void SynthEngine::panic()
00163 {
00164     ::fluid_synth_system_reset(m_synth);
00165 }
00166 
00167 void SynthEngine::controlChange(const int channel, const int midiCtl, const int value)
00168 {
00169     ::fluid_synth_cc(m_synth, channel, midiCtl, value);
00170 }
00171 
00172 void SynthEngine::bender(const int channel, const int value)
00173 {
00174     ::fluid_synth_pitch_bend(m_synth, channel, value + 8192);
00175 }
00176 
00177 void SynthEngine::setSoundFont(const QString &value)
00178 {
00179     if (value != m_soundFont) {
00180         m_soundFont = value;
00181         loadSoundFont();
00182     }
00183 }
00184 
00185 void SynthEngine::scanSoundFonts(const QDir &initialDir)
00186 {
00187     QDir dir(initialDir);
00188     dir.setFilter(QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot);
00189     dir.setSorting(QDir::Name);
00190     QStringList filters;
00191     filters << "*.sf2" << "*.SF2";
00192     QFileInfoList entries= dir.entryInfoList(filters);
00193     foreach(const QFileInfo &info, entries) {
00194         QString name = info.absoluteFilePath();
00195         if (info.isFile()) {
00196             m_soundFontsList << name;
00197         } else if (info.isDir()){
00198             scanSoundFonts(name);
00199         }
00200     }
00201 }
00202 
00203 void SynthEngine::scanSoundFonts()
00204 {
00205     m_soundFontsList.clear();
00206     QStringList paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
00207 #if defined(Q_OS_OSX)
00208     paths << (QCoreApplication::applicationDirPath() + QLatin1Literal("../Resources"));
00209 #endif
00210     foreach(const QString& p, paths) {
00211        QDir d(p + QDir::separator() + QSTR_DATADIR);
00212        if (d.exists()) {
00213             scanSoundFonts(d);
00214        }
00215     }
00216 }
00217 
00218 void SynthEngine::readSettings(QSettings *settings)
00219 {
00220     QDir dir;
00221 #if defined(Q_OS_OSX)
00222     dir = QDir(QCoreApplication::applicationDirPath() + QLatin1Literal("/../Resources"));
00223 #elif defined(Q_OS_UNIX)
00224     dir = QDir(QCoreApplication::applicationDirPath() + QLatin1Literal("/../share/soundfonts/"));
00225 #else
00226     dir = QDir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR, QStandardPaths::LocateDirectory));
00227 #endif
00228     QFileInfo sf2(dir, QSTR_SOUNDFONT);
00229     if (sf2.exists()) {
00230         m_defSoundFont = sf2.absoluteFilePath();
00231     }
00232     m_sfid = -1;
00233     qDebug() << "defSoundFont:" << m_defSoundFont;
00234     settings->beginGroup(QSTR_PREFERENCES);
00235     m_soundFont = settings->value(QSTR_INSTRUMENTSDEFINITION, m_defSoundFont).toString();
00236     settings->endGroup();
00237 }
00238 
00239 void SynthEngine::close()
00240 {
00241     m_currentConnection.clear();
00242     uninitialize();
00243 }
00244 
00245 void SynthEngine::open()
00246 {
00247     m_currentConnection = QSTR_FLUIDSYNTH;
00248 }
00249