/*******************************************************************************
*  Copyright 2007 - 2011, Philip S. Considine                                  *
*  This program is free software: you can redistribute it and/or modify        *
*  it under the terms of the GNU General Public License as published by        *
*  the Free Software Foundation, either version 3 of the License, or           *
*  (at your option) any later version.                                         *
*                                                                              *
*  This program is distributed in the hope that it will be useful,             *
*  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                *
*  GNU General Public License (http://www.gnu.org/licenses/)for more details.  *
*******************************************************************************/

desc:LFO Controlled MIDI Pitch Wheel Generator

slider1:0<0,15,1{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}>MIDI Channel
slider2:0<0,100,1>Max Bend (%)
slider3:1<0,24,0.1>LFO Frequency
slider4:0<0,1,1{Hertz,Beats}>LFO Units
slider5:6<0,9,1{1,2,4,8,16,32,64,128,256,512}>Updates Per Beat
slider6:1<0,1,1{Off,On}>On/Off

////////////////////////////////////////////////////////////////////////////////
@init
statPitch = $xE0;
pitchCentre = 16384;

////////////////////////////////////////////////////////////////////////////////
@slider
slider2 = min(max(slider2, 0), 100);
slider3 = min(max(slider3, 0), 50);

channel = slider1;
valMax = pitchCentre * slider2 * 0.01;
freq = slider3;
units = slider4;
updateFreq = 2 ^ slider5;

// Reset if necessary
slider6 != on ?
(
	on = slider6;
	t = 0;
	updateCounter = 0;
);

////////////////////////////////////////////////////////////////////////////////
@block
updateSamples = srate * 60 / tempo / updateFreq;

units == 0 ? // Hz
(
	sinTemp = 2 * $pi * freq;
)
:
units == 1 ? // Beats
(
	sinTemp = 2 * $pi * tempo / 60 / freq;
);

on ?
(
	active = 1;

	updateCounter + samplesblock >= updateSamples ?
	(	
		updateSamples <= samplesblock ?
		(			
			// Possibly more than one update in the block
			samplesLeft = samplesblock;
			offset = 0;
			while
			(
				offset += updateSamples - updateCounter;
			
				t += (updateSamples - updateCounter) / srate;
				value = pitchCentre + floor(valMax * sin(sinTemp * t));
				
				midisend(offset, statPitch + channel, value);
				samplesLeft -= updateSamples - updateCounter;
				updateCounter = 0;
				samplesLeft >= updateSamples;
			);
			updateCounter = samplesLeft;
			t += updateCounter / srate;
		)
		:
		(
			// Block is smaller than updateSamples, just one update
			offset = updateCounter + samplesblock - updateSamples;

			t += offset / srate;
			value = pitchCentre + floor(valMax * sin(sinTemp * t));

			midisend(offset, statPitch + channel, value);
			updateCounter = samplesblock - offset;
			t += updateCounter / srate;
		);
	)
	:
	(
		// Just update counters
		updateCounter += samplesblock;
		t += samplesblock / srate;
	);
)
:
(
	// Send off value only if not already sent
	active ?
	(
		midisend(offset, statController + channel, target | (offValue << 8));
		active = 0;
	);
);
