Entropy Piano Tuner  1.1.3 (documentation not yet complete)
An open-source experimental software for piano tuning by entropy minimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
synthesizer.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2015 Haye Hinrichsen, Christoph Wick
3  *
4  * This file is part of Entropy Piano Tuner.
5  *
6  * Entropy Piano Tuner is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * Entropy Piano Tuner is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * Entropy Piano Tuner. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
20 #include "synthesizer.h"
21 #include "hammerknock.h"
22 
23 #include "../../system/log.h"
24 #include "../../math/mathtools.h"
25 
26 #include <random>
27 #include <iostream>
28 
29 //=============================================================================
30 // Structure describing an envelope
31 //=============================================================================
32 
33 //-----------------------------------------------------------------------------
34 // Constructor
35 //-----------------------------------------------------------------------------
36 
48 
49 Envelope::Envelope(double attack, double decay,
50  double sustain, double release, double hammer) :
51  attack(attack),
52  decay(decay),
53  sustain(sustain),
54  release(release),
55  hammer(hammer)
56 {}
57 
58 
59 //=============================================================================
60 // CLASS SYNTHESIZER
61 //=============================================================================
62 
63 //-----------------------------------------------------------------------------
64 // Constructor
65 //-----------------------------------------------------------------------------
66 
72 
74  mNumberOfKeys(88),
75  mPlayingTones(),
76  mPlayingMutex(),
77  mSineWave(),
78  mHammerWaveLeft(),
79  mHammerWaveRight(),
80  mReverbSize(0),
81  mReverbCounter(0),
82  mReverbL(),
83  mReverbR(),
84  mIntensity(0)
85 {}
86 
87 
88 //-----------------------------------------------------------------------------
89 // Initialize and start the main thread
90 //-----------------------------------------------------------------------------
91 
99 
100 void Synthesizer::init (int sampleRate, int channels)
101 {
102  PCMWriterInterface::init(sampleRate, channels);
103 
104  if (mNumberOfKeys < 0 or mNumberOfKeys > 256)
105  { LogW("Called init with an invalid number of keys = %d",mNumberOfKeys); return; }
106 
107  // Pre-calculate a sine wave for speedup
108  mSineWave.resize(SineLength);
109  for (int i=0; i<SineLength; ++i)
110  mSineWave[i]=static_cast<float>(sin(MathTools::TWO_PI * i / SineLength));
111 
112  // Pre-calculate a piano-hammer-like noise (one second), could be improved
113  FFTComplexType amplitude (0.15/mSampleRate);
114  int datasize = std::min(mSampleRate/2+1,static_cast<int>(mHammerKnockFFT[0].size()));
115  FFTComplexVector fftl(mSampleRate/2+1,0),fftr(mSampleRate/2+1,0);
116  for (int i=0; i<datasize; i++)
117  {
118  fftl[i] = FFTComplexType(mHammerKnockFFT[0][i],-mHammerKnockFFT[1][i])*amplitude;
119  fftr[i] = FFTComplexType(mHammerKnockFFT[2][i],-mHammerKnockFFT[3][i])*amplitude;
120  }
121  FFT_Implementation transformer;
124  mHammerWaveLeft.assign(mSampleRate,0);
125  mHammerWaveRight.assign(mSampleRate,0);
126  transformer.calculateFFT(fftl,mHammerWaveLeft);
127  transformer.calculateFFT(fftr,mHammerWaveRight);
128  for (int i=0; i<mSampleRate; i++)
129  {
130  mHammerWaveRight[i] *= exp(-pow(i*3.0/mSampleRate,1.5));
131  mHammerWaveLeft[i] *= exp(-pow(i*3.0/mSampleRate,1.5));
132  }
133 
134  // Initialize reverb
135  mReverbSize = mSampleRate/10;
136  mReverbCounter = 0;
137  mReverbL.resize(mReverbSize);
138  mReverbR.resize(mReverbSize);
139  mReverbL.assign(mReverbSize,0);
140  mReverbR.assign(mReverbSize,0);
141  mDelay1 = static_cast<int> (0.1128*mReverbSize);
142  mDelay2 = static_cast<int> (0.3928*mReverbSize);
143  mDelay3 = static_cast<int> (0.8762*mReverbSize);
144 
145  // Start the waveform generator
148 }
149 
150 
151 //-----------------------------------------------------------------------------
152 // Set number of keys
153 //-----------------------------------------------------------------------------
154 
159 
160 void Synthesizer::setNumberOfKeys (int numberOfKeys)
161 {
162  if (numberOfKeys < 0 or numberOfKeys > 255)
163  {
164  LogW("Unreasonable number of keys = %d.",numberOfKeys);
165  return;
166  }
167  else if (numberOfKeys != mNumberOfKeys)
168  {
169  mNumberOfKeys = numberOfKeys;
171  }
172 }
173 
174 //-----------------------------------------------------------------------------
175 // Pre-calculate the PCM waveform of a sound
176 //-----------------------------------------------------------------------------
177 
199 
201  const Spectrum &spectrum)
202 {
203  if (id>=0 and id<100) mWaveformGenerator.preCalculate(id, spectrum);
204 }
205 
206 
207 //-----------------------------------------------------------------------------
208 // Play a sound
209 //-----------------------------------------------------------------------------
210 
229 
230 void Synthesizer::playSound (const int keynumber,
231  const double frequency,
232  const double volume,
233  const Envelope &env,
234  const bool waitforcomputation,
235  const bool stereo)
236 {
237  if (frequency <= 0 or volume <= 0 or mNumberOfKeys == 0) return;
238  Tone tone;
239  tone.keynumber = keynumber;
240  tone.frequency = frequency;
241  double position = (20+(keynumber&0xff)) * 1.0 / (mNumberOfKeys+40);
242  if (not stereo) position = 0.5;
243  tone.leftamplitude = sqrt((1-position)*volume);
244  tone.rightamplitude = sqrt(position*volume);
245  tone.phaseshift = (position-0.5)/500;
246  tone.envelope = env;
247  tone.clock=0;
248  tone.stage=1;
249  tone.amplitude=0;
250 
251  int timeout = 0;
252  if (frequency>0 and frequency<10)
253  {
254  while (waitforcomputation and mWaveformGenerator.isComputing(keynumber)
255  and timeout++ < 1000) {
256  std::this_thread::sleep_for(std::chrono::milliseconds(1));
257  }
258  tone.waveform = mWaveformGenerator.getWaveForm(keynumber);
259  }
260  else
261  tone.waveform.clear();
262 
263  mPlayingMutex.lock();
264  mPlayingTones.push_back(tone);
265  mPlayingMutex.unlock();
266 }
267 
268 
269 //-----------------------------------------------------------------------------
270 // update of the intensity
271 //-----------------------------------------------------------------------------
272 
284 
286 {
287  mPlayingMutex.lock();
288  if (mPlayingTones.size()>0) mIntensity = 1;
289  mPlayingMutex.unlock();
290 
291  if (mIntensity < 0.0000001)
292  {
293  mIntensity = 0;
294  }
295  else
296  {
297  // first remove all sounds with a volume below cutoff:
298  mPlayingMutex.lock();
299  for (auto it = mPlayingTones.begin(); it != mPlayingTones.end(); /* no inc */)
300  if (it->stage>=2 and it->amplitude<CutoffVolume)
301  it=mPlayingTones.erase(it);
302  else ++it;
303  //size_t N = mPlayingTones.size();
304  mPlayingMutex.unlock();
305  }
306 }
307 
308 
309 //-----------------------------------------------------------------------------
310 // Generate the waveform
311 //-----------------------------------------------------------------------------
312 
321 
323 {
324  // update intensity and played tones
325  updateIntensity();
326 
327  if (mIntensity == 0 ) {
328  return false;
329  }
330 
331  const int sampleRate = mSampleRate;
332  const int channels = mChannels;
333 
334  int64_t clock_timeout = 40*sampleRate; // one minute timeout
335  int hammerwavesize = mHammerWaveLeft.size();
336 
337  if (channels<=0 or channels>2) return false;
338 
339 
340  for (size_t bufferIndex = channels - 1; bufferIndex < outputBuffer.size(); bufferIndex += channels) {
341  // pcm data
342  double left = 0, right = 0;
343 
344  mPlayingMutex.lock();
345  for (Tone &tone : mPlayingTones)
346  {
347  //============== MANAGE THE ENVELOPE =================
348 
349  double y = tone.amplitude; // get last amplitude
350  Envelope &envelope = tone.envelope; // get ADSR
351  switch (tone.stage) // Manage ADSR
352  {
353  case 1: // ATTACK
354  y += envelope.attack/sampleRate;
355  if (envelope.decay>0)
356  {
357  if (y >= 1) tone.stage++;
358  }
359  else
360  {
361  if (y >= envelope.sustain) tone.stage+=2;
362  }
363  break;
364  case 2: // DECAY
365  y *= (1-(1+y)*envelope.decay/sampleRate); // DECAY
366  if (y <= envelope.sustain) tone.stage++;
367  break;
368  case 3: // SUSTAIN
369  y += (envelope.sustain-y) * envelope.release / sampleRate;
370  if (tone.clock > clock_timeout) tone.stage=4;
371  break;
372  case 4: // RELEASE
373  y *= (1-envelope.release/sampleRate);
374  break;
375  }
376  tone.amplitude = y;
377  tone.clock ++;
378 
379  //================ CREATE THE PCM WAVEFORM ==============
380 
381  if (tone.frequency > 10) // if sine wave
382  {
383  double t = 1+tone.clock*1.0/sampleRate;
384  int i = static_cast<int64_t>(SineLength*tone.frequency*t);
385  int j = static_cast<int64_t>(SineLength*tone.frequency*(t+tone.phaseshift));
386  left += tone.leftamplitude * y * 0.2 * mSineWave[i%SineLength];;
387  right += tone.rightamplitude * y * 0.2 * mSineWave[j%SineLength];;
388  }
389  else // if complex sound
390  {
391  if (envelope.hammer) if (tone.clock < hammerwavesize)
392  {
393  left += tone.leftamplitude * mHammerWaveLeft[tone.clock];
394  int phaseshifted = tone.clock + static_cast<int>(tone.phaseshift * sampleRate);
395  if (phaseshifted < hammerwavesize)
396  right += tone.rightamplitude* mHammerWaveRight[phaseshifted];
397  }
398 
399  double t = (1+tone.clock*1.0/sampleRate)*tone.frequency;
400  left += tone.leftamplitude * y * 0.3 *
401  mWaveformGenerator.getInterpolation(tone.waveform,t);
402  right += tone.rightamplitude * y * 0.3 *
403  mWaveformGenerator.getInterpolation(tone.waveform,t+tone.phaseshift);
404  }
405  }
406 
407  const double reverbamplitude = 0.2;
408  double echo1 = mReverbR[(mReverbCounter+mDelay1) % mReverbSize];
409  double echo2 = mReverbL[(mReverbCounter+mDelay2) % mReverbSize];
410  double echo3 = mReverbR[(mReverbCounter+mDelay3) % mReverbSize];
411  double echo4 = mReverbL[(mReverbCounter+1) % mReverbSize];
412  left += reverbamplitude * ( echo2 + echo3 );
413  right += reverbamplitude * ( echo1 + echo4 );
414  mReverbL[mReverbCounter] = left;
415  mReverbR[mReverbCounter] = right;
417  mIntensity = 0.98 * mIntensity + left*left + right*right;
418 
419  mPlayingMutex.unlock();
420 
421  // write data to buffer
422  if (channels==1)
423  {
424  outputBuffer[bufferIndex] = static_cast<AudioBase::PCMDataType>((left+right)/2);
425  }
426  else // if stereo
427  {
428  outputBuffer[bufferIndex - 1] = static_cast<AudioBase::PCMDataType>(left);
429  outputBuffer[bufferIndex] = static_cast<AudioBase::PCMDataType>(right);
430  }
431 
432  }
433  return true;
434 }
435 
436 
437 //-----------------------------------------------------------------------------
438 // Get tone pointer (private)
439 //-----------------------------------------------------------------------------
440 
446 
447 const Tone* Synthesizer::getSoundPointer (const int id) const
448 {
449  const Tone *snd(nullptr);
450  mPlayingMutex.lock();
451  for (auto &ch : mPlayingTones) if (ch.keynumber==id) { snd=&ch; break; }
452  mPlayingMutex.unlock();
453  return snd;
454 }
455 
457 {
458  Tone *snd(nullptr);
459  mPlayingMutex.lock();
460  for (auto &ch : mPlayingTones) if (ch.keynumber==id) { snd=&ch; break; }
461  mPlayingMutex.unlock();
462  return snd;
463 }
464 
465 
466 //-----------------------------------------------------------------------------
467 // Terminate a sound
468 //-----------------------------------------------------------------------------
469 
476 
477 void Synthesizer::releaseSound (const int id)
478 {
479  bool released=false;
480  mPlayingMutex.lock();
481  for (auto &ch : mPlayingTones) if ((ch.keynumber & 0xff)==id) { ch.stage=4; released=true; }
482  mPlayingMutex.unlock();
483  if (not released) LogW("Release: Sound with id=%d does not exist.",id);
484 }
485 
486 
487 //-----------------------------------------------------------------------------
488 // Check whether a certain sound is still active
489 //-----------------------------------------------------------------------------
490 
497 
498 bool Synthesizer::isPlaying (const int id) const
499 { return (getSoundPointer(id) != nullptr); }
500 
501 
502 //-----------------------------------------------------------------------------
503 // Change the sustain level
504 //-----------------------------------------------------------------------------
505 
516 
517 void Synthesizer::ModifySustainLevel (const int id, const double level)
518 {
519  Tone* snd = getSoundPointer(id);
520  if (snd)
521  {
522  mPlayingMutex.lock();
523  snd->envelope.sustain = level;
524  mPlayingMutex.unlock();
525  }
526  else LogW ("Cannot modify sustain level: id %d does not exist",id);
527 }
int stage
1=attack 2=decay 3=sustain 4=release.
Definition: synthesizer.h:85
double sustain
Sustain level.
Definition: synthesizer.h:50
std::vector< PCMDataType > PacketType
Type definition of a PCM packet (vector of PCM values).
Definition: audiobase.h:51
int_fast64_t clock
Running time in sample cycles.
Definition: synthesizer.h:84
double leftamplitude
Left stereo volume.
Definition: synthesizer.h:79
std::vector< Tone > mPlayingTones
Chord defined as a collection of tones.
Definition: synthesizer.h:147
bool isPlaying(const int id) const
Check whether a sound with given id is still playing.
int keynumber
Identification tag (negativ=sine)
Definition: synthesizer.h:77
const Tone * getSoundPointer(const int id) const
Get a pointer to the sound according to the given ID.
virtual void init(const int sampleRate, const int channels)
Initialize the PCM-Writer with given sample rate and channel number.
Envelope(double attack=0, double decay=0, double sustain=0, double release=0, double hammer=0)
Envelope::Envelope.
Definition: synthesizer.cpp:49
double rightamplitude
Right stereo volume.
Definition: synthesizer.h:80
std::vector< double > mReverbL
Definition: synthesizer.h:161
#define LogW(...)
Definition: log.h:56
std::vector< FFTComplexType > FFTComplexVector
Definition: fftadapter.h:36
int mNumberOfKeys
Number of keys, passed in init()
Definition: synthesizer.h:145
WaveformGenerator mWaveformGenerator
Definition: synthesizer.h:143
void playSound(const int id, const double frequency, const double volume, const Envelope &env, const bool waitforcomputation=false, const bool stereo=true)
Function which plays a single note (sound)
FFTRealVector mHammerWaveRight
Definition: synthesizer.h:157
std::vector< double > mReverbR
Reverb.
Definition: synthesizer.h:161
Waveform mSineWave
Sine wave vector, computed in init().
Definition: synthesizer.h:153
static const std::vector< std::vector< int > > mHammerKnockFFT
Hammerknock Fourier data.
Definition: synthesizer.h:155
double decay
Subsequent decay rate.
Definition: synthesizer.h:49
double mIntensity
Definition: synthesizer.h:162
Synthesizer()
Constructor, intitializes the member variables.
Definition: synthesizer.cpp:73
std::mutex mPlayingMutex
Mutex to protect access to the chord.
Definition: synthesizer.h:148
double phaseshift
Stereo phase shift.
Definition: synthesizer.h:81
double attack
Initial attack rate.
Definition: synthesizer.h:48
int mSampleRate
Sample rate.
void init(int numberOfKeys, int samplerate)
Initialization procedure of the waveform generator.
double PCMDataType
Definition: audiobase.h:48
std::complex< double > FFTComplexType
Definition: fftadapter.h:34
virtual bool generateAudioSignal(AudioBase::PacketType &outputPacket) overridefinal
Generate waveform.
void releaseSound(const int id)
Terminate a sound.
virtual void start()
Start the thread.
int mChannels
Number of channels.
const int_fast64_t SineLength
sine value buffer length.
Definition: synthesizer.h:150
Waveform getWaveForm(const int keynumber)
Mutexed getter function to obtain the calculated waveform.
int mReverbCounter
Definition: synthesizer.h:159
bool isComputing(const int keynumber)
Find out whether the WaveformGenerator is still computing.
void updateIntensity()
Update function to update intensity.
void setNumberOfKeys(int numberOfKeys)
Tell the synthesizer to change the total number of keys.
Envelope envelope
Dynamic properties of the tone.
Definition: synthesizer.h:82
double frequency
Fundamental frequency.
Definition: synthesizer.h:78
float getInterpolation(const Waveform &W, const double t)
Get an a linearly interpolated value of the waveform.
double hammer
Intensity of hammer noise.
Definition: synthesizer.h:52
void preCalculateWaveform(const int id, const Spectrum &spectrum)
Pre-calculate the PCM waveform of a sound.
void ModifySustainLevel(const int id, const double level)
Change the level (sustain level) of a constantly playing sound.
void preCalculate(int keynumber, const Spectrum &spectrum)
pre-calculate a waveform
std::map< double, double > Spectrum
Definition: synthesizer.h:113
double release
Release rate.
Definition: synthesizer.h:51
virtual void init(int sampleRate, int channels) overridefinal
Initialize and start the synthesizer.
const double CutoffVolume
Fade-out volume cutoff.
Definition: synthesizer.h:151
const double TWO_PI
Definition: mathtools.h:38
Structure describing the envelope (dynamics) of a sound.
Definition: synthesizer.h:46
WaveformGenerator::Waveform waveform
Copy of the waveform.
Definition: synthesizer.h:88
FFTRealVector mHammerWaveLeft
Hammer noise, computed in init().
Definition: synthesizer.h:156
double amplitude
current envelope amplitude
Definition: synthesizer.h:86
void calculateFFT(const FFTRealVector &in, FFTComplexVector &out)
Foward FFT, mapping a real vector with size N to a complex one with size N/2+1.
Structure of a single tone.
Definition: synthesizer.h:75
Thread-safe implementation of fftw3.