Just Intonation  Version 1.3.1 (19)
Explore key-independent dynamically adapting tuning in just intonation
wave.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2016-2017 Karolin Stange, Christoph Wick, and Haye Hinrichsen
3  *
4  * This file is part of JustIntonation.
5  *
6  * JustIntonation 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  * JustIntonation 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
14  * for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with JustIntonation. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
20 //=============================================================================
21 // Wave: Class holding the sampled sound for one key
22 //=============================================================================
23 
24 #include "wave.h"
25 
26 #include <QFile>
27 #include <QDebug>
28 #include <QThread>
29 #include <QtGlobal>
30 
31 
32 #include "instrumentfilehandler.h"
33 #include "voice.h"
34 
35 #define STATUS if (Voice::mVerbosity >= 4) qDebug() << "Wave:"
36 #define MESSAGE if (Voice::mVerbosity >= 3) qDebug() << "Wave:"
37 #define WARNING if (Voice::mVerbosity >= 2) qWarning()<<"Wave: WARNING:"
38 #define ERROR if (Voice::mVerbosity >= 1) qCritical() << "Wave: ERROR:"
39 
40 
41 //-----------------------------------------------------------------------------
42 // Constructor
43 //-----------------------------------------------------------------------------
47 
49  : mRepetitionIndex(0)
50  , mRepetitionFactor(1)
51  , mSustainSample()
52  , mReleaseSample()
53  , mSustainShift(0)
54  , mReleaseShift(0)
55  , mEnvelope()
56 {}
57 
58 
59 //-----------------------------------------------------------------------------
60 // Compute a synthetic triangular wave
61 //-----------------------------------------------------------------------------
68 
69 void Wave::computeTriangularWave (double frequency, int samplerate, double stereo)
70 {
71  if (samplerate==0) return;
72  const int N = 1<<20;
73  mReleaseSample.clear();
74  mSustainSample.resize(N);
75  double phaseleft = 2*stereo;
76  double phaseright = - 2*stereo;
77  double amplitude=0;
78  double increment = frequency / samplerate;
79 
80  for (int i=0; i<N/2; ++i)
81  {
82  phaseleft += increment; while (phaseleft>1) phaseleft--;
83  phaseright += increment; while (phaseright>1) phaseright--;
84  amplitude = 32768.0*std::min(500*i,N/2-i)/N*2;
85  mSustainSample[2*i] = amplitude*(phaseleft < 0.5 ? 0.22 - phaseleft : phaseleft-0.72);
86  mSustainSample[2*i+1] = amplitude*(phaseright < 0.5 ? 0.22 - phaseright : phaseright-0.72);
87  }
89  computeEnvelope(samplerate);
90 }
91 
92 
93 //-----------------------------------------------------------------------------
94 // Insert waveform (called from importer)
95 //-----------------------------------------------------------------------------
96 
97 bool Wave::insert(const QVector<qint32> &L, const QVector<qint32> &R,
98  const bool release, const double amplitude)
99 {
100  // Find the maximal amplitude
101  qint32 maximalAmplitude = 0;
102  for (auto &a : L) if (abs(a)>maximalAmplitude) maximalAmplitude=abs(a);
103  for (auto &a : R) if (abs(a)>maximalAmplitude) maximalAmplitude=abs(a);
104 
105  // Count by how many bits the max amplitude exceeds a 16bit integer
106  int shift = 0;
107  while (maximalAmplitude & 0x7FFF8000) { shift++; maximalAmplitude >>= 1; }
108  int divisor = (1<<shift);
109 
110  // Specify an amplitude shift for playback
111  int ampshift = 0;
112  if (amplitude > 1) ampshift = round(log(amplitude)/log(2.0));
113  else divisor <<= static_cast<int>(round(-log(amplitude)/log(2.0)));
114 
115  // Make sure that there are no more than 2^20 frames
116  int N=L.size();
117  if (N > (1<<20))
118  {
119  qDebug() << "Wave::insert: Wave size" << L.size() << "exceeds 2^20";
120  return false;
121  }
122 
123  if (release)
124  {
125  mReleaseSample.resize(2*N);
126  mReleaseShift = shift + ampshift;
127  for (int i=0; i<N; i++)
128  {
129  mReleaseSample[2*i] = static_cast<qint16>(L[i]/divisor);
130  mReleaseSample[2*i+1] = static_cast<qint16>(R[i]/divisor);
131  }
132  }
133  else // if wave
134  {
135  mSustainSample.resize(2*N);
136  mSustainShift = shift + ampshift;
137  for (int i=0; i<N; i++)
138  {
139  mSustainSample[2*i] = static_cast<quint16>(L[i]/divisor);
140  mSustainSample[2*i+1] = static_cast<quint16>(R[i]/divisor);
141  }
142  if (N == (1<<20))
143  {
144  STATUS << "Compute envelope and perform automatic cyclic morphing";
145  computeEnvelope(44100); // real sample rate required
147  }
148  }
149  return true;
150 }
151 
152 //-----------------------------------------------------------------------------
153 // Write a wave to disk
154 //-----------------------------------------------------------------------------
160 
161 bool Wave::write(QIODevice &iodevice)
162 {
163  STATUS << "Writing PCM to QIODevice";
164  // Write tag and repetition indices
165  const int tag=0x11111111;
166  if (not InstrumentFileHandler::write(iodevice,tag)) return false;
169 
170  // Encapsulate writing process in a local function:
171  auto writeWaveform = [&iodevice] (QVector<qint16> &wave)
172  {
173  InstrumentFileHandler::write(iodevice,wave.size());
174  if (wave.size()>0)
175  {
176  QByteArray data = QByteArray::fromRawData(
177  reinterpret_cast<const char*>(wave.constData()),
178  sizeof(qint16) * wave.size());
179  // Compress data before writing
180  QByteArray compressed = qCompress(data,9);
181  InstrumentFileHandler::write(iodevice,compressed.size());
182  STATUS << "Compressing" << 2*wave.size() << "->" << compressed.size();
183  int bytes = static_cast<int>(iodevice.write(compressed));
184  if (bytes != compressed.size())
185  {
186  ERROR << "Could not write compressed data";
187  return false;
188  }
189  }
190  return true;
191  };
192 
193  if (not writeWaveform(mSustainSample)) return false;
195  if (not writeWaveform(mReleaseSample)) return false;
197  return true;
198 }
199 
200 
201 //-----------------------------------------------------------------------------
202 // Read a wave from disk
203 //-----------------------------------------------------------------------------
212 
213 bool Wave::read(QIODevice &iodevice)
214 {
215  // First verify tag and read the repetition indices
216  int tag=0;
217  if (not InstrumentFileHandler::read(iodevice,tag) or tag!=0x11111111) return false;
220 
221  // Reading is encapsulted in the following local function
222  auto readWaveform = [&iodevice] (QVector<qint16> &wave)
223  {
224  int uncompressedSize=0, compressedSize=0;
225  InstrumentFileHandler::read(iodevice,uncompressedSize);
226  if (uncompressedSize==0) wave.clear();
227  else
228  {
229  InstrumentFileHandler::read(iodevice,compressedSize);
230  if (QThread::currentThread()->isInterruptionRequested()) return false;
231  QByteArray array = iodevice.read(compressedSize);
232  QByteArray uncompressed = qUncompress(array);
233  if (uncompressed.size() != 2*uncompressedSize)
234  {
235  WARNING << "WaveForm::read: incompatible sizes. File corrupted?";
236  return false;
237  }
238  wave.clear();
239  wave.resize(uncompressedSize);
240 #if defined(Q_OS_WINRT)
241  // In WinRT memcpy is not allowed for security reasons
242  for (int i=0; i<uncompressedSize; i++)
243  { wave[2*i]=uncompressed[i]%256; wave[2*i+1]=uncompressed[i]/256; }
244 #else
245  memcpy(&wave[0], uncompressed.constData(), uncompressed.size());
246 #endif
247  if (QThread::currentThread()->isInterruptionRequested()) return false;
248  STATUS << "Uncompressing" << compressedSize << array.size()
249  << "->" << 2*uncompressedSize << uncompressed.size();
250  }
251  return true;
252  };
253 
254  if (not readWaveform(mSustainSample)) return false;
256  if (not readWaveform(mReleaseSample)) return false;
258 
259  computeEnvelope(44100); // sample rate needed ******************************* ********** !!!!!!!!!!!!!!!!!!!!!
260 
261  return true;
262 }
263 
264 
265 
266 //-----------------------------------------------------------------------------
267 // Write a short summary of the wave data to qDebug()
268 //-----------------------------------------------------------------------------
273 
274 void Wave::printInfo(int keynumber)
275 {
276  if (mSustainSample.size()==0) return;
277  qDebug() << " Key" << keynumber << ": Waveform containing"
278  << mSustainSample.size()/2 << "frames" << "Repetition data"
280 }
281 
282 
283 //-----------------------------------------------------------------------------
284 // Determine the envelope of the sustain wave
285 //-----------------------------------------------------------------------------
290 
291 void Wave::computeEnvelope(int samplerate)
292 {
293  const double damping = 0.0007;
294  const quint32 mask = envelopeWidth-1;
295  mEnvelope.resize((mSustainSample.size()-1)/envelopeWidth+1);
296  double slidingPower = 0;
297  int equilibrationsize = qMin(mSustainSample.size(),samplerate/3);
298  for (int index = 0; index < equilibrationsize; ++index)
299  slidingPower = slidingPower*(1-damping) + mSustainSample[index]*mSustainSample[index]*damping;
300  for (int index = 0; index < mSustainSample.size(); ++index)
301  {
302  slidingPower = slidingPower*(1-damping) + mSustainSample[index]*mSustainSample[index]*damping;
303  if ((index & mask) == mask) mEnvelope[index/envelopeWidth] = sqrt(slidingPower);
304  }
305  mEnvelope[mEnvelope.size()-1] = sqrt(slidingPower);
306 }
quint32 mRepetitionIndex
Index from where on the sample is repeated.
Definition: wave.h:79
Wave()
Constructor, resetting member variables.
Definition: wave.cpp:48
QVector< double > mEnvelope
Amplitude envelope.
Definition: wave.h:85
#define WARNING
Definition: wave.cpp:37
QVector< qint16 > mSustainSample
Sound sample when key is pressed.
Definition: wave.h:81
const int envelopeWidth
Frames per envelope point.
Definition: wave.h:92
int mReleaseShift
PCM amplitedes shifted # bits to the left.
Definition: wave.h:84
void printInfo(int keynumber=0)
Debugging function: Write a short summary of the wave data to qDebug()
Definition: wave.cpp:274
void automaticCyclicMorphing()
Function defined externally (Importer)
bool insert(const QVector< qint32 > &L, const QVector< qint32 > &R, const bool release, const double amplitude)
Definition: wave.cpp:97
void computeEnvelope(int samplerate)
Determine the envelope of the sustain wave.
Definition: wave.cpp:291
QVector< qint16 > mReleaseSample
Sound sample when key is releasek.
Definition: wave.h:82
bool read(QIODevice &iodevice)
Read a wave from disk.
Definition: wave.cpp:213
bool write(QIODevice &iodevice)
Write a PCM wave to disk (QIODevice)
Definition: wave.cpp:161
#define ERROR
Definition: wave.cpp:38
static bool read(QIODevice &iodevice, const T &object)
void computeTriangularWave(double frequency, int samplerate, double stereo)
Compute a synthetic triangular wave.
Definition: wave.cpp:69
double mRepetitionFactor
Amplitude decrease factor upon repetition.
Definition: wave.h:80
int mSustainShift
PCM amplitudes shifted # bits to the left.
Definition: wave.h:83
#define STATUS
Definition: wave.cpp:35
static bool write(QIODevice &iodevice, const T &object)