
TODO: -------------------------------------------------------------------------

* 'fork' unit - unity gain panmix without the controls, basically.
	* Have this added automatically when subvoice output doesn't match the
	  parent voice?

* Instructions to wait for a one-shot wave to end, and/or test if it is still
  playing.

* Proper constant power panning in panmix!

* GUI media player style app? Player plugins?

* Positional audio demo!

* Extra package with Win32 binaries + demos!

* Segfault when doing a2_FreeBank() and reloading banks a few times.
	* Only happens in certain cases, apparently in conjunction with some
	  compile errors!
	* The (now commented out) old section of test.a2s seems to trigger it.

* Should not be using FIFOs with offline states! We can push messages directly
  into those, eliminating the overhead, and the risk of buffer overflows.

* New wiring system:
	* A2_structitem has one 8 bit "buffer address code" for each output and
	  each input.
		* Top N bits is a bus index:
			0: Nestlevel scratch buffers
			1: Voice main outputs
			2: Voice effect sends
		* Remaining bits form the buffer ("bus channel") index.
		* We also need something corresponding to A2_IO_WIREOUT - or do
		  we just ignore the above and do what we're doing now instead?
	* Use {...} blocks in struct defs to explicitly define subchains!
		* Any inputs on the first unit, and any outputs of the last
		  unit of the subchain will be wired like inputs of a normal
		  unit in the parent chain.
		* Inter-unit wiring within the chain is done via separate
		  buffers, not interfering with the parent chain, or other
		  chains.
	* Explicit 'mix' directive along with 'wire' in struct definitions!
	  This way we can specify exactly what we mean in a clean way, and the
	  implementation details are left to the engine and units.
	* Unit output mode control registers?
		* Replace
		* Add
		* Multiply
		* Ring modulate

* Logic somewhere (API, core...?) that uses a suitable builtin program when
  someone attempts to play a wave like an instrument!

* Maybe local function calls or subvoice spawnning should have a different call
  syntax? Now they look the same, which is really rather confusing...

* Compiler should fail or at least warn about SET on non control registers!

* Compiler warnings for unused local functions and non-exported programs!

* Voices need to lock banks in place while using them!

* Consistent naming conventions - not a2_FreeThis() and a2_ThatFree()!

* API for detecting available drivers?

* TDELAY* instructions need to use a separate timer/accumulator that deals in
  ticks, eliminating rounding error buildup as long as "clean" delay values are
  used for 'td'.

* WAKE should only have a SLEEPing voice continue execution! The current WAKE
  behavior should be a different instruction; "FORCE-if-sleeping" or similar.
  Or we should just plain remove that, and have FORCE work like the current
  WAKE...?
	NOTE:	FORCE can only ever interrupt SLEEP, END or DELAY instructions
		anyway!

* Panning with Haas effect...?

* Parametric EQ!

* Use BLIT (temporary switch to alternate oscillator implementation) to handle
  the transients when using 'phase'?

* Port a bunch of oscillators from Audiality 1!? (Some would preferably be
  reimplemented using IFFT synthesis and stuff.)
	* A parameter interface might be useful for this. We may not want to
	  implement everything as true control regs, for performance and
	  complexity issue, and the overhead of a larger register frame. This
	  can be of use for other voice structure units and FX units as well!

* Forward declarations of functions, for mutual recursion...?

* Make the VM PC a straight pointer...?
	* We trust the VM code to be safe and correct anyway! No change there.
	* Need to change branch instructions to PC relative, as they're
	  currently absolute.

* a2_KillSub() is actually a bitch to implement properly...! How do we find and
  release any handles that might be associated with the subvoices?

* Voices with no message handlers should just die, or at least stop processing
  entirely in the END instruction!
	* Should probably have different instructions, so we can have programs
	  explicitly do this even when they do have handlers.
	* Maybe we should also have a non-processing sleep state from which
	  voices can be woken up by messages?

* Simple VM optimization:
	* Add an extra set of register write instructions (arith etc), so we
	  have one for control registers and one for temp/var registers.
	* Move the a2_RTMark() inline first in each instruction implementation.
	* Put the labels for the temp/var variants after the a2_RTMark()s.
	* Have a2c_Code() check which instruction variant to use!

