Previously, negative amplitudes were clamped to zero.
Now, they are allowed to range from -ALMOST_ONE to +ALMOST_ONE.
This is useful in certain circumstances, such as using synthio
to create CV-like outputs that can be positive or negative, by
using the amplitude property of the note.
Apply envelope & panning after biquad filtering.
This may fix the weird popping problem. It also reduces the number
of operations that are done "in stereo", so it could help performance.
It also fixes a previously unnoticed problem where a ring-modulated
waveform had 2x the amplitude of an un-modulated waveform.
The test differences look large but it's because some values got changed
in the LSB after the mathematical divisions were moved around.
When there's no sustain, the release step needs to be calculated from
the attack level, not the sustain level. Otherwise, contrary to intent,
this leads to the actual release taking a loooonnngg time.
A note can be placed in the center (panning=0) or moved to just the left
(panning=1) or right (panning=-1) channels. Fractional panning values
place it partially in both channels.
this has the side effect of making some notes more accurate, the new
frequency= value in the test is closer to the true midi frequency of
830.609...Hz.
and re-vamp overall envelope calculation again.
Now, if you set a low overall attack level like 0.2 this avoids the
"diminishing volume" effect when many notes sound at once. You need
simply choose a maximum attack level that is appropriate for the max
number of voices that will actually be played.
.. and account releasing notes at their sustain level until they're
done.
this ameliorates the effect where multiple releasing notes
don't seem to actually be releasing, but stay at a constant volume.
This class allows much more expressive sound synthesis:
* tremolo & vibrato
* arbitrary frequency
* different evelope & waveform per note
* all properties dynamically settable from Python code
This works for me (tested playing midi to raw files on host computer, as
well as a variant of the nunchuk instrument on pygamer)
it has to re-factor how/when MIDI reading occurs, because reasons.
endorse new test results
.. and allow `-1` to specify a note with no sustain (plucked)
In contrast to MidiTrack, this can be controlled from Python code,
turning notes on/off as desired.
Not tested on real HW yet, just the acceptance test based on checking
which notes it thinks are held internally.