kibibu PeerTune
------------------------------

Will adjust the tuning of any synth that has individual note tuning attributes.

To use:
- Add a PeerTune as well as any tunable synth (say, kibibu Green Milk...)
- Right click on the PeerTune machine, and select the tunable synth from the "Apply To" menu
  (Only tunable synths will appear)
- Tweak the sliders, or load some presets.
  (The entire scala archive with <= 12 tones is available)


Note that tuning may only apply to synths when the note is triggered, although this
behaviour is up to individual synth developers. Green Milk, for example, only
calculates tuning when notes are triggered, and will not "retune" an already playing note.

You can target other PeerTunes too, but it will only apply the Detune param to the
Detune Offset attribute of the other PeerTune. This isn't a feature you need to bother
with unless you want to detune a bunch of (individually tuned) PeerTunes at once.
You can't make cyclic chains (eg where PeerTune1 controls PeerTune2, and PeerTune2
controls PeerTune1) so go nuts!

Tip: If the presets don't make any sense to you, there are comments associated with each one.
     Open up the Edit... button from the parameter view.

--- For devs ---

Its pretty easy to add microtuning to your own synths. PeerTune works with attributes
in a kind of "offset from standard note" mode.

Create your tuning attributes to allow values between 0 and 24000, with 12000 meaning
"no shift". Call them "C offset", "C# offset" or similar. As long as the first 2 letters
represent the note (including the space for single char notes!) you'll be fine.

  CMachineAttribute const attrC = { "C offset (cents/10)", 0,24000,12000 };
  CMachineAttribute const attrCs = { "C# offset (cents/10)", 0,24000,12000 };
  etc...

Green Milk and Matilde handle this by having an array of 12 "note pitches". The following
function sets up note pitches from attributes (if the attributes are in aval.notes[])
	
void mi::AttributesChanged()
{
	// update the built-in pitches
	for(int i = 0; i < 12; ++i)
	{
		// note the -12.0f subtracts the 1 octave offset
		notePitches[i] = float(i) + (float(aval.notes[i]) / 1000.0f) - 12.0f;
	}
}

The following functions may be used to convert a buzz note to a "note number"

float mi::mapNote(int octave, int note)
{
	return ((octave * 12.0f) + this->notePitches[note]) - 12.0f;
}

float mi::mapNoteNum(byte buzzNote)
{
	byte octave = buzzNote >> 4;
	byte note = (buzzNote & 0x0F) - 1;

	return mapNote(octave,note);
}

The float "note number" you get can be converted to a real world frequency (in Hz) by:

float frequency = (16.3516f * powf(2.0f, num/12));

--- Detune Attribute ---
You can also add another attribute starting with "Detune", which is a single semitone detune.

  CMachineAttribute const attrDetune = { "Detune Offset (cents)", 0,2000,1000 };

PeerTune will use this rather than detuning all the individual attributes, if it exists.
However, its entirely optional, and peertune will detune your stuff fine without it.
This attribute is how PeerTune adjusts other PeerTunes.

In this case, the mi::AttributesChanged looks more like
void mi::AttributesChanges()
{
	for(int i = 0; i < 12; ++i)
	{
		// note the -13.0f subtracts the 1 octave note offset
		// and the 1 semitone detune offset
		notePitches[i] = float(i) + (float(aval.notes[i] + aval.detune) / 1000.0f) - 13.0f;
	}
}


--- REMEMBER! ---
The attributes must start with capital note letters, and MUST have AT LEAST 2-character names
"C " is ok. "C Offset (cents/10)" is better.

The detune attribute, if it exists, MUST start with "Detune" (case is important).

Also note that PeerTune will generate attributes outside of the min/max range you specify.
Don't be surprised with attributes with negative values. The code above doesn't care about ranges,
and will work fine. If the idea of out-of-range attributes scares you, just set the minimum to -12000
and the max to 36000 or thereabouts. Only the default (12000) is important.

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

Thanks to Btd for allowing others to pick through his code.
This doesn't use the peer control library, but I borrowed Btd's hack code for tweaking attributes.

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

Cameron Foale (kibibu)
http://www.kibibu.com