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.
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.
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.
a waveform object (array of 'h') can be passed in, replacing the
standard square wave. This waveform must be a 'single cycle waveform'
and some obvious things to pass in are sine, triangle or sawtooth waves,
but you can construct whatever you like.
Originally, black_bindings found each contiguous "//|" block and sent
it to black independently. This was slower than it needed to be.
Instead, swap the comment prefix: when running black, take off
"//|" prefixes and put "##|" prefixes on all un-prefixed lines.
Then, after black is run, do the opposite operation
This more than doubles the overall speed of "pre-commit run --all",
from 3m20s to 55s CPU time on my local machine (32.5s to under 10s
"elapsed" time)
It also causes a small amount of churn in the bindings, because
black now sees enough context to know whether one 'def' follows another
or ends the 'def's in a 'class'. In the latter case, it adds an extra
newline, which becomes a "//|" line.
I'm less sure why a trailing comma was omitted before down in
rp2pio/StateMachine.c but let's roll with it.