* Unloading objects is an ugly hack. Three basic options:
	1) Insta-kill all voices whenever unloading anything that the realtime
	   context *might* be using. (What we do now.)
	2) Scan the whole graph and kill any voices using the objects that are
	   being destroyed.
	3) Refcount everything on the realtime side as well, and just detach
	   released handles on the API side.

* Releasing objects that don't belong to you is not very nice - but maybe the
  engine should handle it to some extent? There should at least not be crashes.

* Could we pre-allocate a range of handles that the VM can use for juggling
  live instantiated objects...?
	* We'd add a realtime handle "sub-manager" with its own LIFO stack of
	  free handles. That way, we're actually dealing with arbitrary
	  individual handles (as opposed to a fixed range), so we can add new
	  handles to the pool as needed. For example, we can send released API
	  handles there instead of back to the API when we're running low. (The
	  API can just add blocks whenever it needs to.)

* Implement TK_STRINGLIT and then wrap that with TK_VALUE etc up as a constant
  expression rule, s we don't have to handle TK_STRINGLIT and TK_STRING all
  over the place.
	* TK_STRINGLIT is handy for 'import' etc as it doesn't create objects!

* Pull in miniz tinfl.c or similar, to directly support compressed scripts?

* Compile time conditionals and stuff using upper case keywords?
	* There should be a way to pass "constants" to modules when loading and
	  compiling them.
	* Constant expression evaluation would be nice to go with this!

* Move builtin programs and waves into their own banks, so they don't pollute
  the namespace of everything!!!

* Add DEBUG instructions for printing info on objects!

* Nick the MIDI file loader/player from the old Audiality? Nice and handy, and
  we could make some tiny but awesome GM patch sets to go with it!
	* Should be wrapped up as some kind of unit or other scriptable object!
	  Thus, we can use MIDI files like any other data from within normal
	  a2s modules, hiding them completely from the API, while providing
	  the same interface and level of control as for "normal" songs.

* Do we even need an initial root voice, or can we just make it a special case
  in a2_Start()?

* We should probably switch to passing filled-out A2_message structs over the
  FIFO (only pointers in the fixed-size FIFO!), and send those messages back
  over a new response FIFO when done with them.
	* Need to keep track of where messages were allocated, as we might be
	  using different memory managers!

* Simple on-demand waves: Register symbols with userdata + callback that the
  compiler runs whenever it hits one of these. This could actually be used for
  anything - not just waves.

* Unit instantiation arguments!!! The compiler can just keep parsing constant
  expressions until end-of-statement - but where to send those figures?
	* Related: Should some stage of the wiring be done by, or specified by,
	  the unit constructors? For example, it would be handy for the panmix
	  unit to specify an additional number of outputs for FX sends - but
	  with just a static list of target codes/indices, this can't be done
	  properly with dynamic configurations, as when using '>'.

* Scratch oscillator! Basically a wtosc that has no frequency register, but
  instead a ramping phase register, making it easy to hit specific waveform
  positions, and also allowing the oscillator to play backwards.

* Reverse feature for wtosc...? Apart from some wave padding trickery (do we
  need the same amount of padding on both ends?), the main issue is that linear
  pitch cannot express negative frequencies.

* Ramping control:
	* Auto mode (default; what we do currently on most control regs):
		* Ramps are automatically calculated when delay instructions
		  are executed, so as to reach the register target values when
		  the VM wakes up again.
	* Instant mode:
		* Changes are applied instantly - no ramping!
	* Asynchronous mode:
		* Ramping speeds are calculated as if constantly aiming a
		  configurable amount of time ahead, rather than being driven
		  by the delay instructions.

* wtosc:
	* Linear ramping of the phase delta per sample

* Granular oscillator:
	* Plays one-shot waveforms, triggering one repetition for
	  each period as controlled by p + sp.
	* Uses an extra register to control actual waveform
	  playback pitch.
	* Use another register for timing randomization?
	* Manual trig mode?

* Why are we getting objects in slot 0, and builtin objects in strange orders?
	* Doesn't seem to cause any trouble...?

* Timing should probably be part of one of the drivers!
	* Not relevant for offline rendering and the like! It's only used by
	  the API when controlling a realtime context.

