@@ -34,6 +34,36 @@ Pipewave::Pipewave(Addsynth& model, int note, float freq)
3434{
3535}
3636
37+ Pipewave::Pipewave (Pipewave& other)
38+ : _model{ other._model }
39+ , _note{ other._note }
40+ , _freq{ other._freq }
41+ , _sampleRate{ other._sampleRate }
42+ , _needsToBeRebuilt{ other._needsToBeRebuilt .load () }
43+ , _attackLength{ other._attackLength }
44+ , _loopLength{ other._loopLength }
45+ , _sampleStep{ other._sampleStep }
46+ , _releaseLength{ other._releaseLength }
47+ , _releaseMultiplier{ other._releaseMultiplier }
48+ , _releaseDetune{ other._releaseDetune }
49+ , _instability{ other._instability }
50+ , _wavetable{ other._wavetable }
51+ , _attackStartPtr{}
52+ , _loopStartPtr{}
53+ , _loopEndPtr{}
54+ {
55+ // Adjust pointers to the copied wavetable.
56+ float * wavetable{ other._wavetable .data () };
57+
58+ const auto attackOffset = other._attackStartPtr - wavetable;
59+ const auto loopStartOffset = other._loopStartPtr - wavetable;
60+ const auto loopEndOffset = other._loopEndPtr - wavetable;
61+
62+ _attackStartPtr = _wavetable.data () + attackOffset;
63+ _loopStartPtr = _wavetable.data () + loopStartOffset;
64+ _loopEndPtr = _wavetable.data () + loopEndOffset;
65+ }
66+
3767Pipewave::~Pipewave () = default ;
3868
3969float Pipewave::getPipeFrequency () const noexcept
@@ -79,6 +109,16 @@ void Pipewave::play(Pipewave::State& state, float* out)
79109 jassert (_loopStartPtr != nullptr );
80110 jassert (_loopEndPtr != nullptr );
81111
112+ if (_needsToBeRebuilt.load ()) {
113+ // Drastic measures - pipe has been retuned while playing.
114+ // Data pointers may be invalid at this point - terminate the voice immediately.
115+ memset (out, 0 , sizeof (float ) * SUB_FRAME_LENGTH);
116+ state.env = Pipewave::Over;
117+ state.playPtr = nullptr ;
118+ state.releasePtr = nullptr ;
119+ return ;
120+ }
121+
82122 float * p = state.playPtr ;
83123 float * r = state.releasePtr ;
84124
@@ -208,7 +248,7 @@ void Pipewave::genwave()
208248 float m = _model.getNoteAttack (_note);
209249
210250 for (int h = 0 ; h < N_HARM; ++h) {
211- float t = _model.getHarmonicAttack (h, _note);
251+ const float t = _model.getHarmonicAttack (h, _note);
212252
213253 if (t > m)
214254 m = t;
@@ -254,38 +294,38 @@ void Pipewave::genwave()
254294 int wavetableLength = _attackLength + _loopLength + _sampleStep * (SUB_FRAME_LENGTH + 4 );
255295 _wavetable.resize (wavetableLength);
256296
257- std::vector<float > _arg (wavetableLength);
258- std::vector<float > _att (wavetableLength);
297+ std::vector<float > arg (wavetableLength);
298+ std::vector<float > att (wavetableLength);
259299
260300 _attackStartPtr = _wavetable.data ();
261301 _loopStartPtr = _attackStartPtr + _attackLength;
262302 _loopEndPtr = _loopStartPtr + _loopLength;
263303
264304 memset (_attackStartPtr, 0 , sizeof (float ) * _wavetable.size ());
265305
266- _releaseLength = (int )(ceilf (_model.getNoteRelease (_note) * _sampleRate / SUB_FRAME_LENGTH) + 1 );
267- _releaseMultiplier = 1 .0f - powf (0 .1f , 1 .0f / _releaseLength);
268- _releaseDetune = _sampleStep * (math::exp2ap (_model.getNoteReleaseDetune (_note) / 1200 .0f ) - 1 .0f );
306+ _releaseLength = (int )(ceilf (_model.getNoteRelease (_note) * _sampleRate / SUB_FRAME_LENGTH) + 1 );
307+ _releaseMultiplier = 1 .0f - powf (0 .1f , 1 .0f / _releaseLength);
308+ _releaseDetune = _sampleStep * (math::exp2ap (_model.getNoteReleaseDetune (_note) / 1200 .0f ) - 1 .0f );
269309 _instability = _model.getNoteInstability (_note);
270310
271311 int k = (int )(_sampleRate * _model.getNoteAttack (_note) + 0.5 );
272312
273- // _arg [i] will contain phase steps along the generated wavetable
313+ // arg [i] will contain phase steps along the generated wavetable
274314
275315 {
276316 float t = 0 .0f ;
277317
278318 // Interpolate from frequency f1 to f0 during the attack
279319 for (int i = 0 ; i <= _attackLength; ++i) {
280- _arg [i] = t - floorf (t + 0 .5f );
320+ arg [i] = t - floorf (t + 0 .5f );
281321 t += (i < k) ? (((k - i) * f0 + i * f1) / k) : f1;
282322 }
283323 }
284324
285325 // Generate phase steps of the sustained loop
286326 for (int i = 1 ; i < _loopLength; ++i) {
287- float t = _arg [_attackLength] + (float )i * nc / _loopLength;
288- _arg [i + _attackLength] = t - floorf (t + 0 .5f );
327+ float t = arg [_attackLength] + (float )i * nc / _loopLength;
328+ arg [i + _attackLength] = t - floorf (t + 0 .5f );
289329 }
290330
291331 float v0 = math::exp2ap (0 .1661f * _model.getNoteVolume (_note));
@@ -302,18 +342,18 @@ void Pipewave::genwave()
302342 v = v0 * math::exp2ap (0 .1661f * (v + _model.getHarmonicRandomisation (h, _note) * (2 .0f * rnd.nextFloat () - 1 .0f )));
303343 k = (int )(_sampleRate * _model.getHarmonicAttack (h, _note) + 0 .5f );
304344
305- if (k > _att .size ())
306- _att .resize (k);
345+ if (k > att .size ())
346+ att .resize (k);
307347
308- attgain (_att .data (), k, _model.getHarmonicAttackProfile (h, _note));
348+ attgain (att .data (), k, _model.getHarmonicAttackProfile (h, _note));
309349
310350 for (int i = 0 ; i < _attackLength + _loopLength; ++i) {
311- float t = _arg [i] * (h + 1 );
351+ float t = arg [i] * (h + 1 );
312352 t -= floorf (t);
313353 m = v * sinf (MathConstants<float >::twoPi * t);
314354
315355 if (i < k)
316- m *= _att [i];
356+ m *= att [i];
317357
318358 _attackStartPtr[i] += m;
319359 }
@@ -408,8 +448,11 @@ Rankwave::Rankwave(Addsynth& model)
408448}
409449
410450void Rankwave::createPipes (const Scale& scale, float tuningFrequency)
411- {
412- _pipes.clear ();
451+ {
452+ for (auto & p : _pipes)
453+ p.clear ();
454+
455+ _pipeSetIndex = 0 ;
413456
414457 const auto fn = _model.getFn ();
415458 const auto fd = _model.getFd ();
@@ -418,9 +461,10 @@ void Rankwave::createPipes(const Scale& scale, float tuningFrequency)
418461 float fbase = tuningFrequency * fn / fd;
419462
420463 for (int i = _noteMin; i <= _noteMax; ++i) {
421- auto pipe = std::make_unique<Pipewave>(_model, i - _noteMin, scale.getFrequencyForMidoNote (i, fbase));
422-
423- _pipes.add (pipe.release ());
464+ for (size_t j = 0 ; j < _pipes.size (); ++j) {
465+ auto pipe = std::make_unique<Pipewave>(_model, i - _noteMin, scale.getFrequencyForMidoNote (i, fbase));
466+ _pipes[j].add (pipe.release ());
467+ }
424468 }
425469}
426470
@@ -431,10 +475,13 @@ void Rankwave::retunePipes(const Scale& scale, float tuningFrequency)
431475 const float fnd = (float )_model.getFn () / (float )_model.getFd ();
432476 jassert (fnd > 0 .0f );
433477
478+ int pipeSetIndex{ _pipeSetIndex.load () };
479+ int nextPipeSetIndex{ (pipeSetIndex + 1 ) % (int )_pipes.size () };
480+
434481 if (g->isMTSEnabled ()) {
435482 // Use MTS provided tuning
436483 for (int i = _noteMin; i <= _noteMax; ++i) {
437- Pipewave* pipe = _pipes[i - _noteMin];
484+ Pipewave* pipe = _pipes[nextPipeSetIndex][ i - _noteMin];
438485 const float f{ g->getMTSNoteToFrequency (i, 0 ) * fnd };
439486
440487 if (pipe->getPipeFrequency () != f) {
@@ -448,7 +495,7 @@ void Rankwave::retunePipes(const Scale& scale, float tuningFrequency)
448495 float fbase = tuningFrequency * fnd;
449496
450497 for (int i = _noteMin; i <= _noteMax; ++i) {
451- Pipewave* pipe = _pipes[i - _noteMin];
498+ Pipewave* pipe = _pipes[nextPipeSetIndex][ i - _noteMin];
452499 pipe->setFrequency (scale.getFrequencyForMidoNote (i, fbase));
453500 pipe->setNeedsToBeRebuilt (true );
454501 }
@@ -457,9 +504,14 @@ void Rankwave::retunePipes(const Scale& scale, float tuningFrequency)
457504
458505void Rankwave::prepareToPlay (float sampleRate)
459506{
460- for (auto * pipe : _pipes) {
507+ int pipeSetIndex{ _pipeSetIndex.load () };
508+ int nextPipeSetIndex{ (pipeSetIndex + 1 ) % (int )_pipes.size () };
509+
510+ for (auto * pipe : _pipes[nextPipeSetIndex]) {
461511 pipe->prepateToPlay (sampleRate);
462512 }
513+
514+ _pipeSetIndex.store (nextPipeSetIndex);
463515}
464516
465517Pipewave::State Rankwave::trigger (int note)
@@ -469,12 +521,14 @@ Pipewave::State Rankwave::trigger(int note)
469521
470522 const int index = note - _noteMin;
471523
472- if (!isPositiveAndBelow (index, _pipes.size ())) {
524+ int pipeSetIndex{ _pipeSetIndex.load () };
525+
526+ if (!isPositiveAndBelow (index, _pipes[pipeSetIndex].size ())) {
473527 jassertfalse;
474528 return {};
475529 }
476530
477- Pipewave* pipe = _pipes[note - _noteMin];
531+ Pipewave* pipe = _pipes[pipeSetIndex][ note - _noteMin];
478532 return pipe->trigger ();
479533}
480534
0 commit comments