Just Intonation  Version 1.3.0 (18)
Explore scale-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 
30 #include "instrumentfilehandler.h"
31 #include "voice.h"
32 
33 #define STATUS if (Voice::mVerbosity >= 4) qDebug() << "Wave:"
34 #define MESSAGE if (Voice::mVerbosity >= 3) qDebug() << "Wave:"
35 #define WARNING if (Voice::mVerbosity >= 2) qWarning()<<"Wave: WARNING:"
36 #define ERROR if (Voice::mVerbosity >= 1) qCritical() << "Wave: ERROR:"
37 
38 
39 //-----------------------------------------------------------------------------
40 // Constructor
41 //-----------------------------------------------------------------------------
45 
47  : mRepetitionIndex(0)
48  , mRepetitionFactor(1)
49  , mSustainSample()
50  , mReleaseSample()
51  , mSustainShift(0)
52  , mReleaseShift(0)
53  , mEnvelope()
54 {}
55 
56 
57 //-----------------------------------------------------------------------------
58 // Compute a synthetic triangular wave
59 //-----------------------------------------------------------------------------
66 
67 void Wave::computeTriangularWave (double frequency, int samplerate, double stereo)
68 {
69  if (samplerate==0) return;
70  const int N = 1<<20;
71  mReleaseSample.clear();
72  mSustainSample.resize(N);
73  double phaseleft = 2*stereo;
74  double phaseright = - 2*stereo;
75  double amplitude=0;
76  double increment = frequency / samplerate;
77 
78  for (int i=0; i<N/2; ++i)
79  {
80  phaseleft += increment; while (phaseleft>1) phaseleft--;
81  phaseright += increment; while (phaseright>1) phaseright--;
82  amplitude = 32768.0*std::min(500*i,N/2-i)/N*2;
83  mSustainSample[2*i] = amplitude*(phaseleft < 0.5 ? 0.22 - phaseleft : phaseleft-0.72);
84  mSustainSample[2*i+1] = amplitude*(phaseright < 0.5 ? 0.22 - phaseright : phaseright-0.72);
85  }
87  computeEnvelope(samplerate);
88 }
89 
90 
91 //-----------------------------------------------------------------------------
92 // Insert waveform (called from importer)
93 //-----------------------------------------------------------------------------
94 
95 bool Wave::insert(const QVector<qint32> &L, const QVector<qint32> &R,
96  const bool release, const double amplitude)
97 {
98  // Find the maximal amplitude
99  qint32 maximalAmplitude = 0;
100  for (auto &a : L) if (abs(a)>maximalAmplitude) maximalAmplitude=abs(a);
101  for (auto &a : R) if (abs(a)>maximalAmplitude) maximalAmplitude=abs(a);
102 
103  // Count by how many bits the max amplitude exceeds a 16bit integer
104  int shift = 0;
105  while (maximalAmplitude & 0x7FFF8000) { shift++; maximalAmplitude >>= 1; }
106  int divisor = (1<<shift);
107 
108  // Specify an amplitude shift for playback
109  int ampshift = 0;
110  if (amplitude > 1) ampshift = round(log(amplitude)/log(2.0));
111  else divisor <<= static_cast<int>(round(-log(amplitude)/log(2.0)));
112 
113  // Make sure that there are no more than 2^20 frames
114  int N=L.size();
115  if (N > (1<<20))
116  {
117  qDebug() << "Wave::insert: Wave size" << L.size() << "exceeds 2^20";
118  return false;
119  }
120 
121  if (release)
122  {
123  mReleaseSample.resize(2*N);
124  mReleaseShift = shift + ampshift;
125  for (int i=0; i<N; i++)
126  {
127  mReleaseSample[2*i] = static_cast<qint16>(L[i]/divisor);
128  mReleaseSample[2*i+1] = static_cast<qint16>(R[i]/divisor);
129  }
130  }
131  else // if wave
132  {
133  mSustainSample.resize(2*N);
134  mSustainShift = shift + ampshift;
135  for (int i=0; i<N; i++)
136  {
137  mSustainSample[2*i] = static_cast<quint16>(L[i]/divisor);
138  mSustainSample[2*i+1] = static_cast<quint16>(R[i]/divisor);
139  }
140  if (N == (1<<20))
141  {
142  STATUS << "Compute envelope and perform automatic cyclic morphing";
143  computeEnvelope(44100); // real sample rate required
145  }
146  }
147  return true;
148 }
149 
150 //-----------------------------------------------------------------------------
151 // Write a wave to disk
152 //-----------------------------------------------------------------------------
158 
159 bool Wave::write(QIODevice &iodevice)
160 {
161  STATUS << "Writing PCM to QIODevice";
162  // Write tag and repetition indices
163  const int tag=0x11111111;
164  if (not InstrumentFileHandler::write(iodevice,tag)) return false;
167 
168  // Encapsulate writing process in a local function:
169  auto writeWaveform = [&iodevice] (QVector<qint16> &wave)
170  {
171  InstrumentFileHandler::write(iodevice,wave.size());
172  if (wave.size()>0)
173  {
174  QByteArray data = QByteArray::fromRawData(
175  reinterpret_cast<const char*>(wave.constData()),
176  sizeof(qint16) * wave.size());
177  // Compress data before writing
178  QByteArray compressed = qCompress(data,9);
179  InstrumentFileHandler::write(iodevice,compressed.size());
180  STATUS << "Compressing" << 2*wave.size() << "->" << compressed.size();
181  int bytes = iodevice.write(compressed);
182  if (bytes != compressed.size())
183  {
184  ERROR << "Could not write compressed data";
185  return false;
186  }
187  }
188  return true;
189  };
190 
191  if (not writeWaveform(mSustainSample)) return false;
193  if (not writeWaveform(mReleaseSample)) return false;
195  return true;
196 }
197 
198 
199 //-----------------------------------------------------------------------------
200 // Read a wave from disk
201 //-----------------------------------------------------------------------------
210 
211 bool Wave::read(QIODevice &iodevice)
212 {
213  // First verify tag and read the repetition indices
214  int tag=0;
215  if (not InstrumentFileHandler::read(iodevice,tag) or tag!=0x11111111) return false;
218 
219  // Reading is encapsulted in the following local function
220  auto readWaveform = [&iodevice] (QVector<qint16> &wave)
221  {
222  int uncompressedSize=0, compressedSize=0;
223  InstrumentFileHandler::read(iodevice,uncompressedSize);
224  if (uncompressedSize==0) wave.clear();
225  else
226  {
227  InstrumentFileHandler::read(iodevice,compressedSize);
228  if (QThread::currentThread()->isInterruptionRequested()) return false;
229  QByteArray array = iodevice.read(compressedSize);
230  QByteArray uncompressed = qUncompress(array);
231  if (uncompressed.size() != 2*uncompressedSize)
232  {
233  WARNING << "WaveForm::read: incompatible sizes. File corrupted?";
234  return false;
235  }
236  wave.clear();
237  wave.resize(uncompressedSize);
238  memcpy(&wave[0], uncompressed.constData(), uncompressed.size());
239  if (QThread::currentThread()->isInterruptionRequested()) return false;
240  STATUS << "Uncompressing" << compressedSize << array.size()
241  << "->" << 2*uncompressedSize << uncompressed.size();
242  }
243  return true;
244  };
245 
246  if (not readWaveform(mSustainSample)) return false;
248  if (not readWaveform(mReleaseSample)) return false;
250 
251  computeEnvelope(44100); // sample rate needed ******************************* ********** !!!!!!!!!!!!!!!!!!!!!
252 
253  return true;
254 }
255 
256 
257 
258 //-----------------------------------------------------------------------------
259 // Write a short summary of the wave data to qDebug()
260 //-----------------------------------------------------------------------------
265 
266 void Wave::printInfo(int keynumber)
267 {
268  if (mSustainSample.size()==0) return;
269  qDebug() << " Key" << keynumber << ": Waveform containing"
270  << mSustainSample.size()/2 << "frames" << "Repetition data"
272 }
273 
274 
275 //-----------------------------------------------------------------------------
276 // Determine the envelope of the sustain wave
277 //-----------------------------------------------------------------------------
282 
283 void Wave::computeEnvelope(int samplerate)
284 {
285  const double damping = 0.0007;
286  const quint32 mask = envelopeWidth-1;
287  mEnvelope.resize((mSustainSample.size()-1)/envelopeWidth+1);
288  double slidingPower = 0;
289  int equilibrationsize = qMin(mSustainSample.size(),samplerate/3);
290  for (int index = 0; index < equilibrationsize; ++index)
291  slidingPower = slidingPower*(1-damping) + mSustainSample[index]*mSustainSample[index]*damping;
292  for (int index = 0; index < mSustainSample.size(); ++index)
293  {
294  slidingPower = slidingPower*(1-damping) + mSustainSample[index]*mSustainSample[index]*damping;
295  if ((index & mask) == mask) mEnvelope[index/envelopeWidth] = sqrt(slidingPower);
296  }
297  mEnvelope[mEnvelope.size()-1] = sqrt(slidingPower);
298 }
quint32 mRepetitionIndex
Index from where on the sample is repeated.
Definition: wave.h:79
Wave()
Constructor, resetting member variables.
Definition: wave.cpp:46
QVector< double > mEnvelope
Amplitude envelope.
Definition: wave.h:85
#define WARNING
Definition: wave.cpp:35
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:266
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:95
void computeEnvelope(int samplerate)
Determine the envelope of the sustain wave.
Definition: wave.cpp:283
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:211
bool write(QIODevice &iodevice)
Write a PCM wave to disk (QIODevice)
Definition: wave.cpp:159
#define ERROR
Definition: wave.cpp:36
static bool read(QIODevice &iodevice, const T &object)
void computeTriangularWave(double frequency, int samplerate, double stereo)
Compute a synthetic triangular wave.
Definition: wave.cpp:67
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:33
static bool write(QIODevice &iodevice, const T &object)