Just Intonation  Version 1.3.0 (18)
Explore scale-independent dynamically adapting tuning in just intonation
sampler.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 // Sampler
22 //=============================================================================
23 
24 #include "sampler.h"
25 #include "tone.h"
26 #include "soundgenerator.h"
27 #include "tuner/tuner.h"
28 
29 //-----------------------------------------------------------------------------
30 // Constructor
31 //-----------------------------------------------------------------------------
32 
36 
38  : AudioGenerator()
39  , pSoundGenerator(nullptr)
40  , pTones(nullptr)
41  , mLeft((uint)mMaxNumberOfFrames)
42  , mRight((uint)mMaxNumberOfFrames)
43 {}
44 
45 
46 //-----------------------------------------------------------------------------
47 // Init
48 //-----------------------------------------------------------------------------
49 
55 
56 void Sampler::init (SoundGenerator *soundgenerator)
57 {
58  pSoundGenerator = soundgenerator;
59  if (not soundgenerator)
60  {
61  qDebug() << "Sound generator pointer invalid";
62  return;
63  }
64  pTones = soundgenerator->getTones();
65 }
66 
67 //-----------------------------------------------------------------------------
68 // Essential sound-generating function of the sampler
69 //-----------------------------------------------------------------------------
70 
80 
81 size_t Sampler::generateSound(char *buffer, size_t maxSize)
82 {
83  //************ Determine parameters *************
84 
85  // Overall volume factor
86  constexpr double volumeFactor = 32;
87 
88  // 2 bytes (PCM16, Linux) or 3 bytes (PCM24, MAC)
89  uint bytes = (mParameters.sampleSize==16 ? 2:3);
90 
91  // number of frames to be generated
92  size_t frames = std::min(maxSize/bytes/2,mMaxNumberOfFrames);
93  if (frames==0) return 0;
94 
95  // get pointers to arrays used for superposition
96  qint32* leftarray = mLeft.data();
97  qint32* rightarray = mRight.data();
98 
99  // clear the superposition arrays
100  memset(leftarray, 0, sizeof(qint32)*frames);
101  memset(rightarray, 0, sizeof(qint32)*frames);
102 
103 
104  //*************** Compute sound ****************
105 
106  // Loop over all tones computing the superposition
108  for (Tone &tone : *pTones) if (tone.mState != Tone::State::TERMINATED)
109  {
110  qint32 volume = static_cast<qint32>(volumeFactor*tone.mVolume);
111 
112  Wave &sample = tone.getSample();
113  const QVector<qint16>* pcm;
114  if (tone.mType == Tone::Type::RELEASETONE)
115  {
116  pcm = sample.getReleaseSample();
117  volume <<= sample.getReleaseShift();
118  }
119  else // main tone
120  {
121  pcm = sample.getSustainSample();
122  volume <<= sample.getSustainShift();
123  }
124  const qint16* waveformpointer = pcm->data();
125  quint32 arrayindexmax = pcm->size();
126  if (arrayindexmax==0) continue;
127  quint32 time = tone.mTime;
128  int key = tone.mKey & 0x7F;
129  quint32 increment = pSoundGenerator->getIncrement(key);
130  quint32 repetitionTime = (tone.pSample->getRepetitionIndex()) << 11;
131  double repetitionFactor = tone.pSample->getRepetitionFactor();
132 
133  qint16 left = tone.left;
134  qint16 right = tone.right;
135  for (size_t j=0; j<frames; j++)
136  {
137  qint32 weight = (time & 0xFFFU) ^ 0xFFFU;
138  qint32 norm = weight | 0x1000U;
139  quint32 arrayindex = (time>>11) & 0x1FFFFEU;
140  left = ((waveformpointer[arrayindex]<<12) + weight*left)/norm;
141  right = ((waveformpointer[arrayindex+1]<<12) + weight*right)/norm;
142  leftarray[j] += volume*left;
143  rightarray[j] += volume*right;
144 
145  time += increment;
146  if (arrayindex >= arrayindexmax-2)
147  {
148  // if a repetition is available
149  if (repetitionTime and tone.mType != Tone::Type::RELEASETONE)
150  {
151  time = (time & 0xFFFU) | repetitionTime;
152  tone.mVolume *= repetitionFactor;
153  volume = static_cast<qint32>(volumeFactor*tone.mVolume);
154  volume <<= sample.getSustainShift();
155  // qDebug() << "Volume = " << tone.mVolume;
156  }
157  else
158  {
159  // qDebug() << "Sampler terminates key (treble shorter than 24sec)";
160  tone.mVolume = 0;
161  time = 0;
162  tone.mState = Tone::State::TERMINATED;
163  break;
164  }
165  }
166  if ((j&0xF) == 0)
167  {
168  if (tone.mState == Tone::State::RELEASED)
169  {
170  tone.mVolume *= 0.99;
171  volume = 99 * volume / 100;
172  }
173  }
174  }
175  tone.left = left;
176  tone.right = right;
177  tone.mTime = time;
178  }
180 
181 
182  //*************** Copy sound to audio ****************
183 
184  // number of bytes to be generated
185  size_t buffersize = 2*frames*bytes;
186 
187  // Clear audio device buffer
188  memset(buffer, 0, buffersize);
189 
190  // Redefine pointer in order to transfer 16 bit in one package
191  qint16* audioptr = (qint16*)buffer;
192 
193  size_t i=0;
194  for (size_t j=0; j<frames; j++)
195  {
196  qint32 signalleft = leftarray[j]>>7;
197  qint32 signalright = rightarray[j]>>7;
198  if (bytes==2)
199  {
200  audioptr[i++] += (qint16)(signalleft>>8);
201  audioptr[i++] += (qint16)(signalright>>8);
202  }
203  else if (bytes==3)
204  {
205  audioptr[i++] += (qint16)(signalleft & 0xFFFFU); // not clear whether addition is correct here
206  audioptr[i++] += (qint16)((signalleft>>16) | ((signalright & 0xFFU)<<16));
207  audioptr[i++] += (qint16)(signalright >> 8);
208  }
209  }
210  //qDebug() << "sampler rendered buffer size = " << buffersize << "/" << maxSize;
211  return buffersize;
212 }
213 
Class managing the generation of sound.
Class holding the sampled sound for one key.
Definition: wave.h:49
int sampleSize
Sample size (16 or 24)
AudioParameters mParameters
Local copy of the audio parameters.
const QVector< qint16 > * getSustainSample()
Definition: wave.h:66
SoundGenerator * pSoundGenerator
Pointer to the SoundGenerator.
Definition: sampler.h:67
QVector< qint32 > mRight
Audio signal to be constructed.
Definition: sampler.h:70
int getReleaseShift()
Definition: wave.h:68
Virtual base class for audio-generating modules.
Class describing a tone that is currently being played.
Definition: tone.h:45
Sampler()
Constructor of the Sampler without functionality.
Definition: sampler.cpp:37
size_t generateSound(char *charbuffer, size_t maxSize) override final
Essential sound-generating function of the sampler.
Definition: sampler.cpp:81
int getSustainShift()
Definition: wave.h:69
void init(SoundGenerator *soundgenerator)
Initialization of the sampler.
Definition: sampler.cpp:56
const QVector< qint16 > * getReleaseSample()
Definition: wave.h:67
size_t mMaxNumberOfFrames
Maximal number of frames per buffer.
QList< Tone > * pTones
Pointer to the list of tones held by SoundGenerator.
Definition: sampler.h:68
QVector< qint32 > mLeft
Definition: sampler.h:70
quint32 getIncrement(int key)