Open dpwe opened 3 months ago
Brian's idea is to use the voices
system to allocate a voice that holds down the needed oscs. For instance, to reserve 4 voices you can do something like amy.send(voices=NEW_NUMBER, store_patch="v0Zv1Zv2Zv3Z")
. AMY will detect that the "patch" requires 4 oscs, and will allocate and hold those oscillators (somewhere). Then, to use those oscs, subsequent calls to amy.send()
simply need to include voices=NEW_NUMBER
.
The user is still required to manage the allocation of voices numbers. This is what midi.Synth.allocated_amy_voices
does, but currently that's specifically oriented to the patch-based synths. We might want to separate out that manager so it can be used by SingleOscSynthBase
and direct use of AMY oscs.
Inspecting debug
output, this doesn't actually work at the moment (no oscs show up as allocated), but that's just bugs:
amy.reset()
amy.send(store_patch="1024,v0Zv1Zv2Zv3Z")
amy.send(voices="0", patch=1024)
amy.send(debug=99)
which gives the output that ends with:
osc_to_voice:
0: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
16: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
32: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
48: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
64: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
80: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
96: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
112: 255 255 255 255 255 255 255 255
memory_patch 0 oscs 2 patch v0Zv1Zv2Zv3Z
We notice:
osc_to_voice
table are allocated to any voices.memory_patch
0 (i.e., patch 1024) is detected as constituting only 2 voices.Try it with load_patch
, not patch
?
I fixed up the store_patch
bug in #210 .
I now get the correct behavior, using load_patch
in Tulip:
amy.reset()
amy.send(store_patch="1024,v0Zv1Zv2Zv3Z")
amy.send(voices=0, load_patch=1024)
amy.send(debug=99)
...
voice 0 base osc 60
osc_to_voice:
0: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
16: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
32: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
48: 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0
64: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
80: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
96: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
112: 255 255 255 255 255 255 255 255
memory_patch 0 oscs 4 patch v0Zv1Zv2Zv3Z
Hi Brian, hi Dan, this concept of setting up oscillators for voices via patches looks like a great concept to me. I am about to develop a kind of OSCar-inpired synth using AMY, so I guess this should work to set up let's say 32 partials per "macro-oscillator" for maybe 4-6 voices, correct?
Also I am assuming it could it also be possible to add a filter, lfos, envelopes and maybe even an FM-Algorithm this way too, to be associated with a certain voice? Or is it only meant for "real" oscillators and other building-blocks of voices still would have to be added differently? All the best, Mathias
The wave=amy.PARTIALS
functionality is related to this. However, to some extent PARTIALS
is a throwback to an earlier time when oscs were grabbed without care .. the patches simply grab the next N oscs after the 'parent', where N is specified in the (compiled-in) partials table.
PARTIALS
oscillators will respect pitch (including modulation) and filtering. However, it ignores amplitude envelope (although it does respect vel
).
If we were to get serious about additive synthesis, this part of the engine would need some serious attention!
Ah ok, could you maybe roughly point out how the "best practice" with the new voices/oscillators logic as proposed here would be to allocate lets say 4 voices with 32 partials each, two LFOs and a filter via a wire-protocol command and/or via native Amy events? TBH I understand the intentions, but did not grasp the whole thing entirely. Not having a Volume EG of course is a bit of an issue to build a real synth with these options... (I guess the Breakpoint-EG already is consumed by the partials?) But maybe to only use a Filter EG still could work!
The current operation is that there is a parent osc with wave=amy.PARTIALS
that retrieves a preset partials set, which specifies the total number of partials required. It then grabs the following N oscs and makes them type PARTIAL
(no "S") to act as the modulated sinusoids. The parent osc updates the FM and AM env gen params of each partial as the sound evolves. Filter and pitch modulation of the parent osc end up applying to the sum of the partials; parent amplitude envelope does not, but that's an oversight we can fix.
However I'm unclear what you hope to do in terms of providing the partial coefficients. Right now they are analyzed from audio external to AMY with Loris, then compiled in to the AMY binary. This pretty limited - you probably don't want to have to recompile each time you change a voice. I could imagine code updating the tables at run time, but that's quite a lot of modification.
Thanks for explaining those details about amy.PARTIALS! And yes, I think to have a parent amplitute enverlope would be great, especially if that would work without issues with the output from Loris. Or is the parent oscillator an additional one to what Loris generates from a sample anyways?
Concerning what my intention with additive synthesis would be: I was planning to have lets say four voices with 32 sine oscillators each (pitched according to the harmonic series) , not directly dependant on amy.PARTIALS / Loris. So it would be more kind of inspired by the AT&T Hal Alles Machine (Crumar GDS / DK Synergy II+), or the Kawai K5000 or the OSCar. For instance with the K5000 you can use "formant filters", which are actually macros applied on the (in that case 64) partial-tones. Or you can increase/decrease the volume of only odd or even partial-tones etc. As a first step I imagined to build one or two very simple oscillators similar to those that the OSCar supplies: only changing the volume of the overtones would be needed, no breakpoint-EGs as with the K5000 for a start. But then to add a Master-Filter and a Master Volume EG (in contrast to the aforementioned purely additive designs) would be needed to obtain a working synth I guess.
Oscillators are the fundamental resource in Amy, each able to produce a waveform with modulation etc.
Voices are a higher-level construct grouping multiple oscillators. Musical notes often use multiple oscillators in co-ordination (FM voices are a clear example), and the AMY
voices
/patch_num
mechanism makes this convenient.However, each voice allocated grabs a number of oscs, and the user can't tell which ones (for one thing, the wire protocol is write-only). So it's very hard to mix the use of
voices
andoscs
, because theoscs
you're referencing might be in use by one of your voices.For scenarios that might want to mix using
voices
with rawoscs
, we could provide a mechanism that protected some subset of the oscs from being used by the voices mechanism. For instance, you could reserve the first 20 oscs for direct use, so that the voices allocator only uses oscs 20 and above.We could introduce a new command to reserve oscs. Or, we could figure out some mechanism within the existing wire protocol. For instance, a negative voice number, as the first reference to
voices
after a reset, could reserve the oscillators: