Release 4.4.0 tarball

This commit is contained in:
Gary Scavone
2013-09-29 23:44:33 +02:00
committed by Stephen Sinclair
parent 3706458166
commit d2ed001eb5
1427 changed files with 44061 additions and 39976 deletions

View File

@@ -8,8 +8,9 @@
<img src="princeton.gif"> &nbsp; <img src="ccrma.gif"> &nbsp; <img src="mcgill.gif"><P>
<a class="qindex" href="index.html">Home</a> &nbsp; <a class="qindex" href="information.html">Information</a> &nbsp; <a class="qindex" href="classes.html">Classes</a> &nbsp; <a class="qindex" href="download.html">Download</a> &nbsp; <a class="qindex" href="usage.html">Usage</a> &nbsp; <a class="qindex" href="maillist.html">Mail List</a> &nbsp; <a class="qindex" href="system.html">Requirements</a> &nbsp; <a class="qindex" href="links.html">Links</a> &nbsp; <a class="qindex" href="faq.html">FAQ</a> &nbsp; <a class="qindex" href="tutorial.html">Tutorial</a></CENTER>
<HR>
<!-- Generated by Doxygen 1.4.4 -->
<h1><a class="anchor" name="skini">Synthesis toolKit Instrument Network Interface (SKINI)</a></h1>This describes the latest (version 1.1) implementation of SKINI for the Synthesis ToolKit in C++ (STK) by Perry R. Cook.<p>
<!-- Generated by Doxygen 1.5.8 -->
<div class="contents">
<h1><a class="anchor" name="skini">Synthesis toolKit Instrument Network Interface (SKINI) </a></h1>This describes the latest (version 1.1) implementation of SKINI for the Synthesis ToolKit in C++ (STK) by Perry R. Cook.<p>
<div class="fragment"><pre class="fragment"> Too good to be <span class="keyword">true</span>?
Have control and read it too?
A SKINI haiku.
@@ -34,9 +35,9 @@ Message types include standard MIDI types like NoteOn, NoteOff, ControlChange, e
All fields other than type, time, and channel are optional, and the types and useage of the additional fields is defined in the file <code>SKINI.tbl</code>.<p>
The other important file used by SKINI is <code>SKINI.msg</code>, which is a set of defines to make C code more readable, and to allow reasonably quick re-mapping of control numbers, etc.. All of these defined symbols are assigned integer values. For Java, the defines could be replaced by declaration and assignment statements, preserving the look and behavior of the rest of the code.<h2><a class="anchor" name="cfiles">
Files Used To Implement SKINI</a></h2>
<a class="el" href="classSkini.html">Skini</a> is a C++ class which can either open a SKINI file and successively read and parse lines of text as SKINI strings, or accept strings from another object and parse them. The latter functionality would be used by a socket, pipe, or other connection receiving SKINI messages a line at a time, usually in real time, but not restricted to real time.<p>
<code>SKINI.msg</code> should be included by anything wanting to use the <a class="el" href="classSkini.html">Skini</a> object. This is not mandatory, but use of the __SK_blah_ symbols which are defined in the .msg file will help to ensure clarity and consistency when messages are added and changed.<p>
<code>SKINI.tbl</code> is used only by the <a class="el" href="classSkini.html">Skini</a> parser object (Skini.cpp). In the file <code>SKINI.tbl</code>, an array of structures is declared and assigned values which instruct the parser as to what the message types are, and what the fields mean for those message types. This table is compiled and linked into applications using SKINI, but could be dynamically loaded and changed in a future version of SKINI.<h2><a class="anchor" name="parser">
Skini is a C++ class which can either open a SKINI file and successively read and parse lines of text as SKINI strings, or accept strings from another object and parse them. The latter functionality would be used by a socket, pipe, or other connection receiving SKINI messages a line at a time, usually in real time, but not restricted to real time.<p>
<code>SKINI.msg</code> should be included by anything wanting to use the Skini object. This is not mandatory, but use of the __SK_blah_ symbols which are defined in the .msg file will help to ensure clarity and consistency when messages are added and changed.<p>
<code>SKINI.tbl</code> is used only by the Skini parser object (Skini.cpp). In the file <code>SKINI.tbl</code>, an array of structures is declared and assigned values which instruct the parser as to what the message types are, and what the fields mean for those message types. This table is compiled and linked into applications using SKINI, but could be dynamically loaded and changed in a future version of SKINI.<h2><a class="anchor" name="parser">
SKINI Messages and the SKINI Parser:</a></h2>
The parser isn't all that smart, but neither am I. Here are the basic rules governing a valid SKINI message:<p>
<ul>
@@ -49,7 +50,7 @@ The parser isn't all that smart, but neither am I. Here are the basic rules gove
<li>The first field must be a SKINI message name (like NoteOn). These might become case-insensitive in future versions, so don't plan on exciting clever overloading of names (like noTeOn being different from NoTeON). There can be a number of leading spaces or tabs, but don't exceed 32 or so.</li></ul>
<p>
<ul>
<li>The second field must be a time specification in seconds. A time field can be either delta-time (most common and the only one supported in version 0.8), or absolute time. Absolute time messages have an '=' appended to the beginning of the floating point number with no space. So 0.10000 means delta time of 100 ms, while =0.10000 means absolute time of 100 ms. Absolute time messages make most sense in score files, but could also be used for (loose) synchronization in a real-time context. Real-time messages should be time-ordered AND time-correct. That is, if you've sent 100 total delta-time messages of 1.0 seconds, and then send an absolute time message of =90.0 seconds, or if you send two absolute time messages of =100.0 and =90.0 in that order, things will get really fouled up. The SKINI parser doesn't know about time, however. The <a class="el" href="classWvOut.html">WvOut</a> device is the master time keeper in the Synthesis Toolkit, so it should be queried to see if absolute time messages are making sense. There's an example of how to do that later in this document. Absolute times are returned by the parser as negative numbers (since negative deltaTimes are not allowed).</li></ul>
<li>The second field must be a time specification in seconds. A time field can be either delta-time (most common and the only one supported in version 0.8), or absolute time. Absolute time messages have an '=' appended to the beginning of the floating point number with no space. So 0.10000 means delta time of 100 ms, while =0.10000 means absolute time of 100 ms. Absolute time messages make most sense in score files, but could also be used for (loose) synchronization in a real-time context. Real-time messages should be time-ordered AND time-correct. That is, if you've sent 100 total delta-time messages of 1.0 seconds, and then send an absolute time message of =90.0 seconds, or if you send two absolute time messages of =100.0 and =90.0 in that order, things will get really fouled up. The SKINI parser doesn't know about time, however. The WvOut device is the master time keeper in the Synthesis Toolkit, so it should be queried to see if absolute time messages are making sense. There's an example of how to do that later in this document. Absolute times are returned by the parser as negative numbers (since negative deltaTimes are not allowed).</li></ul>
<p>
<ul>
<li>The third field must be an integer channel number. Don't go crazy and think that this is just MIDI channel 0-15 (which is supported). The channel number is scanned as a long int. Channels 0-15 are in general to be treated as MIDI channels. After that it's wide open. Channels could be socket numbers, machine IDs, serial numbers, or even unique tags for each event in a synthesis. A -1 channel can be used as don't care, omni, or other functions depending on your needs and taste.</li></ul>
@@ -58,37 +59,37 @@ The parser isn't all that smart, but neither am I. Here are the basic rules gove
<li>All remaining fields are specified in the <code>SKINI.tbl</code> file. In general, there are maximum two more fields, which are either SK_INT (long), SK_DBL (double float), or SK_STR (string). The latter is the mechanism by which more arguments can be specified on the line, but the object using SKINI must take that string apart (retrived by using getRemainderString()) and scan it. Any excess fields are stashed in remainderString.</li></ul>
<h2><a class="anchor" name="file">
A Short SKINI File:</a></h2>
<div class="fragment"><pre class="fragment"> Howdy!!! Welcome to SKINI, by P. Cook 1999
NoteOn 0.000082 2 55 82
NoteOff 1.000000 2 55 0
NoteOn 0.000082 2 69 82
StringDetune 0.100000 2 10
StringDetune 0.100000 2 30
StringDetune 0.100000 2 50
NoteOn 0.000000 2 69 82
StringDetune 0.100000 2 40
StringDetune 0.100000 2 22
StringDetune 0.100000 2 12
<span class="comment">//</span>
StringDamping 0.000100 2 0.0
NoteOn 0.000082 2 55 82
NoteOn 0.200000 2 62 82
NoteOn 0.100000 2 71 82
NoteOn 0.200000 2 79 82
NoteOff 1.000000 2 55 82
NoteOff 0.000000 2 62 82
NoteOff 0.000000 2 71 82
NoteOff 0.000000 2 79 82
StringDamping =4.000000 2 0.0
NoteOn 0.000082 2 55 82
NoteOn 0.200000 2 62 82
NoteOn 0.100000 2 71 82
NoteOn 0.200000 2 79 82
NoteOff 1.000000 2 55 82
NoteOff 0.000000 2 62 82
NoteOff 0.000000 2 71 82
NoteOff 0.000000 2 79 82
<div class="fragment"><pre class="fragment"> <span class="comment">/* Howdy!!! Welcome to SKINI, by P. Cook 1999</span>
<span class="comment"></span>
<span class="comment"> NoteOn 0.000082 2 55 82</span>
<span class="comment"> NoteOff 1.000000 2 55 0</span>
<span class="comment"> NoteOn 0.000082 2 69 82</span>
<span class="comment"> StringDetune 0.100000 2 10</span>
<span class="comment"> StringDetune 0.100000 2 30</span>
<span class="comment"> StringDetune 0.100000 2 50</span>
<span class="comment"> NoteOn 0.000000 2 69 82</span>
<span class="comment"> StringDetune 0.100000 2 40</span>
<span class="comment"> StringDetune 0.100000 2 22</span>
<span class="comment"> StringDetune 0.100000 2 12</span>
<span class="comment"> //</span>
<span class="comment"> StringDamping 0.000100 2 0.0</span>
<span class="comment"> NoteOn 0.000082 2 55 82</span>
<span class="comment"> NoteOn 0.200000 2 62 82</span>
<span class="comment"> NoteOn 0.100000 2 71 82</span>
<span class="comment"> NoteOn 0.200000 2 79 82</span>
<span class="comment"> NoteOff 1.000000 2 55 82</span>
<span class="comment"> NoteOff 0.000000 2 62 82</span>
<span class="comment"> NoteOff 0.000000 2 71 82</span>
<span class="comment"> NoteOff 0.000000 2 79 82</span>
<span class="comment"> StringDamping =4.000000 2 0.0</span>
<span class="comment"> NoteOn 0.000082 2 55 82</span>
<span class="comment"> NoteOn 0.200000 2 62 82</span>
<span class="comment"> NoteOn 0.100000 2 71 82</span>
<span class="comment"> NoteOn 0.200000 2 79 82</span>
<span class="comment"> NoteOff 1.000000 2 55 82</span>
<span class="comment"> NoteOff 0.000000 2 62 82</span>
<span class="comment"> NoteOff 0.000000 2 71 82</span>
<span class="comment"> NoteOff 0.000000 2 79 82</span>
</pre></div><h2><a class="anchor" name="table">
The SKINI.tbl File and Message Parsing:</a></h2>
The <code>SKINI.tbl</code> file contains an array of structures which are accessed by the parser object Skini.cpp. The struct is:<p>
@@ -114,15 +115,15 @@ so an assignment of one of these structs looks like:<p>
<li>SK_DBL : double precision floating point. SKINI uses these in the MIDI context for note numbers with micro tuning, velocities, controller values, etc.</li></ul>
<p>
<ul>
<li>SK_STR : only valid in final field. This allows (nearly) arbitrary message types to be supported by simply scanning the string to EOL (End Of Line) and then passing it to a more intelligent handler. For example, MIDI SYSEX (system exclusive) messages can be read as space-delimited integers into the SK_STR buffer. Longer bulk dumps, soundfiles, etc. should be handled as a new message type pointing to a FileName, <a class="el" href="classSocket.html">Socket</a>, or something else stored in the SK_STR field, or as a new type of multi-line message.</li></ul>
<li>SK_STR : only valid in final field. This allows (nearly) arbitrary message types to be supported by simply scanning the string to EOL (End Of Line) and then passing it to a more intelligent handler. For example, MIDI SYSEX (system exclusive) messages can be read as space-delimited integers into the SK_STR buffer. Longer bulk dumps, soundfiles, etc. should be handled as a new message type pointing to a FileName, Socket, or something else stored in the SK_STR field, or as a new type of multi-line message.</li></ul>
<p>
Each individual SKINI message is parsed and saved to a <a class="el" href="structSkini_1_1Message.html">Skini::Message</a> structure of the form: <div class="fragment"><pre class="fragment"> <span class="keyword">struct </span>Message {
<span class="keywordtype">long</span> type; !&lt; The message type, as defined in SKINI.msg.
<span class="keywordtype">long</span> channel; !&lt; The message channel (not limited to 16!).
StkFloat time; !&lt; The message time stamp in seconds (delta or absolute).
std::vector&lt;StkFloat&gt; floatValues; !&lt; The message values read as floats (values are type-specific).
std::vector&lt;long&gt; intValues; !&lt; The message values read as ints (number and values are type-specific).
std::string remainder; !&lt; Any remaining message data, read as ascii text.
Each individual SKINI message is parsed and saved to a Skini::Message structure of the form: <div class="fragment"><pre class="fragment"> <span class="keyword">struct </span>Message {
<span class="keywordtype">long</span> type;
<span class="keywordtype">long</span> channel;
StkFloat time;
std::vector&lt;StkFloat&gt; floatValues;
std::vector&lt;long&gt; intValues;
std::string remainder;
};
</pre></div><p>
Here's a couple of lines from the <code>SKINI.tbl</code> file<p>
@@ -135,7 +136,7 @@ Here's a couple of lines from the <code>SKINI.tbl</code> file<p>
{<span class="stringliteral">"StringDamping"</span> , __SK_ControlChange_, __SK_StringDamping_, SK_DBL},
{<span class="stringliteral">"StringDetune"</span> , __SK_ControlChange_, __SK_StringDetune_, SK_DBL},
</pre></div><p>
The first three are basic MIDI messages. The first two would cause the parser, after recognizing a match of the string "NoteOff" or "NoteOn", to set the message type to 128 or 144 (__SK_NoteOff_ and __SK_NoteOn_ are defined in the file <code>SKINI.msg</code> to be the MIDI byte value, without channel, of the actual MIDI messages for NoteOn and NoteOff). The parser would then set the time or delta time (this is always done and is therefore not described in the SKINI Message Struct). The next two fields would be scanned either as double-precision <code>floats</code> or as <code>long ints</code>, depending on the format specified in <code>SKINI.tbl</code>, and saved to the corresponding C++ vector variables in the <a class="el" href="structSkini_1_1Message.html">Skini::Message</a> structure (either <code>floatValues</code> or <code>intValues</code>). Floating-point values are also cast to <code>ints</code> (and vice-versa) and stored to their respective variables. For example, an expected integer value of 64 will also be saved as 64.0 in the corresponding <code>floatValues</code> variable of the <a class="el" href="structSkini_1_1Message.html">Skini::Message</a> structure. The remainder of the line is stashed in the remainderString variable.<p>
The first three are basic MIDI messages. The first two would cause the parser, after recognizing a match of the string "NoteOff" or "NoteOn", to set the message type to 128 or 144 (__SK_NoteOff_ and __SK_NoteOn_ are defined in the file <code>SKINI.msg</code> to be the MIDI byte value, without channel, of the actual MIDI messages for NoteOn and NoteOff). The parser would then set the time or delta time (this is always done and is therefore not described in the SKINI Message Struct). The next two fields would be scanned either as double-precision <code>floats</code> or as <code>long ints</code>, depending on the format specified in <code>SKINI.tbl</code>, and saved to the corresponding C++ vector variables in the Skini::Message structure (either <code>floatValues</code> or <code>intValues</code>). Floating-point values are also cast to <code>ints</code> (and vice-versa) and stored to their respective variables. For example, an expected integer value of 64 will also be saved as 64.0 in the corresponding <code>floatValues</code> variable of the Skini::Message structure. The remainder of the line is stashed in the remainderString variable.<p>
The ControlChange spec is basically the same as NoteOn and NoteOff, but the second data byte is set to an integer (for checking later as to what MIDI control is being changed).<p>
The Volume spec is a MIDI Extension message, which behaves like a ControlChange message with the controller number set explicitly to the value for MIDI Volume (7). Thus the following two lines would accomplish the same changing of MIDI volume on channel 2:<p>
<div class="fragment"><pre class="fragment"> ControlChange 0.000000 2 7 64.1
@@ -144,54 +145,55 @@ The Volume spec is a MIDI Extension message, which behaves like a ControlChange
I like the second line better, thus my motivation for SKINI in the first place.<p>
The StringDamping and StringDetune messages behave the same as the Volume message, but use Control Numbers which aren't specifically nailed-down in MIDI. Note that these Control Numbers are carried around as long ints, so we're not limited to 0-127. If, however, you want to use a MIDI controller to play an instrument, using controller numbers in the 0-127 range might make sense.<h2><a class="anchor" name="using">
Using SKINI:</a></h2>
Here's a simple example of code which uses the <a class="el" href="classSkini.html">Skini</a> object to read a SKINI file and control a single instrument.<p>
<div class="fragment"><pre class="fragment"> <a class="code" href="classSkini.html">Skini</a> score;
<a class="code" href="structSkini_1_1Message.html">Skini::Message</a> message;
instrument = <span class="keyword">new</span> <a class="code" href="classMandolin.html">Mandolin</a>(50.0);
score.<a class="code" href="classSkini.html#a2">setFile</a>( argv[1] );
<span class="keywordflow">while</span> ( score.<a class="code" href="classSkini.html#a3">nextMessage</a>( message ) != 0 ) {
tempDouble = message.<a class="code" href="structSkini_1_1Message.html#o2">time</a>;
Here's a simple example of code which uses the Skini object to read a SKINI file and control a single instrument.<p>
<div class="fragment"><pre class="fragment"> Skini score;
Skini::Message message;
instrument = <span class="keyword">new</span> Mandolin(50.0);
score.setFile( argv[1] );
<span class="keywordflow">while</span> ( score.nextMessage( message ) != 0 ) {
tempDouble = message.time;
<span class="keywordflow">if</span> (tempDouble &lt; 0) {
tempDouble = - tempDouble;
tempDouble = tempDouble - output.<a class="code" href="classWvOut.html#a3">getTime</a>();
tempDouble = tempDouble - output.getTime();
<span class="keywordflow">if</span> (tempDouble &lt; 0) {
printf(<span class="stringliteral">"Bad News Here!!! Backward Absolute Time Required.\n"</span>);
tempDouble = 0.0;
}
}
tempLong = (long) ( tempDouble * <a class="code" href="classStk.html#e0">Stk::sampleRate</a>() );
tempLong = (long) ( tempDouble * Stk::sampleRate() );
<span class="keywordflow">for</span> ( i=0; i&lt;tempLong; i++ ) {
output.<a class="code" href="classWvOut.html#a6">tick</a>( instrument-&gt;<a class="code" href="classInstrmnt.html#a8">tick</a>() );
output.tick( instrument-&gt;tick() );
}
tempDouble3 = message.<a class="code" href="structSkini_1_1Message.html#o3">floatValues</a>[1] * NORM_MIDI;
<span class="keywordflow">if</span> ( message.<a class="code" href="structSkini_1_1Message.html#o0">type</a> == __SK_NoteOn_ ) {
tempDouble3 = message.floatValues[1] * NORM_MIDI;
<span class="keywordflow">if</span> ( message.type == __SK_NoteOn_ ) {
<span class="keywordflow">if</span> ( tempDouble3 == 0.0 ) {
tempDouble3 = 0.5;
instrument-&gt;<a class="code" href="classInstrmnt.html#a3">noteOff</a>( tempDouble3 );
instrument-&gt;noteOff( tempDouble3 );
}
<span class="keywordflow">else</span> {
tempLong = message.<a class="code" href="structSkini_1_1Message.html#o4">intValues</a>[0];
tempLong = message.intValues[0];
tempDouble2 = Midi2Pitch[tempLong];
instrument-&gt;<a class="code" href="classInstrmnt.html#a2">noteOn</a>( tempDouble2, tempDouble3 );
instrument-&gt;noteOn( tempDouble2, tempDouble3 );
}
}
<span class="keywordflow">else</span> <span class="keywordflow">if</span> ( message.<a class="code" href="structSkini_1_1Message.html#o0">type</a> == __SK_NoteOff_ ) {
instrument-&gt;<a class="code" href="classInstrmnt.html#a3">noteOff</a>( tempDouble3 );
<span class="keywordflow">else</span> <span class="keywordflow">if</span> ( message.type == __SK_NoteOff_ ) {
instrument-&gt;noteOff( tempDouble3 );
}
<span class="keywordflow">else</span> <span class="keywordflow">if</span> ( message.<a class="code" href="structSkini_1_1Message.html#o0">type</a> == __SK_ControlChange_ ) {
tempLong = message.<a class="code" href="structSkini_1_1Message.html#o4">intValues</a>[0];
instrument-&gt;<a class="code" href="classInstrmnt.html#a10">controlChange</a>( tempLong, tempDouble3 );
<span class="keywordflow">else</span> <span class="keywordflow">if</span> ( message.type == __SK_ControlChange_ ) {
tempLong = message.intValues[0];
instrument-&gt;controlChange( tempLong, tempDouble3 );
}
}
</pre></div><p>
When a SKINI score is passed to a <a class="el" href="classSkini.html">Skini</a> object using the <a class="el" href="classSkini.html#a2">Skini::setFile()</a> function, valid messages are read from the file and returned using the <a class="el" href="classSkini.html#a3">Skini::nextMessage()</a> function.<p>
The "time" member of a <a class="el" href="structSkini_1_1Message.html">Skini::Message</a> is the deltaTime until the current message should occur. If this is greater than 0, synthesis occurs until the deltaTime has elapsed. If deltaTime is less than zero, the time is interpreted as absolute time and the output device is queried as to what time it is now. That is used to form a deltaTime, and if it's positive we synthesize. If it's negative, we print an error, pretend this never happened and we hang around hoping to eventually catch up.<p>
The rest of the code sorts out message types NoteOn, NoteOff (including NoteOn with velocity 0), and ControlChange. The code implicitly takes into account the integer type of the control number, but all other data is treated as double float. <HR>
When a SKINI score is passed to a Skini object using the Skini::setFile() function, valid messages are read from the file and returned using the Skini::nextMessage() function.<p>
The "time" member of a Skini::Message is the deltaTime until the current message should occur. If this is greater than 0, synthesis occurs until the deltaTime has elapsed. If deltaTime is less than zero, the time is interpreted as absolute time and the output device is queried as to what time it is now. That is used to form a deltaTime, and if it's positive we synthesize. If it's negative, we print an error, pretend this never happened and we hang around hoping to eventually catch up.<p>
The rest of the code sorts out message types NoteOn, NoteOff (including NoteOn with velocity 0), and ControlChange. The code implicitly takes into account the integer type of the control number, but all other data is treated as double float. </div>
<HR>
<table>
<tr><td><A HREF="http://ccrma.stanford.edu/software/stk/"><I>The Synthesis ToolKit in C++ (STK)</I></A></td></tr>
<tr><td>&copy;1995-2007 Perry R. Cook and Gary P. Scavone. All Rights Reserved.</td></tr>
<tr><td>&copy;1995-2009 Perry R. Cook and Gary P. Scavone. All Rights Reserved.</td></tr>
</table>
</BODY>