* 'decimator' unit!
	* Bandlimited downsampling + non-interpolated upsampling.
	* Sample quantization.
	* "Poor electronics" filters? (Separate unit?)
	* "Tiny speaker" simulator? (Separate unit?)

* Multi-sine "organ" waves?
	* FFT based offline waveform generator!
		* We could just strap it on as a tool that uses normal waves as
		  frequency domain data, so we can use the same tools for
		  generating spectra as for generating waveforms.

* A proper IFFT synthesis engine?
	* Could implement that as one or more voice units, probably...
	* Latency and transient response are the major issues with IFFT
	  synthesis - but augmenting it with subsample accurate time domain
	  synthesis might be interesting.

* APIs for transferring or copying objects across master states...?

* Allow subvoices to process audio from their parent voice...? The 'inline'
  unit would need inputs, and subvoices for this would need a special exception
  from the "first unit must have no inputs" rule.

* ChipVoice style auto crossfading twin oscillator!
	* Registers:
		p	Pitch
		a	Amplitude
		phase	Phase (forces BOTH oscillators!)
		detune	Detune for next wave
		gain	Gain for next wave
		w	Wave. Latches 'detune', 'gain' and 'time', and starts
			the crossfade!

* Implement/prototype as A2S?
	* WonkyVerb - multitap feedback delay network with modulated taps.
	* WeirdoVerb:
		* Set up a pool of fragment buffers.
		* Record input audio into buffers, overwriting, picking from
		  the oldest ones in the pool with a slight fuzz factor.
		* Apply a triangular or Hann window or similar to the buffers!
		* At random intervals, play buffers at slightly random pitch,
		  volume and pan positions.
		* Maybe add some randomized resonant filtering and other FX?
		* Normalize recording levels with a fast compressor/limiter,
		  wired to a slow envelope tracker, to more or less eliminate
		  transients?

* Realtime groove transforms for tick timing!!!

* Structures!
	* Global registry of named structure types! Make them module objects?
	* Instruction for getting and typechecking instances.
	* Compiler does static compile time typechecking and just adds the
	  fields to a namespace, much like how named units are handled.

* Environments! (Structs, basically.)
	* Whenever a program of a module is started as top level, an
	  environment instance is created.
	* When a program is started on a subvoice, it gets access to the
	  environment instance from the nearest program of the same module up
	  the processing tree.
	* Declared per CSL module; valid in all programs in the module.
		* Alternatively, we declare environments as typed structures,
		  and declare in each program which environment type (if any)
		  it should use.
			* Could implement environments as module objects, and
			  just add a VM instruction GETENV that creates or gets
			  the nearest environment of the specified type.

* Fast initialization mechanism for hardcoded VM and control registers?

* Control register write callbacks should probably be set by the Initialize
  callback, just like the Process callback... Different configurations may call
  for different register implementations.

* The FORCE instruction is expected to read back the current state of
  interrupted control ramps in progress, but we need proper register read
  callbacks in the unit API for this!

* Simply add an array similar to the groups, for master fx busses? These would
  theoretically run ordinary programs, although they're fed with audio from
  send units all over the graph, in the same way a normal voice gets audio from
  inline processed subvoices.
	* Make sure these are processed last!
	* Can have subvoices, but fx sends won't work reliably on those...
	* FX send units:
		* How do we address the fx busses? For positional sound effects
		  and instruments with per-voice send levels, it would be handy
		  if the output bus could be selected at spawn, rather than
		  hardwired into the voice program.
	* FX busses on the API/compiler level:
		* Can be module local or exported, like programs.
		* Bound to objects, like waves, programs etc.
		* Is the root voice an FX bus...? We need to be able to
		  explicitly send audio there anyway. And it needs master
		  effects, like compressor/limiter.

* Instructions + syntax for indexing and interpolating values out of waveforms!
	* Period and/or sample oriented versions?
	* Probably obey looping flags, plain and simple...
	* Mipmap level selection?

* Tables!
	* Constant and/or dynamic...?
	* Linked lists of chunks for dynamic sizing?
	* Initialization constructs:
		* Compile time table construction?
		* Run-time construction? Could use the register field to
		  encode element count, to avoid instruction decoding
		  overhead.
	* Indexing and interpolation instructions + code syntax.

* Separate driver interface destruction from Close() method?

