File indexing completed on 2024-04-28 15:08:06

0001 /* miniSynth - A Simple Software Synthesizer
0002    SPDX-FileCopyrightText: 2015 Ville Räisänen <vsr at vsr.name>
0003 
0004    SPDX-License-Identifier: GPL-3.0-or-later
0005 */
0006 
0007 
0008 #include "preset.h"
0009 #include "linearSynthesis.h"
0010 #include "generator.h"
0011 #include <qendian.h>
0012 #include <QMutableListIterator>
0013 
0014 Generator::Generator(const QAudioFormat &_format, QObject *parent) : QIODevice(parent), format(_format) {
0015     linSyn = new LinearSynthesis(Waveform::MODE_SIN);
0016     curtime = 0;
0017 
0018     defaultEnv.attackTime = 100;
0019     defaultEnv.decayTime = 400;
0020     defaultEnv.releaseTime = 100;
0021 
0022     defaultEnv.initialAmpl = 0;
0023     defaultEnv.peakAmpl = 1;
0024     defaultEnv.sustainAmpl = 0.8;
0025 
0026     mod_waveform = new Waveform(Waveform::MODE_SIN);
0027 
0028     synthData    = new qreal[maxUsedBytes];
0029 
0030     for (unsigned int indMaxRead = 0; indMaxRead < maxUsedBytes; indMaxRead++) {
0031         synthData[indMaxRead]    = 0;
0032     }
0033 }
0034 
0035 Generator::~Generator() {
0036     delete linSyn;
0037     delete [] synthData;
0038     delete mod_waveform;
0039 }
0040 
0041 void
0042 Generator::start() {
0043     open(QIODevice::ReadOnly);
0044 }
0045 
0046 void
0047 Generator::stop() {
0048     close();
0049 }
0050 
0051 void
0052 Generator::addWave(unsigned char note, unsigned char vel) {
0053     Wave wav;
0054     wav.state = wav.STATE_ATTACK;
0055     wav.note  = note;
0056     wav.vel   = vel;
0057     wav.state_age = 0;
0058     wav.age      = 0;
0059     wav.env = defaultEnv;
0060 
0061     m_lock.lock();
0062     waveList.push_back(wav);
0063     m_lock.unlock();
0064 }
0065 
0066 qint64
0067 Generator::readData(char *data, qint64 len) {
0068     // QAudioOutput tends to ask large packets of data, which can lead to a
0069     // large delay between noteOn requests and the generation of audio. Thus,
0070     // in order to provide more responsive interface, the packet size is
0071     // limited to 2048 bytes ~ 1024 samples.
0072     if (len > maxUsedBytes) len = maxUsedBytes;
0073 
0074     generateData(len);
0075     memcpy(data, m_buffer.constData(), len);
0076     curtime += (qreal)len/(m_samplingRate*2);
0077     return len;
0078 }
0079 
0080 // Not used.
0081 qint64
0082 Generator::writeData(const char *data, qint64 len) {
0083     Q_UNUSED(data);
0084     Q_UNUSED(len);
0085     return 0;
0086 }
0087 
0088 // Doesn't seem to be called by QAudioOutput.
0089 qint64
0090 Generator::bytesAvailable() const {
0091     return m_buffer.size() + QIODevice::bytesAvailable();
0092 }
0093 
0094 void
0095 Generator::noteOn(unsigned char chan, unsigned char note, unsigned char vel) {
0096     // Velocity of 255 is assumed since a "pleasant" relationship between the
0097     // velocity in the MIDI event and the parameters of the corresponding Wave
0098     // cannot be currently selected by the user.
0099 
0100     if (vel > 0) vel = 255;
0101     addWave(note, vel);
0102     Q_UNUSED(chan);
0103 }
0104 
0105 void
0106 Generator::noteOff(unsigned char chan, unsigned char note) {
0107     QMutableListIterator<Wave> i(waveList);
0108 
0109     while (i.hasNext()) {
0110         Wave wav = i.next();
0111         if (wav.note == note && wav.state != Wave::STATE_RELEASE) {
0112             // To avoid discontinuity in the envelope, the initial value for
0113             // the release part of the envelope should be equal to current
0114             // value.
0115 
0116             wav.env.sustainAmpl = wav.env.eval(wav.state_age, wav.state);
0117 
0118             wav.state = Wave::STATE_RELEASE;
0119             wav.state_age = 0;
0120         }
0121         i.setValue(wav);
0122     }
0123     Q_UNUSED(chan);
0124 }
0125 
0126 void
0127 Generator::setMode(unsigned int _mode) {
0128     delete linSyn;
0129     linSyn = new LinearSynthesis(_mode);
0130     curtime = 0;
0131 }
0132 
0133 void
0134 Generator::setTimbre(QVector<int> &amplitudes, QVector<int> &phases) {
0135     linSyn->setTimbre(amplitudes, phases);
0136 }
0137 
0138 void
0139 Generator::generateData(qint64 len) {
0140     unsigned int numSamples = len/2;
0141     m_buffer.resize(len);
0142 
0143     // Raw synthesized data is assembled into synthData.
0144     memset(synthData, 0, numSamples*sizeof(qreal));
0145 
0146     // All samples for each active note in waveList are synthesized separately.
0147     m_lock.lock();
0148     QMutableListIterator<Wave> i(waveList);
0149 
0150     while (i.hasNext()) {
0151         Wave wav = i.next();
0152         qreal attackTime  = 0.001*(qreal)wav.env.attackTime;
0153         qreal releaseTime = 0.001*(qreal)wav.env.releaseTime;
0154 
0155         qreal freq = 8.175 * 0.5 * qPow(2, ((qreal)wav.note)/12);
0156         qreal ampl = 0.5*((qreal)wav.vel)/256;
0157 
0158         qreal stateAge = wav.state_age;
0159         qreal wavAge   = wav.age;
0160 
0161         const qreal step = 1.f / m_samplingRate;
0162         qreal samplePerStep = 0.f;
0163         for (unsigned int sample = 0; sample < numSamples; sample++, samplePerStep += step) {
0164             qreal t    = curtime   + samplePerStep;
0165             qreal envt = stateAge  + samplePerStep;
0166             qreal modt = wavAge    + samplePerStep;
0167 
0168             // Handle timed change of state in the ADSR-envelopes ATTACK->DECAY
0169             // and RELEASE->OFF.
0170             switch(wav.state) {
0171             case ADSREnvelope::STATE_ATTACK:
0172                 if (envt > attackTime) {
0173                     stateAge -= attackTime;
0174                     wav.state = ADSREnvelope::STATE_DECAY;
0175                     wav.state_age -= attackTime;
0176                     envt = stateAge  + samplePerStep;
0177                 }
0178                 break;
0179             case ADSREnvelope::STATE_RELEASE:
0180                 if (envt > releaseTime) {
0181                     stateAge = 0;
0182                     wav.state = ADSREnvelope::STATE_OFF;
0183                 }
0184                 break;
0185             }
0186 
0187             if (wav.state == ADSREnvelope::STATE_OFF) {
0188                 break;
0189             } else {
0190                 qreal freqmod = 0;
0191                 qreal amod = 0;
0192 
0193                 // Compute modulation waves.
0194 
0195                 if (mod.FM_freq > 0) {
0196                     qreal envVal = mod.useEnvelope ? wav.env.eval(envt, wav.state) : 1;
0197                     if (mod.propFreq) {
0198                         freqmod = mod.FM_ampl
0199                                 * envVal* mod_waveform->eval(2*M_PI*mod.FM_freq*freq*modt);
0200                     } else {
0201                         freqmod = mod.FM_ampl
0202                                 * mod_waveform->eval(2*M_PI*mod.FM_freq*modt);
0203                     }
0204                 }
0205                 if (mod.AM_freq > 0) {
0206                     amod = (1 - qExp(-modt/mod.AM_time))*mod.AM_ampl * mod_waveform->eval(2*M_PI*mod.AM_freq*t);
0207                 }
0208 
0209                 // Evaluate the output wave for the current note and add to the
0210                 // output obtained with other notes.
0211 
0212                 qreal envVal = wav.env.eval(envt, wav.state);
0213                 qreal newVal = envVal * (ampl + amod)
0214                              * 0.5 * linSyn->evalTimbre(2*M_PI*(freq+freqmod)*(modt+100));
0215 
0216                 synthData[sample] += newVal;
0217             }
0218         }
0219         wav.age += (qreal)numSamples/m_samplingRate;
0220         if (wav.state != ADSREnvelope::STATE_OFF) {
0221             wav.state_age += (qreal)numSamples/m_samplingRate;
0222             i.setValue(wav);
0223         }
0224         else {
0225             i.remove();
0226         }
0227     }
0228     m_lock.unlock();
0229 
0230     // Convert data from qreal to qint16.
0231     const int channelBytes = format.sampleSize() / 8;
0232     unsigned char *ptr = reinterpret_cast<unsigned char *>(m_buffer.data());
0233     for (unsigned int sample = 0; sample < numSamples; sample++) {
0234         if (synthData[sample] > 1)  synthData[sample] = 1;
0235         if (synthData[sample] < -1) synthData[sample] = -1;
0236         qint16 value = static_cast<qint16>(synthData[sample] * 32767);
0237         qToLittleEndian<qint16>(value, ptr);
0238         ptr += channelBytes;
0239     }
0240 }
0241 
0242 void
0243 Generator::setEnvelope(const ADSREnvelope &env) {
0244     defaultEnv = env;
0245 }
0246 
0247 void
0248 Generator::setModulation(Modulation &modulation) {
0249     if (modulation.mode != mod_waveform->mode) {
0250         delete mod_waveform;
0251         mod_waveform = new Waveform(modulation.mode);
0252     }
0253     mod = modulation;
0254 }
0255 
0256 void Generator::setPreset(Preset &preset) {
0257     setModulation(preset.mod);
0258     setMode(preset.waveformMode);
0259     setTimbre(preset.timbreAmplitudes, preset.timbrePhases);
0260     setEnvelope(preset.env);
0261 }
0262 
0263 #include "moc_generator.cpp"