Superparticular samchillian: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
Wikispaces>xenjacob
**Imported revision 343572870 - Original comment: **
(No difference)

Revision as of 12:40, 7 June 2012

IMPORTED REVISION FROM WIKISPACES

This is an imported revision from Wikispaces. The revision metadata is included below for reference:

This revision was by author xenjacob and made on 2012-06-07 12:40:57 UTC.
The original revision id was 343572870.
The revision comment was:

The revision contents are below, presented both in the original Wikispaces Wikitext format, and in HTML exactly as Wikispaces rendered it.

Original Wikitext content:

<span class="s1">// ChucK code for Superparticular Samchillian</span>
<span class="s1">// Samchillian idea by Leon Gruenbaum</span>
<span class="s1">// superparticular-ratio implementation by Jacob Barton</span>

// paste these into a new document in miniAudicle, or save text as a .ck to run in command-line

<span class="s1">// change these to match your input/output device</span>
<span class="s1">0 => int inDeviceNum;</span>
<span class="s1">1 => int outDeviceNum;</span>

<span class="s1">class</span> MicroRobinMidiIO
{
MidiIn min;
MidiOut mouse;
MidiMsg inmsg, outmsg;
<span class="s2">0</span> => <span class="s1">int</span> ctr;
//int rr[128][3]; don't think we need this now.
// index = note number?
// column 0 = channel sent to
// column 1 = note number sent
<span class="s1">int</span><span class="s3"> chans[</span><span class="s2">14</span><span class="s3">]; </span>// list of channels used
<span class="s1">float</span><span class="s3"> holds[</span><span class="s2">16</span><span class="s3">]; </span>// pitches of on notes, zero if off.
<span class="s3"> [</span><span class="s2">0</span><span class="s3">,</span><span class="s2">1</span><span class="s3">,</span><span class="s2">2</span><span class="s3">,</span><span class="s2">3</span><span class="s3">,</span><span class="s2">4</span><span class="s3">,</span><span class="s2">5</span><span class="s3">,</span><span class="s2">6</span><span class="s3">,</span><span class="s2">7</span><span class="s3">,</span><span class="s2">8</span><span class="s3">,</span><span class="s2">10</span><span class="s3">,</span><span class="s2">11</span><span class="s3">,</span><span class="s2">12</span><span class="s3">,</span><span class="s2">13</span><span class="s3">,</span><span class="s2">14</span><span class="s3">] @=> chans; </span>//exclude channel 10 (drums) & 16 (send channel)
//microtuning stuff
// PitchBend
// input: pitch (midi note number float) & velocity of desired note
// action: sends appropriate pitchbend message
// (assuming pitchbend range = +/- 2 semitones)
// output: note number required for correct frequency to be realized
// sends pitchbend, assuming +/- wholestep pitchbend range
// returns note number required for correct frequency
<span class="s1">fun int</span> PitchBend(<span class="s1">float</span> pitch, <span class="s1">int</span> velocity)
{
//send pitchbend
<span class="s2">224</span> + chans[ctr] => outmsg.data1;
<span class="s2">0</span> => outmsg.data2;
Math.round((pitch % <span class="s2">1</span>.<span class="s2">0</span>) * <span class="s2">32</span>.<span class="s2">0</span> + <span class="s2">64</span>.<span class="s2">0</span>) $ <span class="s1">int</span> => outmsg.data3;
mouse.send(outmsg);
<span class="s1">return</span> Math.floor(pitch) $ <span class="s1">int</span>;
}
// StartRelay
// input: number of MIDI device, MidiTransform to be used
// creates a loop ~ should be sporked
<span class="s1">fun void</span> StartRelay(<span class="s1">int</span> deviceNum, MidiTransform mt)
{
<span class="s1">if</span>( !min.open(<span class="s2">inDeviceNum</span>)) <span class="s1">me</span>.exit();
<span class="s1">if</span>( !mouse.open(outDeviceNum)) <span class="s1">me</span>.exit();
// print out device that was opened
<<< min.num(), <span class="s4">" -> "</span>, min.name() >>>;
<<< mouse.num(), <span class="s4">" -> "</span>, mouse.name() >>>;
<span class="s1">while</span> ( <span class="s1">true</span>)
{
min => <span class="s1">now</span>;
<span class="s1">while</span>( min.recv(inmsg))
{ 
<span class="s1">if</span>( inmsg.data1 % <span class="s2">16</span> == <span class="s2">0</span>) <span class="s5">// only receive on channel 1</span>
{
<<< <span class="s4">"r "</span>, inmsg.data1 / <span class="s2">16</span>, inmsg.data1 % <span class="s2">16</span>, inmsg.data2, inmsg.data3>>>;
<span class="s1">if</span>( inmsg.data1 / <span class="s2">16</span> == <span class="s2">9</span>)
{ 
mt.NoteOn(inmsg.data2, inmsg.data3);
}
<span class="s1">if</span>( inmsg.data1 / <span class="s2">16</span> == <span class="s2">8</span>)
{
mt.NoteOff(inmsg.data2, inmsg.data3);
}
<span class="s1">if</span>( inmsg.data1 / <span class="s2">16</span> == <span class="s2">12</span>)
{
//prog change apply to channels 1-16
<span class="s5">//works!</span>
inmsg.data1 - (inmsg.data1 % <span class="s2">16</span>) => <span class="s1">int</span> base;
<span class="s1">for</span>(<span class="s2">0</span>=><span class="s1">int</span> i; i<<span class="s2">15</span>; i++)
{
base + chans[i] => outmsg.data1;
inmsg.data2 => outmsg.data2;
i++;
<span class="s1">if</span>( i == <span class="s2">15</span>) 
{ 
<span class="s2">0</span> => outmsg.data3;
mouse.send(outmsg);
<span class="s1">break</span>; 
}
base + chans[i] => outmsg.data3;
mouse.send(outmsg);
inmsg.data2 => outmsg.data1;
i++;
<span class="s1">if</span>( i == <span class="s2">15</span>)
{
<span class="s2">0</span> => outmsg.data2 => outmsg.data3;
mouse.send(outmsg);
<span class="s1">break</span>;
}
base + chans[i] => outmsg.data2;
inmsg.data2 => outmsg.data3;
mouse.send(outmsg);
}
}
<span class="s1">if</span>( inmsg.data1 / <span class="s2">16</span> == <span class="s2">11</span>)
{
//apply any controller data to channels 1-16
inmsg.data1 - (inmsg.data1 % <span class="s2">16</span>) => <span class="s1">int</span> base;
inmsg.data2 => outmsg.data2;
inmsg.data3 => outmsg.data3;
<span class="s1">for</span>(<span class="s2">0</span>=><span class="s1">int</span> i; i<<span class="s2">16</span>; i++)
{
base + i => outmsg.data1;
mouse.send(outmsg);
}
}
}
}
}
}
// NoteOn
// input: pitch in midi note-number extended, velocity
// action: sends a MIDI pitchbend + note-on message to mouse on the current channel
// keeping track of holds
<span class="s1">fun void</span> NoteOn(<span class="s1">float</span> nn, <span class="s1">int</span> velocity)
{
IncrementCtr();
nn => holds[chans[ctr%<span class="s2">14</span>]];
PitchBend(nn, velocity) => outmsg.data2;
// note on, right channel
<span class="s2">144</span> + chans[ctr%<span class="s2">14</span>] => outmsg.data1; 
velocity => outmsg.data3;
mouse.send(outmsg);
//<<< "s ", outmsg.data1 / 16, outmsg.data1 % 16, outmsg.data2, outmsg.data3>>>;
}
// increments mod-14 counter, skipping over channels with
// notes already on them, if possible.
<span class="s1">fun void</span> IncrementCtr()
{
ctr;
<span class="s2">0</span> => <span class="s1">int</span> i;
<span class="s1">for</span>( i; i<<span class="s2">14</span>; i++)
{
<span class="s1">if</span> ( holds[chans[(ctr+i) % <span class="s2">14</span>]] == <span class="s2">0</span>.<span class="s2">0</span>)
{ (ctr + i) % <span class="s2">14</span> => ctr; <span class="s1">return</span>; }
}
(ctr + <span class="s2">1</span>) % <span class="s2">14</span> => ctr;
}
// NoteOff
// input: pitch & note-off velocity
// action: finds the pitch & offs it.
<span class="s1">fun void</span> NoteOff(<span class="s1">float</span> nn, <span class="s1">int</span> velocity)
{
<span class="s2">0</span> => <span class="s1">int</span> c;
<span class="s1">for</span>(c; c<<span class="s2">16</span>; c++)
{
<span class="s1">if</span>(holds[c] == nn) <span class="s5">// we found the pitch!</span>
{
<span class="s2">128</span> + c => outmsg.data1;
Math.floor(nn) $ <span class="s1">int</span> => outmsg.data2;
velocity => outmsg.data3;
mouse.send(outmsg);
//<<< "s ", outmsg.data1 / 16, outmsg.data1 % 16, outmsg.data2, outmsg.data3>>>;
<span class="s2">0</span>.<span class="s2">0</span> => holds[c];
<span class="s1">return</span>;
}
}
<<<<span class="s4">"MISS"</span>, nn>>>;
// we couldn't find the pitch!
// don't do anything. 
}
<span class="s1">fun void</span> ControlChange(<span class="s1">int</span> channel, <span class="s1">int</span> prognum, <span class="s1">int</span> val)
{
<span class="s2">128</span> + channel => outmsg.data1;
prognum => outmsg.data2;
val => outmsg.data3;
}
}

<span class="s1">class</span> MidiTransform
{
// superclass for MIDI transformers to be used by MicroRobinMidiIO
MicroRobinMidiIO myIO;
<span class="s1">fun void</span> LinkToIO(MicroRobinMidiIO io)
{
io @=> myIO;
}
<span class="s1">fun void</span> NoteOn( <span class="s1">int</span> nn, <span class="s1">int</span> vel)
{
<span class="s1">return</span>;
}
<span class="s1">fun void</span> NoteOff( <span class="s1">int</span> nn, <span class="s1">int</span> vel)
{
<span class="s1">return</span>;
}
}

<span class="s1">class</span> SuperparticularSamchillian <span class="s1">extends</span> MidiTransform
{
<span class="s2">57</span>. => <span class="s1">float</span> resentFreq;
<span class="s2">57</span>. => <span class="s1">float</span> prevFreq; 
<span class="s2">62</span> => <span class="s1">int</span> keyboardCenterNN;
<span class="s1">float</span> prevFreqsByKey[<span class="s2">128</span>];
//set pans funky
//for(0=>int f; f<16; f++)
<span class="s5">//{</span>
// myIO.ControlChange(f, 9, f*8);
<span class="s5">//}</span>
<span class="s1">fun void</span> NoteOn( <span class="s1">int</span> nn, <span class="s1">int</span> vel)
{
<span class="s1">if</span>(nn == keyboardCenterNN)
{
myIO.NoteOn( Std.ftom(prevFreq), vel);
}
<span class="s1">else</span>
{
<span class="s1">if</span>(nn < keyboardCenterNN)
{
// superparticular!
<span class="s2">1</span>. + <span class="s2">1</span>./(keyboardCenterNN - nn) /=> prevFreq;
myIO.NoteOn( Std.ftom(prevFreq), vel);
}
<span class="s1">else</span>
{ 
<span class="s1">if</span>(nn > keyboardCenterNN)
{
<span class="s2">1</span>. + <span class="s2">1</span>./(nn - keyboardCenterNN) *=> prevFreq;
myIO.NoteOn( Std.ftom(prevFreq), vel);
}
}
}
Std.ftom(prevFreq) => prevFreqsByKey[nn];
}
<span class="s1">fun void</span> NoteOff( <span class="s1">int</span> nn, <span class="s1">int</span> vel)
{
myIO.NoteOff( prevFreqsByKey[nn], vel);
}
}

MicroRobinMidiIO mrmio;
SuperparticularSamchillian easy;
easy.LinkToIO(mrmio);
<span class="s1">spork</span> ~ mrmio.StartRelay( <span class="s2">1</span>, easy);

<span class="s2">1</span><span class="s3">::</span>second<span class="s3"> => </span>now<span class="s3">;</span>

KBHit kb; 

while<span class="s3">(</span>true<span class="s3">)</span>
{
kb => <span class="s1">now</span>;
<span class="s1">while</span>( kb.more() )
{
kb.getchar() => <span class="s1">int</span> c;
<<< <span class="s4">"ascii:"</span>, c>>>;
easy.NoteOn(c, <span class="s2">88</span>);
}
}

Original HTML content:

<html><head><title>superparticular samchillian</title></head><body><span class="s1"><em> ChucK code for Superparticular Samchillian</span><br />
<span class="s1"></em> Samchillian idea by Leon Gruenbaum</span><br />
<span class="s1"><em> superparticular-ratio implementation by Jacob Barton</span><br />
<br />
</em> paste these into a new document in miniAudicle, or save text as a .ck to run in command-line<br />
<br />
<span class="s1"><em> change these to match your input/output device</span><br />
<span class="s1">0 =&gt; int inDeviceNum;</span><br />
<span class="s1">1 =&gt; int outDeviceNum;</span><br />
<br />
<span class="s1">class</span> MicroRobinMidiIO<br />
{<br />
MidiIn min;<br />
MidiOut mouse;<br />
MidiMsg inmsg, outmsg;<br />
<span class="s2">0</span> =&gt; <span class="s1">int</span> ctr;<br />
</em>int rr[128][3]; don't think we need this now.<br />
<em> index = note number?<br />
</em> column 0 = channel sent to<br />
<em> column 1 = note number sent<br />
<span class="s1">int</span><span class="s3"> chans[</span><span class="s2">14</span><span class="s3">]; </span></em> list of channels used<br />
<span class="s1">float</span><span class="s3"> holds[</span><span class="s2">16</span><span class="s3">]; </span><em> pitches of on notes, zero if off.<br />
<span class="s3"> [</span><span class="s2">0</span><span class="s3">,</span><span class="s2">1</span><span class="s3">,</span><span class="s2">2</span><span class="s3">,</span><span class="s2">3</span><span class="s3">,</span><span class="s2">4</span><span class="s3">,</span><span class="s2">5</span><span class="s3">,</span><span class="s2">6</span><span class="s3">,</span><span class="s2">7</span><span class="s3">,</span><span class="s2">8</span><span class="s3">,</span><span class="s2">10</span><span class="s3">,</span><span class="s2">11</span><span class="s3">,</span><span class="s2">12</span><span class="s3">,</span><span class="s2">13</span><span class="s3">,</span><span class="s2">14</span><span class="s3">] @=&gt; chans; </span></em>exclude channel 10 (drums) &amp; 16 (send channel)<br />
<em>microtuning stuff<br />
</em> PitchBend<br />
<em> input: pitch (midi note number float) &amp; velocity of desired note<br />
</em> action: sends appropriate pitchbend message<br />
<em> (assuming pitchbend range = +/- 2 semitones)<br />
</em> output: note number required for correct frequency to be realized<br />
<em> sends pitchbend, assuming +/- wholestep pitchbend range<br />
</em> returns note number required for correct frequency<br />
<span class="s1">fun int</span> PitchBend(<span class="s1">float</span> pitch, <span class="s1">int</span> velocity)<br />
{<br />
<em>send pitchbend<br />
<span class="s2">224</span> + chans[ctr] =&gt; outmsg.data1;<br />
<span class="s2">0</span> =&gt; outmsg.data2;<br />
Math.round((pitch % <span class="s2">1</span>.<span class="s2">0</span>) * <span class="s2">32</span>.<span class="s2">0</span> + <span class="s2">64</span>.<span class="s2">0</span>) $ <span class="s1">int</span> =&gt; outmsg.data3;<br />
mouse.send(outmsg);<br />
<span class="s1">return</span> Math.floor(pitch) $ <span class="s1">int</span>;<br />
}<br />
</em> StartRelay<br />
<em> input: number of MIDI device, MidiTransform to be used<br />
</em> creates a loop ~ should be sporked<br />
<span class="s1">fun void</span> StartRelay(<span class="s1">int</span> deviceNum, MidiTransform mt)<br />
{<br />
<span class="s1">if</span>( !min.open(<span class="s2">inDeviceNum</span>)) <span class="s1">me</span>.exit();<br />
<span class="s1">if</span>( !mouse.open(outDeviceNum)) <span class="s1">me</span>.exit();<br />
<em> print out device that was opened<br />
&lt;&lt;&lt; min.num(), <span class="s4">&quot; -&gt; &quot;</span>, min.name() &gt;&gt;&gt;;<br />
&lt;&lt;&lt; mouse.num(), <span class="s4">&quot; -&gt; &quot;</span>, mouse.name() &gt;&gt;&gt;;<br />
<span class="s1">while</span> ( <span class="s1">true</span>)<br />
{<br />
min =&gt; <span class="s1">now</span>;<br />
<span class="s1">while</span>( min.recv(inmsg))<br />
{ <br />
<span class="s1">if</span>( inmsg.data1 % <span class="s2">16</span> == <span class="s2">0</span>) <span class="s5"></em> only receive on channel 1</span><br />
{<br />
&lt;&lt;&lt; <span class="s4">&quot;r &quot;</span>, inmsg.data1 / <span class="s2">16</span>, inmsg.data1 % <span class="s2">16</span>, inmsg.data2, inmsg.data3&gt;&gt;&gt;;<br />
<span class="s1">if</span>( inmsg.data1 / <span class="s2">16</span> == <span class="s2">9</span>)<br />
{ <br />
mt.NoteOn(inmsg.data2, inmsg.data3);<br />
}<br />
<span class="s1">if</span>( inmsg.data1 / <span class="s2">16</span> == <span class="s2">8</span>)<br />
{<br />
mt.NoteOff(inmsg.data2, inmsg.data3);<br />
}<br />
<span class="s1">if</span>( inmsg.data1 / <span class="s2">16</span> == <span class="s2">12</span>)<br />
{<br />
<em>prog change apply to channels 1-16<br />
<span class="s5"></em>works!</span><br />
inmsg.data1 - (inmsg.data1 % <span class="s2">16</span>) =&gt; <span class="s1">int</span> base;<br />
<span class="s1">for</span>(<span class="s2">0</span>=&gt;<span class="s1">int</span> i; i&lt;<span class="s2">15</span>; i++)<br />
{<br />
base + chans[i] =&gt; outmsg.data1;<br />
inmsg.data2 =&gt; outmsg.data2;<br />
i++;<br />
<span class="s1">if</span>( i == <span class="s2">15</span>) <br />
{ <br />
<span class="s2">0</span> =&gt; outmsg.data3;<br />
mouse.send(outmsg);<br />
<span class="s1">break</span>; <br />
}<br />
base + chans[i] =&gt; outmsg.data3;<br />
mouse.send(outmsg);<br />
inmsg.data2 =&gt; outmsg.data1;<br />
i++;<br />
<span class="s1">if</span>( i == <span class="s2">15</span>)<br />
{<br />
<span class="s2">0</span> =&gt; outmsg.data2 =&gt; outmsg.data3;<br />
mouse.send(outmsg);<br />
<span class="s1">break</span>;<br />
}<br />
base + chans[i] =&gt; outmsg.data2;<br />
inmsg.data2 =&gt; outmsg.data3;<br />
mouse.send(outmsg);<br />
}<br />
}<br />
<span class="s1">if</span>( inmsg.data1 / <span class="s2">16</span> == <span class="s2">11</span>)<br />
{<br />
<em>apply any controller data to channels 1-16<br />
inmsg.data1 - (inmsg.data1 % <span class="s2">16</span>) =&gt; <span class="s1">int</span> base;<br />
inmsg.data2 =&gt; outmsg.data2;<br />
inmsg.data3 =&gt; outmsg.data3;<br />
<span class="s1">for</span>(<span class="s2">0</span>=&gt;<span class="s1">int</span> i; i&lt;<span class="s2">16</span>; i++)<br />
{<br />
base + i =&gt; outmsg.data1;<br />
mouse.send(outmsg);<br />
}<br />
}<br />
}<br />
}<br />
}<br />
}<br />
</em> NoteOn<br />
<em> input: pitch in midi note-number extended, velocity<br />
</em> action: sends a MIDI pitchbend + note-on message to mouse on the current channel<br />
<em> keeping track of holds<br />
<span class="s1">fun void</span> NoteOn(<span class="s1">float</span> nn, <span class="s1">int</span> velocity)<br />
{<br />
IncrementCtr();<br />
nn =&gt; holds[chans[ctr%<span class="s2">14</span>]];<br />
PitchBend(nn, velocity) =&gt; outmsg.data2;<br />
</em> note on, right channel<br />
<span class="s2">144</span> + chans[ctr%<span class="s2">14</span>] =&gt; outmsg.data1; <br />
velocity =&gt; outmsg.data3;<br />
mouse.send(outmsg);<br />
<em>&lt;&lt;&lt; &quot;s &quot;, outmsg.data1 / 16, outmsg.data1 % 16, outmsg.data2, outmsg.data3&gt;&gt;&gt;;<br />
}<br />
</em> increments mod-14 counter, skipping over channels with<br />
<em> notes already on them, if possible.<br />
<span class="s1">fun void</span> IncrementCtr()<br />
{<br />
ctr;<br />
<span class="s2">0</span> =&gt; <span class="s1">int</span> i;<br />
<span class="s1">for</span>( i; i&lt;<span class="s2">14</span>; i++)<br />
{<br />
<span class="s1">if</span> ( holds[chans[(ctr+i) % <span class="s2">14</span>]] == <span class="s2">0</span>.<span class="s2">0</span>)<br />
{ (ctr + i) % <span class="s2">14</span> =&gt; ctr; <span class="s1">return</span>; }<br />
}<br />
(ctr + <span class="s2">1</span>) % <span class="s2">14</span> =&gt; ctr;<br />
}<br />
</em> NoteOff<br />
<em> input: pitch &amp; note-off velocity<br />
</em> action: finds the pitch &amp; offs it.<br />
<span class="s1">fun void</span> NoteOff(<span class="s1">float</span> nn, <span class="s1">int</span> velocity)<br />
{<br />
<span class="s2">0</span> =&gt; <span class="s1">int</span> c;<br />
<span class="s1">for</span>(c; c&lt;<span class="s2">16</span>; c++)<br />
{<br />
<span class="s1">if</span>(holds[c] == nn) <span class="s5"><em> we found the pitch!</span><br />
{<br />
<span class="s2">128</span> + c =&gt; outmsg.data1;<br />
Math.floor(nn) $ <span class="s1">int</span> =&gt; outmsg.data2;<br />
velocity =&gt; outmsg.data3;<br />
mouse.send(outmsg);<br />
</em>&lt;&lt;&lt; &quot;s &quot;, outmsg.data1 / 16, outmsg.data1 % 16, outmsg.data2, outmsg.data3&gt;&gt;&gt;;<br />
<span class="s2">0</span>.<span class="s2">0</span> =&gt; holds[c];<br />
<span class="s1">return</span>;<br />
}<br />
}<br />
&lt;&lt;&lt;<span class="s4">&quot;MISS&quot;</span>, nn&gt;&gt;&gt;;<br />
<em> we couldn't find the pitch!<br />
</em> don't do anything. <br />
}<br />
<span class="s1">fun void</span> ControlChange(<span class="s1">int</span> channel, <span class="s1">int</span> prognum, <span class="s1">int</span> val)<br />
{<br />
<span class="s2">128</span> + channel =&gt; outmsg.data1;<br />
prognum =&gt; outmsg.data2;<br />
val =&gt; outmsg.data3;<br />
}<br />
}<br />
<br />
<span class="s1">class</span> MidiTransform<br />
{<br />
<em> superclass for MIDI transformers to be used by MicroRobinMidiIO<br />
MicroRobinMidiIO myIO;<br />
<span class="s1">fun void</span> LinkToIO(MicroRobinMidiIO io)<br />
{<br />
io @=&gt; myIO;<br />
}<br />
<span class="s1">fun void</span> NoteOn( <span class="s1">int</span> nn, <span class="s1">int</span> vel)<br />
{<br />
<span class="s1">return</span>;<br />
}<br />
<span class="s1">fun void</span> NoteOff( <span class="s1">int</span> nn, <span class="s1">int</span> vel)<br />
{<br />
<span class="s1">return</span>;<br />
}<br />
}<br />
<br />
<span class="s1">class</span> SuperparticularSamchillian <span class="s1">extends</span> MidiTransform<br />
{<br />
<span class="s2">57</span>. =&gt; <span class="s1">float</span> resentFreq;<br />
<span class="s2">57</span>. =&gt; <span class="s1">float</span> prevFreq; <br />
<span class="s2">62</span> =&gt; <span class="s1">int</span> keyboardCenterNN;<br />
<span class="s1">float</span> prevFreqsByKey[<span class="s2">128</span>];<br />
</em>set pans funky<br />
<em>for(0=&gt;int f; f&lt;16; f++)<br />
<span class="s5"></em>{</span><br />
<em> myIO.ControlChange(f, 9, f*8);<br />
<span class="s5"></em>}</span><br />
<span class="s1">fun void</span> NoteOn( <span class="s1">int</span> nn, <span class="s1">int</span> vel)<br />
{<br />
<span class="s1">if</span>(nn == keyboardCenterNN)<br />
{<br />
myIO.NoteOn( Std.ftom(prevFreq), vel);<br />
}<br />
<span class="s1">else</span><br />
{<br />
<span class="s1">if</span>(nn &lt; keyboardCenterNN)<br />
{<br />
// superparticular!<br />
<span class="s2">1</span>. + <span class="s2">1</span>./(keyboardCenterNN - nn) /=&gt; prevFreq;<br />
myIO.NoteOn( Std.ftom(prevFreq), vel);<br />
}<br />
<span class="s1">else</span><br />
{ <br />
<span class="s1">if</span>(nn &gt; keyboardCenterNN)<br />
{<br />
<span class="s2">1</span>. + <span class="s2">1</span>./(nn - keyboardCenterNN) *=&gt; prevFreq;<br />
myIO.NoteOn( Std.ftom(prevFreq), vel);<br />
}<br />
}<br />
}<br />
Std.ftom(prevFreq) =&gt; prevFreqsByKey[nn];<br />
}<br />
<span class="s1">fun void</span> NoteOff( <span class="s1">int</span> nn, <span class="s1">int</span> vel)<br />
{<br />
myIO.NoteOff( prevFreqsByKey[nn], vel);<br />
}<br />
}<br />
<br />
MicroRobinMidiIO mrmio;<br />
SuperparticularSamchillian easy;<br />
easy.LinkToIO(mrmio);<br />
<span class="s1">spork</span> ~ mrmio.StartRelay( <span class="s2">1</span>, easy);<br />
<br />
<span class="s2">1</span><span class="s3">::</span>second<span class="s3"> =&gt; </span>now<span class="s3">;</span><br />
<br />
KBHit kb; <br />
<br />
while<span class="s3">(</span>true<span class="s3">)</span><br />
{<br />
kb =&gt; <span class="s1">now</span>;<br />
<span class="s1">while</span>( kb.more() )<br />
{<br />
kb.getchar() =&gt; <span class="s1">int</span> c;<br />
&lt;&lt;&lt; <span class="s4">&quot;ascii:&quot;</span>, c&gt;&gt;&gt;;<br />
easy.NoteOn(c, <span class="s2">88</span>);<br />
}<br />
}</body></html>