* Three operand instructions! A constant table instead of immediate values
  would  make room for that nicely, and avoid the nasty f20 numbers.
  Alternatively, we add another word to instructions with an immediate
  value argument.

* CS_PCPULOADAVG seems to report roughly 50% of the load that is reported
  by JACK...

* What's with the regular 60+% spikes in the CPU load in cstest?

* Per-program analysis tool for optimizing songs and sound effects!

---------------------------------------------------------------------------

Structure sizes as of 20120905, 0.2.0:
CS_object:      4
CS_wave:        144
CS_bank:        32
CS_program:     368
CS_stackentry:  136
CS_voice:       544
CS_oscillator:  48
CS_panmixer:    32
CS_message:     56
CS_block:       256

---------------------------------------------------------------------------

* File system driver interface, so we can use PhysicsFS and the like?

* What's with the a2c_SkipLF()s in various constructs? Aren't we supposed to do
  free formatting, since the braces are required anyway?

* Minus before literal is always unary unless followed by whitespace. Might be
  a bit annoying if one doesn't have a habit of always surrounding operators by
  spaces anyway.

* Sleeping voices should not burn CPU! Also, inaudible voices should optimize
  away audio rendering, filters etc. Handy for continuous sound effects and the
  like - though that might be tricky to implement. Basically, we need to keep
  the VM running as usual to have it in the right state if/when it's time to
  wake it up again. Which means, doing mostly nothing, unless it's a VM
  intensive sound, so it could be a massive win.

* VM command to have a voice force detach and die! Many sounds that need
  realtime control will still go to sleep to never respond again once they
  finish, so no point in having them hang around because someone happens to be
  holding a handle.

* "Multiwaves? Waves that are essentially used like normal waves, but actually
  map to multiple other waves as functions of pitch, amplitude, manual control,
  or just random selection.
     First thought was to use this when pre-rendering sounds with noise and
  other random components, to avoid making the sounds stiff and repetitive.
	* Free running phase! (Seems like we have that already...) We don't
	  want waves to be reset to phase 0 whenever they're switched in. We
	  want the whole "wave bank" to play as one, just cross-fading between
	  "tracks".

* Have the asynchronous API calls return "tracking tickets" that can be used
  for reference if errors occur, to check delivery status etc?

* Programs must be able to send messages back to the API!!!

* Binary files! Make the compiler optional. Packed VM code? Or is it better to
  just leave that to lzma or bzip2? Hint: Just dropping the null bytes actually
  makes the compressed file one byte larger in a naive test...! Theoretically,
  the only thing that can shrink compressed results is removing actual
  information. If we use Huffman encoding based on VM instruction use frequency,
  we remove the need for the compressor to store the results of a similar
  analysis in each file. That might save a few bytes.

* Editor/synth application with:
	* ALSA and/or other MIDI interface
	* Code editor
		* MIDI record feature that just inserts code based on some
		  switches and settings! Example:
			td %qdelta
			%vvid:piano %pitch %vel
	* Interactive VM debugger
	* Voice status visualization
	* Live multi-voice visualization in the code editor!
		* Overlay voice status boxes with oscilloscopes, most
		  interesting regs etc, and use lines or arrows to indicate
		  where they are in the code.
		* Use loop arrows and/or afterglow to visualize code that runs
		  too fast for realtime display.
		* Use a bunch of simple filters to eliminate silent voices,
		  voices running, or not running, specific programs etc.

---------------------------------------------------------------------------
BUGS:
	* Timing should be managed centrally somehow, to avoid voices
	  drifting apart due to rounding errors. Then again, this is not
	  a real issue unless we have independent threads running in
	  parallell for "ages" without occasional re-synchronization.

	* Rip the MIDI code out! It belongs in the test programs, or as
	  some sort of optional add-on module...
		* MIDI should use one sub-group per channel, to allow
		  proper implementation of channel-wide controllers.

	* CPU load and related properties and pretty much broken, as
	  SDL_GetTicks() has way too low resolution for measuring such
	  short intervals as the audio callback.

	* There is a detach chain reaction that causes some minor issues;
	  if a program is detached, it can still receive broadcast
	  messages for as long as it hangs around. Now, if that program
	  just starts a few other programs and then goes to sleep, the
	  'sleep' will abort and the voice will 'return' - detaching all
	  subvoices! This means that the program can no longer control
	  it's subvoices, despite being able to receive messages.
	     Now, you're not *really* supposed to talk to detached voices,
	  so we pretty much have this coming if we do. However, this is
	  illogical and inconcistent. We should either not be able to
	  control detached voices AT ALL, or it should work as expected
	  (ie, it works as long as the voices stick around) at all times.

	* Undefined forward declarations give nasty error messages. Will
	  need to report based on the offending fixups somehow. Store
	  source code position in them?

	* Compile errors just abort compilation, but any code generated,
	  symbols exported etc until the point of the error are left
	  around! Can result in "interesting" programs... :-)

	* There might be an occasional symbol leaked if a compile error
	  occurs in the wrong place. a2c_Grab() should probably wire the
	  symbols up for some sort of garbage collection.

---------------------------------------------------------------------------
Ideas:
	* "Effectively silent" conditional jump? (Checking the amplitude
	  for some "very low" value is rather ugly...) The "silent" level
	  could be configurable (quality option), but programs using this
	  should be designed to handle any valid setting!

	* "Approach" instructions?
		* Linear!
		* Inverse exponential: @x y c ==> +x (y - x * c)

	* 'for' variants; which one(s) do we implement?

		* for <var> { }
			Iterate from the initial value of <var> down to 0,
			using <var> as counter.

		* for <var> <end> { }
			Iterate from 0 through <end>.

		* for <var> <start> <end> { }
			Iterate from <start> through <end>. Direction is
			automatically detected.

		* for <var> <start> <end> <step> { }
			Iterate from <start> through <end> in <step>
			increments. Direction is automatically detected,
			and the sign of <step> is ignored.

	* Conditional to check if a waveform is looped or one-shot!
	  (Mostly for a builtin "PlayWave" program - though one might as
	  well handle that by having cs_Start*() select the appropriate
	  program.)

	* Finish the forward branches - or just drop the labels...? A
	  'switch' would most likely need this. Pretty much anything else
	  can be solved with the existing loops and conditionals - though
	  labels + jumps might actually be less messy sometimes. We have
	  no memory management to worry about here, so the situation
	  differs slightly from that of general purpose languages...

	* Multichannel routing:
		* We have a stack of mixing buffers, covering the maximum
		  supported channel count, and some temporary buffers.
		* Within a voice, units just deal with whatever number of
		  voices they are designed for - so, units need to be
		  combined correctly, inserting splitters and mixers as
		  needed.
		* Similarly, subvoices need final output stages that mix
		  into the parent's buffers appropriately. How do we
		  select them...?

	* Audio rate windows/envelopes for granular synthesis? Or just make
	  it AM with two normal oscillators? Slightly heavier, but much
	  more flexible and generally useful. On the plus side, it's very
	  easy to add; just spawn a child voice that modulates our output
	  instead of adding into it.

	* An .a2s file might want to provide hints as to how many voices,
	  stack entries, various kinds of units and stuff like that it may
	  need, so we can pre-allocate sufficient resources to handle it
	  in a realtime safe manner.

	* Basic, textbook PWM pulse implementation:
		* Have a Dirac impulse oneshot wave
		* Control PW with oscillator pitch
		* Control pitch with impulse frequency
	    Problems:
		* PW needs to be restricted at high pitches to avoid
		  aliasing as oscillator "retrig" cuts into the band-
		  limited transients of the waveform.
		* DC offset... We could work around that by making the
		  impulse -1, 1, -1, and extend the latter -1 part enough
		  that the waveform never ends before we retrig.

	* A default tick setting per bank would be handy... The default
	  tick would be used whenever the parent voice/group has a zero
	  tick duration. If the bank doesn't have a default, the engine's
	  global default is used, and that can be changed by the host
	  application.

	* Alternative instrument control approach to consider:
		* A program implements a full "MIDI style" voice - mono or
		  poly! Arguments are init parameters only.
		* Selecting an instrument is starting a single voice with
		  one of those programs. This can initialize output
		  routing and whatnot.
		* Notes are started and controlled entirely using messages
		  to the "master program". The program implements mono,
		  poly, arpeggiatos etc.
	  For a monophonic instrument, the net result is essentially what
	  we have already. For a polyphonic instrument, the main program
	  would be more like the current song "patterns" (only spawns and
	  controls other voices), but would do it's job mainly based on
	  received messages.
	     Do we need extra language features for this? How do we manage
	  voices in polyphonic instruments? Is it sufficient to just take
	  voice IDs as message arguments, and use them directly as VM
	  subvoice IDs? Some 32 IDs should be enough, but mapping from
	  MIDI becomes less trivial than it is with 128+ IDs, like we have
	  in the API.

	* Conditional jump to sense if the voice has been detached! We may
	  want to do stuff, rather than just SLEEPing.
	     Alternatively, we can define an optional message that is sent
	  to a voice as it's detached. That is, in fact, a much more
	  powerful solution, as it can abort long delays and loops if
	  desired - and it can also just set a variable, effectively
	  implementing the conditional jump variant.

	* 'mac' for defining macros that are pasted as text into the
	  source. (Need stack for the source reading interface.)

	* Forward declarations of programs! (There are workarounds...)

	* RNG control instructions? We might want to separate the noise
	  generator from the RAND* instructions, as the noise generator's
	  consumption may vary depending on sample rate and ChipSound
	  version.

	* Realtime control API!
		* We need a callback that runs from the audio callback.
		* We could open up the message subsystem, allowing this
		  callback to receive messages from the application.

		Or, we use user defined, native code voices for this.
		These would be started and controlled much like any other
		voices, and can start other voices and send and receive
		messages to/from other voices.

	* Tables? Functions! Would be very handy for feeding simple loops
	  with sequenced data, instead of unrolling the loops or trying to
	  calculate the data. Obviously, we would also have various math
	  functions, waveforms, perlin noise and whatnot. Using waves as
	  tables would also be possible.

	  One would use various instructions to index
	  the tables in different ways; interpolation types, clamping/
	  wrapping etc.

		IND[I][W] r f i
			Set r to f(i), where IND* grabs the nearest point,
			INDI* uses linear interpolation, and IND*W uses
			wrapping (rather than clamping) at the ends of a
			finite range function.

		READ[W] r f i
			Set r to f(i), and the increment i by 1.

		Asm syntax:
			r f(i[+])[i][w]
			(add|sub|mul) r f(i[+])[i][w]

	  Table definition:
		name [ values... ]	// List of the usual real values
		name "string"		// One [0..255] value per char

		tab notes [0 1 1 0 1 0 0 1]
		for x 0 7
		{
			p (notes[x] * p2 + p1); + x 1; tdelay 8
		}

		'c' that parses into a single [0..255] value would be
		handy as well.

	  We could construct a SWITCH instruction based on this, but we
	  should probably not make those tables publically available, as
	  that could send the VM anywhere...!
		switch <expr> <label> [<label>...]

	* Reverse playback of waveforms...? (Needs some minor extra logic,
	  but no major issues... I think.)

---------------------------------------------------------------------------
OPTIMIZATIONS:
	* VM push/pop should only save registers that are actually
  	  clobbered by the callie! (Performance optimization...)

	* MUL2, MUL3, ADD2, ADD3 etc, for quick construction of
	  the final output of envelopes, LFOs, volume, velocity
	  etc to control regs?

	* The 'inscount' safety thing only needs to count in flow
	  control instructions. And, it shouldn't really be needed
	  for production VM code anyway, so maybe use it only in
	  DEBUG builds and authoring software?

	* case OP_AMOVE4:
		carg[reg + 3] = v->r[(arg >> 15) & 0x1f];
	  case OP_AMOVE3:
		carg[reg + 2] = v->r[(arg >> 10) & 0x1f];
	  case OP_AMOVE2:
		carg[reg + 1] = v->r[(arg >> 5) & 0x1f];
	  case OP_AMOVE:
		carg[reg] = v->r[arg & 0x1f];
		break;

	* Build a peephole optimizer right into a2c_Code()?
		* Keep a "last break" position in the state.
		* When declaring a label, program or other jump target,
		  reset the last break pos to 0.
		* Reset the last break pos after issuing a branch, return
		  or other "exit".
		* When issuing an instruction, run peephole optimization
		  from the last break to the new instruction. If we deal
		  only with two instructions at a time, we only need to
		  check that "last break" is non-zero before optimizing.

--------------------------------------------------------------------------
